javafx - JAVAFX - 带有可修改自定义 TimePicker 单元格的 Tableview 关闭太快
问题描述
我有一个带有可修改自定义 TimePicker 单元格的 Tableview。我编写了一个函数来侦听该单元格中的更改,但是当我单击特定小时时,时钟不会在第一次单击时保持打开和关闭状态,我必须再次单击以选择分钟例如。我怎样才能让时钟打开并在时钟关闭时进行editCommitEvent()?
谢谢您的帮助 :)
这是我的 custum 单元的代码。PS:我使用 jfoenix TimePicker
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<>();
}
}
解决方案
首先,JFXTimePicker
当您单击时钟时隐藏的原因(很可能)是由于您的onMouseExited
处理程序。当您将鼠标移到弹出窗口上时,它会“退出”JFXTimePicker
并隐藏时钟。
您还TableCell
以错误的方式实现了可编辑。您应该覆盖类(继承自)的startEdit()
andcancelEdit()
方法。您可以查看类的源代码,例如它是如何完成的。我还制定了一个这样做的例子:Cell
TableCell
TextFieldTableCell
JFXTimePicker
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
它扩展具有诸如onHiding
和之类的属性onHidden
。
注意:如果在手动输入时间后,您尝试提交并且DateTimeFormatter
无法解析,String
它只会恢复为旧值。除了值没有改变之外,没有任何错误的迹象。然而,这似乎是由 引起的行为JFXTimePicker
。
您也不需要尝试自己处理提交价值。默认情况下,TableColumn
已经尝试在基础属性上设置新值。TableView
这在(在“编辑”标题下,强调我的)的Javadoc中提到:
当你调用
Cell.commitEdit(Object)
一个事件时,会触发一个事件 ,你可以通过添加一个viaTableView
来观察它。同样,您也可以观察编辑开始和编辑取消的编辑事件。EventHandler
TableColumn.setOnEditCommit(javafx.event.EventHandler)
默认情况下,
TableColumn
编辑提交处理程序是非空的,默认处理程序会尝试覆盖当前正在编辑的行中项目的属性值。当方法传入新值时,它能够做到这一点 ,并通过被触发Cell.commitEdit(Object)
的 传递给编辑提交处理程序。CellEditEvent
只需调用TableColumn.CellEditEvent.getNewValue()
即可检索此值。
如果您最终使用了自己的EventHandler
in,setOnEditCommit
那么您需要自己实现该行为:
请务必注意,如果您
TableColumn.setOnEditCommit(javafx.event.EventHandler)
使用自己的 调用EventHandler
,那么您将删除默认处理程序。除非您随后处理对属性(或相关数据源)的写回,否则不会发生任何事情。TableColumnBase.addEventHandler(javafx.event.EventType, javafx.event.EventHandler)
您可以通过使用该方法来 解决此问题, 以添加TableColumn.editCommitEvent()
EventType
您想要EventHandler
的作为第二个参数的 a。使用此方法,您不会替换默认实现,但会在发生编辑提交时通知您。
推荐阅读
- laravel - How I run laravel / vue web application with wamp?
- audio - 如何使用 Voxeet“静音”?
- c# - User.Identity.Name is null in my ASP.NET Core Web API
- python - Python SQL query has the wrong type
- php - Laravel 7 表单验证 json 对象
- java - 移除广告时调整布局大小
- node.js - 在 node.js 中过滤时间段
- python - Python:尝试使用 dict 创建 json 对象(TypeError:无法解压不可迭代的用户对象)
- python - 如何在一个 DetailView 中组合多个模型
- r - 如何在散点图中绘制决策边界,不会提示有关树可以具有的预测变量数量的以下错误?