JavaFX自定义TableCell侦听

时间:2014-09-05 03:31:35

标签: java javafx textfield javafx-8 tablecell

例如,当您按下回车键时,TextFieldTableCell会响应并调用commitEdit()。

如果我使用自定义节点进行显示,那么我该如何监听确认编辑的方法?例如,我有一个扩展VBox的DateTimePicker。我无法将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);
    }

}

1 个答案:

答案 0 :(得分:1)

通常,可编辑单元格在处于非编辑模式时会显示默认文本,而在编辑模式下则会显示编辑控件(DateTimePicker)。您的自定义单元格实现需要处理它们之间的转换,以及确保在更新单元格项目时正确更新编辑控件的文本和值。

因此,如果处于编辑模式(updateItem(...)),则应覆盖DateTimePicker以更新isEditing()的值,如果不是,则覆盖文本。覆盖startEdit()切换为显示DateTimePicker而不是文字,并cancelEdit()切换回来。

您可能根本不需要覆盖commitEdit()。如果您的列绑定到某个属性,则默认的commitEdit()应该更新该属性(或者您可以在向该列注册的onEditCommit处理程序中执行此操作)。

tutorial有一个完全实现的可编辑表格单元格的示例:请参见底部附近的清单13.11。

但是,您需要在适当的时候调用commitEdit(...)。这样做的语义有点棘手:如果用户在DateTimePicker内的任何单个控件都有焦点时按下Enter键,并且焦点可能远离{{1}时,您可能想要提交编辑完全。

我建议您在DateTimePicker课程中创建onAction媒体资源。这很容易做到,您只需在属性更改时调用DateTimePicker。在Richard Bair's MoneyField中有一个很好的例子(该链接中有很多内容,只要看看他创建setEventHander(...)处理程序的位置)。然后,您可以(在onAction内部)检查各个控件上的操作事件(或者可能是Enter键按下),并在发生这种情况时调用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(); } 时提交编辑。您可能需要进行一些试验才能使其正常工作。