JAVAFX - Tableview с изменяемой ячейкой TimePicker закрывается слишком быстро - PullRequest
0 голосов
/ 26 июня 2018

У меня есть Tableview с изменяемой ячейкой TimePicker. Я написал функцию, которая прослушивает изменения в этой ячейке, но когда я нажимаю на определенный час, часы не остаются открытыми и закрываются при первом щелчке, и мне приходится нажимать снова, чтобы выбрать минуты для примера. Как я могу позволить часам открыться и сделать editCommitEvent (), когда часы закрываются?

Спасибо за вашу помощь:)

Вот код моей клетки. 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<>();
    }

}

1 Ответ

0 голосов
/ 26 июня 2018

Во-первых, причина, по которой 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 как второй аргумент. Используя этот метод, вы не замените реализация по умолчанию, но вы будете уведомлены, когда редактировать коммит произошло.

...