首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >带有可修改的自定义TimePicker单元格的JAVAFX - Tableview关闭太快

带有可修改的自定义TimePicker单元格的JAVAFX - Tableview关闭太快
EN

Stack Overflow用户
提问于 2018-06-27 00:28:49
回答 1查看 324关注 0票数 0

我有一个带有可修改的自定义TimePicker单元格的表格视图。我写了一个函数来监听单元格中的变化,但是当我点击一个特定的小时时,时钟不会在第一次点击时保持打开和关闭状态,我必须再次点击来选择分钟作为示例。如何让时钟打开,并在时钟关闭时执行editCommitEvent()?

感谢您的帮助:)

这是我保管室的代码。PS:我使用jfoenix TimePicker

代码语言:javascript
复制
public class TimePickerTableCell<Patient> extends TableCell<Patient, LocalTime> {

    private JFXTimePicker timePicker;
    private boolean listening = true;

    // listener for changes in the timePicker
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private final ChangeListener<LocalTime> listener = (observable, oldValue, newValue) -> {
        if (listening) {
            listening = false;

            TableColumn<Patient, LocalTime> column = getTableColumn();
            EventHandler<TableColumn.CellEditEvent<Patient, LocalTime>> handler = column.getOnEditCommit();

            if (handler != null) {
                // use TableColumn.onEditCommit if there is a handler

                handler.handle(new TableColumn.CellEditEvent<>(
                        (TableView<Patient>) getTableView(),
                        new TablePosition<Patient, LocalTime>(getTableView(), getIndex(), column),
                        TableColumn.<Patient, LocalTime>editCommitEvent(),
                        newValue
                        ));             

            } else {
                // otherwise check if ObservableValue from cellValueFactory is
                // also writable and use in that case
                ObservableValue<LocalTime> observableValue = column.getCellObservableValue((Patient) getTableRow().getItem());
                if (observableValue instanceof WritableValue) {
                    ((WritableValue) observableValue).setValue(newValue);
                }
            }
            listening = true;
        }
    };

    public TimePickerTableCell () {
        this.timePicker = new JFXTimePicker();
        this.timePicker.valueProperty().addListener(listener);

        this.timePicker.setOnMouseEntered((event)->{timePicker.requestFocus();timePicker.show();System.err.println("OUVERTURE TIMEPICKER");});
        this.timePicker.setOnMouseExited((event)->{if(event.getY()<23)timePicker.hide();});
    }

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

        if (empty) {
            listening = false;
            setGraphic(null);
        } else {
            listening = false;
            setGraphic(this.timePicker);
            this.timePicker.setValue(item);
            this.timePicker.getStyleClass().add("time-picker");
            listening = true;
        }
    }

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

}
EN

回答 1

Stack Overflow用户

发布于 2018-06-27 04:22:01

首先,当您单击时钟时JFXTimePicker隐藏的原因(很可能)是因为您的onMouseExited处理程序。当你在弹出窗口上移动鼠标时,它会“退出”JFXTimePicker,从而隐藏时钟。

你也以错误的方式实现了一个可编辑的TableCell。您应该覆盖Cell类( TableCell继承自该类)的startEdit()cancelEdit()方法。您可以查看像TextFieldTableCell这样的类的源代码,了解它是如何完成的。我还用JFXTimePicker做了一个这样做的例子

代码语言:javascript
复制
import com.jfoenix.controls.JFXTimePicker;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.input.KeyCode;
import javafx.util.Callback;
import javafx.util.converter.LocalTimeStringConverter;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class TimePickerTableCell<S> extends TableCell<S, LocalTime> {

    // Static methods for creating TableColumn.cellFactory Callbacks

    public static <S> Callback<TableColumn<S, LocalTime>, TableCell<S, LocalTime>> forTableColumn() {
        return v -> new TimePickerTableCell<>();
    }

    public static <S> Callback<TableColumn<S, LocalTime>, TableCell<S, LocalTime>> forTableColumn(DateTimeFormatter formatter) {
        return v -> new TimePickerTableCell<>(formatter);
    }

    // Formatter property

    private final ObjectProperty<DateTimeFormatter> formatter = new SimpleObjectProperty<>(this, "formatter");
    public final void setFormatter(DateTimeFormatter formatter) { this.formatter.set(formatter); }
    public final DateTimeFormatter getFormatter() { return formatter.get(); }
    public final ObjectProperty<DateTimeFormatter> formatterProperty() { return formatter; }

    // JFXTimePicker field

    private JFXTimePicker timePicker;

    // Constructors

    public TimePickerTableCell() {
        this(DateTimeFormatter.ISO_LOCAL_TIME);
    }

    public TimePickerTableCell(DateTimeFormatter formatter) {
        getStyleClass().add("time-picker-table-cell");
        setFormatter(formatter);
    }

    // Display logic

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

        setGraphic(null);

        if (empty || item == null) {
            setText(null);
        } else {
            setText(formatItem(item));
        }
    }

    private String formatItem(LocalTime item) {
        if (item == null) {
            return null;
        }
        return getFormatter() == null ? item.toString() : getFormatter().format(item);
    }

    // Edit logic

    @Override
    public void startEdit() {
        if (!isEditable() ||
                !getTableColumn().isEditable() ||
                !getTableView().isEditable()) {
            return;
        }
        super.startEdit();
        if (isEditing()) {
            if (timePicker == null) {
                createTimePicker();
            }
            timePicker.setValue(getItem());
            setText(null);
            setGraphic(timePicker);

            // Wrapped this in a Platform#runLater call because otherwise
            // I couldn't get this to work properly. Despite this, there are
            // times where this still seems buggy.
            Platform.runLater(() -> {
                timePicker.requestFocus();
                timePicker.getEditor().selectAll();
            });
        }
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setText(formatItem(getItem()));
        setGraphic(null);
    }

    private void createTimePicker() {
        timePicker = new JFXTimePicker();

        timePicker.setConverter(new LocalTimeStringConverter(getFormatter(), null));
        formatter.addListener((observable, oldValue, newValue) ->
                timePicker.setConverter(new LocalTimeStringConverter(newValue, null)));

        timePicker.getEditor().setOnKeyReleased(event -> {
            if (event.getCode() == KeyCode.ENTER) {
                commitEdit(timePicker.getValue());
                event.consume();
            } else if (event.getCode() == KeyCode.ESCAPE) {
                cancelEdit();
                event.consume();
            }
        });

        timePicker.focusedProperty().addListener((observable, oldValue, newValue) -> {
            if (!newValue) {
                cancelEdit();
            }
        });

    }
}

在这里,如果ESCAPE键被释放,或者如果JFXTimePicker失去焦点,则取消编辑。似乎与时钟交互并不会导致JFXTimePicker失去焦点(至少在我尝试它的时候是这样)。

如果要提交编辑,则必须按ENTER键。即使时钟当前正在显示,这也是有效的(至少当我尝试它时是这样的)。

这不会在时钟关闭时自动提交编辑,但如果需要,您应该能够添加该行为。由于JFXTimePicker是从ComboBoxBase扩展而来的,因此它具有onHidingonHidden等属性。

注意:如果在手动输入时间后,您尝试提交,而DateTimeFormatter无法解析String,则它将恢复为旧值。除了值没有改变之外,没有任何错误的迹象。然而,这似乎是由JFXTimePicker__引起的行为。

您也不需要尝试自己处理值的提交。默认情况下,TableColumn已尝试在基础属性上设置新值。这是在TableView的Javadoc中提到的(在“编辑”标题下,emphasis mine):

当您调用Cell.commitEdit(Object)时,会向TableView激发一个事件,您可以通过TableColumn.setOnEditCommit(javafx.event.EventHandler)添加一个EventHandler来观察到这一点。类似地,您还可以观察编辑开始和编辑取消编辑事件。

默认情况下,TableColumn 编辑提交处理程序是非空的,它具有一个默认处理程序,该处理程序尝试覆盖当前正在编辑的行中的项的属性值。它能够做到这一点,因为Cell.commitEdit(Object)方法传入了新值,并通过触发的CellEditEvent将新值传递给编辑提交处理程序。只需调用TableColumn.CellEditEvent.getNewValue()来检索该值即可。

如果您最终在setOnEditCommit中使用自己的EventHandler,那么您需要自己实现该行为:

需要注意的是,如果您使用自己的EventHandler调用TableColumn.setOnEditCommit(javafx.event.EventHandler),那么您将删除默认的处理程序。除非您随后处理对属性(或相关数据源)的写回,否则不会发生任何事情。您可以使用TableColumnBase.addEventHandler(javafx.event.EventType, javafx.event.EventHandler)方法添加一个TableColumn.editCommitEvent() EventType,并将所需的EventHandler作为第二个参数,从而解决此问题。使用此方法,您不会替换默认实现,但在发生编辑提交时会通知您。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51047599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档