Во-первых, причина, по которой JFXTimePicker
скрывается при щелчке по часам, (скорее всего) связана с вашим обработчиком onMouseExited
. Когда вы наводите курсор мыши на всплывающее окно, оно «выходит» из JFXTimePicker
и таким образом скрывает часы.
Вы также реализуете редактируемый TableCell
неправильным способом. Вы должны переопределить методы startEdit()
и cancelEdit()
класса 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
уже пытается установить новое значение для базового свойства по умолчанию. Это упоминается в Javadoc TableView
(под заголовком «Редактирование», выделение шахта):
Когда вы звоните Cell.commitEdit(Object)
, событие отправляется на
TableView
, который вы можете наблюдать, добавив EventHandler
через
TableColumn.setOnEditCommit(javafx.event.EventHandler)
. Точно так же вы
также можно наблюдать события редактирования для начала редактирования и отмены редактирования.
По умолчанию обработчик коммита редактирования TableColumn
не нулевой, с
обработчик по умолчанию, который пытается перезаписать значение свойства для
элемент в редактируемой в данный момент строке . Это может сделать это как
Cell.commitEdit(Object)
метод передается в новом значении, и это
передается в обработчик фиксации редактирования через CellEditEvent
, то есть
уволена. Это просто вопрос вызова
TableColumn.CellEditEvent.getNewValue()
, чтобы получить это значение.
Если вы в конечном итоге используете свой EventHandler
в setOnEditCommit
, вам нужно реализовать это поведение самостоятельно:
Очень важно отметить, что если вы позвоните
TableColumn.setOnEditCommit(javafx.event.EventHandler)
со своим
EventHandler
, тогда вы удалите обработчик по умолчанию. Если не
Затем вы обрабатываете обратную запись в свойство (или соответствующие данные
источник), ничего не произойдет. Вы можете обойти это, используя
TableColumnBase.addEventHandler(javafx.event.EventType,
javafx.event.EventHandler)
способ добавить
TableColumn.editCommitEvent()
EventType
с желаемым EventHandler
как второй аргумент. Используя этот метод, вы не замените
реализация по умолчанию, но вы будете уведомлены, когда редактировать коммит
произошло.