2014-09-05 5 views
0

TextFieldTableCell, например, отвечает и вызывает commitEdit(), когда вы нажимаете клавишу ввода.JavaFX Custom TableCell Listening

Если я использую настраиваемый узел для отображения, то как я могу прослушать способы подтверждения редактирования? Например, у меня есть DateTimePicker, который расширяет VBox. Я не могу добавить KeyListener в VBox.

Что делать, чтобы следить за подтверждением внесенных изменений в таблицу? Вот что я пытался:

class TableCellDateTimePicker extends TableCell<CHILD, LocalDateTime> { 

    public TableCellDateTimePicker() { 
     super(); 
    } 



    @Override 
    public void startEdit() { 
     super.startEdit(); 
     DateTimePicker picker = new DateTimePicker(); 
     picker.getDatePickerField().setOnKeyPressed((KeyEvent event) -> { 
      System.out.println("PRESS"); 
      if (event.getCode() == KeyCode.ENTER) { 
       commitEdit(picker.getValue()); 
      } 
     }); 
     picker.setValue(getItem()); 
     setGraphic(picker); 
    } 



    @Override 
    public void commitEdit(LocalDateTime newValue) { 
     super.commitEdit(newValue); 
     setText(newValue.toString()); 
    } 



    @Override 
    public void cancelEdit() { 
     super.cancelEdit(); 
    } 

} 

DateTimePicker:

/** 
* A custom DateTimePicker that lets a user select a LocalDateTime. 
* 
* @author Toni-Tran 
*/ 
public class DateTimePicker extends VBox { 

    @FXML 
    private DatePicker datePicker; 
    @FXML 
    private Button showTimePickerBtn; 

    private NumberPicker hourField; 
    private NumberPicker minuteField; 

    private ObjectProperty<LocalDateTime> currentLocalDateTimeValue; 



    public DateTimePicker() { 
     FXMLLoader loader = new FXMLLoader(this.getClass().getResource(
       ScreenPaths.DATE_TIME_PICKER)); 
     loader.setController(this); 
     loader.setRoot(this); 
     try { 
      loader.load(); 
     } catch (IOException e) { 
     } 
    } 



    @FXML 
    private void initialize() { 
     showTimePickerBtn.setOnAction(event -> this.showTimePicker()); 

     hourField = new NumberPicker(); 
     hourField.setBounds(0, 23); 
     hourField.setWrapAround(true); 

     minuteField = new NumberPicker(); 
     minuteField.setBounds(0, 59); 
     minuteField.setWrapAround(true); 

     currentLocalDateTimeValue = new SimpleObjectProperty<>(); 

     datePicker.valueProperty().addListener((ObservableValue<? extends LocalDate> observable, 
       LocalDate oldValue, LocalDate newValue) -> { 
        LocalDateTime newLDT; 
        if (newValue != null) { 
         newLDT = LocalDateTime.of(newValue.getYear(), 
           newValue.getMonth(), newValue.getDayOfMonth(), 
           hourField.getValue(), minuteField.getValue()); 
         currentLocalDateTimeValue.set(newLDT); 
        } else { 
         currentLocalDateTimeValue.set(null); 
        } 
       }); 

     hourField.valueProperty().addListener((ObservableValue<? extends Number> observable, 
       Number oldValue, Number newValue) -> { 
        if (currentLocalDateTimeValue.getValue() != null) { 
         LocalDateTime newLDT = LocalDateTime.of(currentLocalDateTimeValue.getValue().getYear(), 
           currentLocalDateTimeValue.getValue().getMonth(), currentLocalDateTimeValue.getValue().getDayOfMonth(), 
           hourField.getValue(), minuteField.getValue()); 
         currentLocalDateTimeValue.set(newLDT); 
        } else { 
         currentLocalDateTimeValue.set(null); 
        } 
       }); 

     minuteField.valueProperty().addListener((ObservableValue<? extends Number> observable, 
       Number oldValue, Number newValue) -> { 
        if (currentLocalDateTimeValue.getValue() != null) { 
         LocalDateTime newLDT = LocalDateTime.of(currentLocalDateTimeValue.getValue().getYear(), 
           currentLocalDateTimeValue.getValue().getMonth(), currentLocalDateTimeValue.getValue().getDayOfMonth(), 
           hourField.getValue(), minuteField.getValue()); 
         currentLocalDateTimeValue.set(newLDT); 
        } else { 
         currentLocalDateTimeValue.set(null); 
        } 
       }); 
    } 



    /** 
    * Manually set a LocalDateTime value for this control. 
    * 
    * @param val The {@link LocalDateTime} value for this control. 
    */ 
    public void setValue(LocalDateTime val) { 
     if (val == null) { 
      return; 
     } 
     LocalDate day = LocalDate.of(val.getYear(), val.getMonthValue(), 
       val.getDayOfMonth()); 
     datePicker.setValue(day); 
     hourField.setValue(val.getHour()); 
     minuteField.setValue(val.getMinute()); 
    } 



    /** 
    * Returns the currently set LocalDateTime. 
    * 
    * @return the {@link LocalDateTime} value of this control. 
    */ 
    public LocalDateTime getValue() { 
     return currentLocalDateTimeValue.getValue(); 
    } 



    /** 
    * Returns the Observable property of the DateTimePicker's current 
    * LocalDateTime value. 
    * 
    * @return the Observable property of the DateTimePicker's current 
    * LocalDateTime value. 
    */ 
    public ObjectProperty<LocalDateTime> valueProperty() { 
     return currentLocalDateTimeValue; 
    } 



    /** 
    * This is triggered when the user wants to view the screen for setting a 
    * certain time for their LocalDateTime. 
    */ 
    public void showTimePicker() { 
     HBox topContainer = new HBox(); 
     topContainer.getChildren().addAll(hourField, new Label(":"), 
       minuteField); 
     topContainer.setSpacing(3); 
     DialogPopup.showNodeApplicationlModal(topContainer); 
    } 

} 
+0

Не успевайте проверить его, но делает 'picker.setOnAction (event -> commitEdit (picker.getValue()));' work? –

+0

У него нет возможности использовать setOnAction.Я также попытался использовать setOnMouseClicked. Он не реагирует на клики вообще. –

+0

Ой, подождите ... Что такое 'DateTimePicker'? Я неправильно читал 'DatePicker' –

ответ

1

Как правило, редактируется ячейка будет отображать текст по умолчанию, если не в режиме редактирования и управления редактирования (ваш DateTimePicker), когда в редактировании Режим. Ваша пользовательская реализация ячейки должна обрабатывать переход между ними, а также следить за тем, чтобы текст и значение для элемента управления редактирования были правильно обновлены, если элемент ячейки обновлен.

Поэтому вы должны переопределить updateItem(...), чтобы обновить значение DateTimePicker, если в режиме редактирования (isEditing()) или текст, если нет. Переопределите startEdit(), чтобы переключить, чтобы показать DateTimePicker вместо текста, и cancelEdit(), чтобы переключиться обратно.

Возможно, вам не потребуется переопределять commitEdit(). Если ваш столбец связан с свойством, по умолчанию commitEdit() должен обновить это свойство (или вы можете сделать это в обработчике onEditCommit, зарегистрированном в столбце).

В документе tutorial приведен пример полностью реализованной редактируемой ячейки таблицы: см. Список 13.11 у основания.

Однако вам необходимо будет вызвать commitEdit(...) в соответствующее время. Семантика этого немного сложна: вы, вероятно, захотите зафиксировать редактирование, если пользователь нажимает Enter, когда какой-либо из отдельных элементов управления внутри вашего DateTimePicker имеет фокус, и, возможно, когда фокус полностью удаляется от DateTimePicker.

Я бы порекомендовал творить onAction свою собственность в вашем классе DateTimePicker. Это довольно легко сделать, вам просто нужно позвонить setEventHander(...), когда свойство изменится. Хороший пример в Richard Bair's MoneyField (в этой ссылке есть много чего, просто посмотрите, где он создает обработчик onAction). Затем вы можете (внутренне до DateTimePicker) проверить события действий (или, возможно, ввести нажатия клавиш) на отдельных элементах управления и вызвать fireEvent(new ActionEvent(...)), когда это произойдет. Затем ваша реализация ячейки ячейки может зарегистрировать onAction с DateTimePicker и позвонить по номеру commitEdit(...).

Выполнение редактирования при потере фокуса не должно быть намного сложнее. Может выставить ReadOnlyBooleanProperty hasFocus() в DateTimePicker:

private final ReadOnlyBooleanWrapper hasFocus = new ReadOnlyBooleanWrapper(this, "hasFocus"); 
hasFocus.bind(
    hourField.focusedProperty() 
    .or(minuteField.focusedProperty()) 
    .or(datePicker.focusedProperty()) 
    .or(showTimePickerButton.focusedProperty())); 

// ... 
public ReadOnlyBooleanProperty hasFocusProperty() { 
    return hasFocus.getReadOnlyProperty(); 
} 

Тогда ваша реализация клетка может заметить, что имущество и совершать правку, если она меняется на false. Возможно, вам придется поэкспериментировать с этим немного, чтобы заставить его работать удовлетворительно.

+0

Отличные ресурсы. Я посмотрю на них. Однако последний вопрос: я перепробовал метод updateItem() следующим образом: 'protected void updateItem (элемент LocalDateTime, boolean empty) { if (item == null || empty) { setGraphic (null); } else { setGraphic (null); setText (item.toString()); } } ' , но всякий раз, когда я переставляю столбцы таблицы, я получаю добавленную дублируемую ячейку непосредственно под ней. Является ли мой метод неправильным, или это ошибка JavaFX? –

+0

Установите текст как нулевой, так и графический, когда ячейка пуста. –

+0

Это сделало трюк. Спасибо! –

Смежные вопросы