【问题标题】:Dynamically show a DatePicker动态显示 DatePicker
【发布时间】:2018-06-14 16:47:49
【问题描述】:

我正在编写一个显示StringPropertyObjectPropery<LocalDate> 值的表的JavaFX 应用程序。当我深入研究表格的工作方式时,似乎我不能使用DatePicker 作为单元格,所以我打算将日期显示为字符串,但是当用户尝试编辑该单元格时,我会捕获该事件并显示一个动态的DatePicker,它将接受一个新的日期值并更新单元格。

现在,我无法显示此动态 DatePicker

JavaFX:

    <TableView fx:id="tableView" editable="true" GridPane.columnIndex="0" GridPane.rowIndex="1">
        <columns>
         ...
        <TableColumn fx:id="recDate" onEditStart="#handleChangeDate" prefWidth="100.0" text="Received Date">
            <cellValueFactory>
                <PropertyValueFactory property="recDate" />
                <!-- <DatePicker fx:id="recDatePicker" /> -->
            </cellValueFactory>
        </TableColumn>
         ...

Java 8:

@FXML
private void handleChangeDate(CellEditEvent<MissionItem, LocalDate> e) {
    final DatePicker dp = new DatePicker(e.getOldValue());
    dp.setDisable(false);
    dp.setOnAction(event -> {
        LocalDate date = dp.getValue();
        System.out.println("Selected date: " + date);
    });
    Platform.runLater(dp::show);
    dp.show(); //redundant. Still doesn't work.
    System.out.println("fired event");
}

我可以看到fired event,但是DatePicker 永远不会出现。

我的目标是:

  • 将表格显示为一组字符串/LocalDates
  • 假设单元格本身不能是 DatePicker,这是一个很好的事件处理程序,当用户想要编辑日期单元格时,会显示动态 DatePicker,接受用户输入并更新值。
  • 确保这可以扩展到 1000 行。

【问题讨论】:

  • 你需要将DatePicker添加到场景中

标签: java swing javafx datepicker javafx-8


【解决方案1】:

要自定义列的单元格,您需要在此列的cellFactory 中创建适当的TableCells:

public class DatePickerTableCell<T> extends TableCell<T, LocalDate> {

    private final DatePicker datePicker;
    private boolean listening = true;

    // listener for changes in the datepicker
    private final ChangeListener<LocalDate> listener = (observable, oldValue, newValue) -> {
        if (listening) {
            listening = false;

            TableColumn<T, LocalDate> column = getTableColumn();
            EventHandler<TableColumn.CellEditEvent<T, LocalDate>> handler = column.getOnEditCommit();
            if (handler != null) {
                // use TableColumn.onEditCommit if there is a handler
                handler.handle(new TableColumn.CellEditEvent<>(
                        (TableView<T>) getTableView(),
                        new TablePosition<T, LocalDate>(getTableView(), getIndex(), column),
                        TableColumn.<T, LocalDate>editCommitEvent(),
                        newValue
                ));
            } else {
                // otherwise check if ObservableValue from cellValueFactory is
                // also writable and use in that case
                ObservableValue<LocalDate> observableValue = column.getCellObservableValue((T) getTableRow().getItem());
                if (observableValue instanceof WritableValue) {
                    ((WritableValue) observableValue).setValue(newValue);
                }
            }

            listening = true;
        }
    };

    public DatePickerTableCell() {
        this.datePicker = new DatePicker();
        this.datePicker.valueProperty().addListener(listener);
    }

    @Override
    protected void updateItem(LocalDate item, boolean empty) {
        super.updateItem(item, empty);

        if (empty) {
            listening = false;
            setGraphic(null);
        } else {
            listening = false;
            setGraphic(this.datePicker);
            this.datePicker.setValue(item);
            listening = true;
        }
    }

    public static <E> Callback<TableColumn<E, LocalDate>, TableCell<E, LocalDate>> forTableColumn() {
        return column -> new DatePickerTableCell<>();
    }

}

请注意,此类不会对“正常”编辑状态做出反应。它始终处于编辑状态。但是,它确实尝试调用 onEditCommit 处理程序来启用对不可观察属性的处理编辑。

工厂可以通过 fxml 添加使用

<TableColumn fx:id="recDate" prefWidth="100.0" text="Received Date">
    <cellValueFactory>
        <PropertyValueFactory property="recDate" />
    </cellValueFactory>
    <cellFactory>
         <DatePickerTableCell fx:factory="forTableColumn"/>
    </cellFactory>
</TableColumn>

(需要在 fxml 中包含适当的导入指令。)

【讨论】:

  • 这确实有效,但是我试图将原始源值填充到DatePicker 构造函数中,但是我发现原始值都是空的?
  • new DatePicker(this.getItem()); this.getItem() 总是返回 null 当它至少应该是进入单元格的原始值时......
  • 感谢编辑,它有效!我猜监听器应该默认设置为true。
  • 分配值应该在updateItem 方法中完成,因为最初所有单元格都是空的并且项目是null。但是,代码中有一个错误阻止了初始更新。对此感到抱歉。
猜你喜欢
  • 2013-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 1970-01-01
  • 2019-09-20
相关资源
最近更新 更多