Есть ли способ навигации по JavaFX TableView, состоящему из нескольких столбцов, включая множество раскрывающихся списков? - PullRequest
0 голосов
/ 08 апреля 2019

У меня очень сложное табличное представление со столбцами, сделанными из разных cellFactories. Один набор столбцов может быть comboBox или TextField. Моя главная проблема заключается в том, что переход от одной ячейки к другой не работает. Переход от textField к textField работает, но как только я нажимаю comboBox, блок получает фокус, но как только элемент выбран, блок закрывается, и навигация по ячейке никуда не ведет.

Я пробовал несколько вещей, проблема действительно обнаружилась, пытаясь заставить comboBox реагировать на события keyPress. В tableView вам все еще нужно щелкнуть мышью, чтобы открыть ComboBox и сделать выбор.

открытый класс CustomFieldTableCell расширяет TableCell {

private final TextField textField = new TextField();
private final ComboBox<String> comboBox = new ComboBox<>();
private boolean isPredefined = false;
private boolean isCustomReqField = false; //else it's a custom result field

private final StringConverter<T> converter ;
private TableView<S> tableView = null;

public CustomFieldTableCell(StringConverter<T> converter) {
    this.converter = converter ;

    itemProperty().addListener((obx, oldItem, newItem) -> {
        if (newItem == null) {
            setText(null);
            setGraphic(null);
        } else {
            List<String> predefinedValues = new ArrayList<>();
            if (isCustomReqField) {
                RequirementField reqField = DiscusController.getInstance().getRequirementField(getTableColumn().getText());
                if (reqField != null) {
                    isPredefined = reqField.getFieldType() == RequirementField.FieldType.PREDEFINED;
                    predefinedValues = reqField.getPredefinedValues();
                }

            } else {
                ResultField resultField = DiscusController.getInstance().getResultsController().getResultField(getTableColumn().getText());
                if (resultField != null) {
                    isPredefined = resultField.getFieldType() == ResultField.FieldType.PREDEFINED;
                    predefinedValues = resultField.getPredefinedValues();
                }
            }
            if (isPredefined) {
                setGraphic(comboBox);
                comboBox.getItems().clear();
                comboBox.getItems().add(" ");
                comboBox.getItems().addAll(predefinedValues);
                comboBox.getSelectionModel().select(converter.toString(newItem));
            } else {
                textField.setText(converter.toString(newItem));
                setGraphic(textField);
            }
            setText(converter.toString(newItem));
        }
    });
    setContentDisplay(ContentDisplay.TEXT_ONLY);

    textField.setOnAction(evt -> {
        commitEdit(this.converter.fromString(textField.getText()));
    });
    textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
        if (! isNowFocused) {
            commitEdit(this.converter.fromString(textField.getText()));
        }
    });
    comboBox.setOnAction(evt -> {
        commitEdit(this.converter.fromString(comboBox.getValue()));
    });
    comboBox.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
        if (! isNowFocused) {
            commitEdit(this.converter.fromString(comboBox.getValue()));
        }
    });
    comboBox.setOnKeyPressed(event -> {
        String s = DropdownUtils.jumpToCombo(event.getText(), comboBox.getValue(), comboBox.getItems());
        if (s != null) {
            comboBox.setValue(s);
        }
        if (event.getCode() == KeyCode.ENTER) {
            if (isPredefined) {
                commitEdit(this.converter.fromString(comboBox.getValue()));
            } else {
                commitEdit(this.converter.fromString(textField.getText()));
            }
            int increment = event.isShiftDown() ? -1 : 1;
            int index = getTableRow().getIndex() + increment;
            getTableView().edit(index, getTableColumn());
            getTableView().scrollTo(index - 1);
        } else if (event.getCode() == KeyCode.ESCAPE) {
            cancelEdit();
        } else if (event.getCode() == KeyCode.TAB) {
            if (isPredefined) {
                commitEdit(this.converter.fromString(comboBox.getValue()));
            } else {
                commitEdit(this.converter.fromString(textField.getText()));
            }
            if (tableView != null) {
                TableColumn nextColumn = getNextColumn(!t.isShiftDown(), this.getTableColumn());
                if (nextColumn != null) {
                    getTableView().edit(getTableRow().getIndex(), nextColumn);
                }
            }
        }
    });

    textField.setOnKeyPressed(t -> {
        if (t.getCode() == KeyCode.ENTER) {
            if (isPredefined) {
                commitEdit(this.converter.fromString(comboBox.getValue()));
            } else {
                commitEdit(this.converter.fromString(textField.getText()));
            }
            int increment = t.isShiftDown() ? -1 : 1;
            int index = getTableRow().getIndex() + increment;
            getTableView().edit(index, getTableColumn());
            getTableView().scrollTo(index - 1);
        } else if (t.getCode() == KeyCode.ESCAPE) {
            cancelEdit();
        } else if (t.getCode() == KeyCode.TAB) {
            if (isPredefined) {
                commitEdit(this.converter.fromString(comboBox.getValue()));
            } else {
                commitEdit(this.converter.fromString(textField.getText()));
            }
            if (tableView != null) {
                TableColumn nextColumn = getNextColumn(!t.isShiftDown(), this.getTableColumn());
                if (nextColumn != null) {
                    getTableView().edit(getTableRow().getIndex(), nextColumn);
                }
            }
        }
    });
}

public CustomFieldTableCell(TableView tableView, boolean isCustomReqField) {
    this((StringConverter<T>) IDENTITY_CONVERTER);
    this.tableView = tableView;
    this.isCustomReqField = isCustomReqField;
}



public static <S> CustomFieldTableCell<S, String> createTextFieldComboCell(TableView<S> table, boolean isCustomReqField) {
    return new CustomFieldTableCell<>(table, isCustomReqField);
}

// set the text of the text field and display the graphic
@Override
public void startEdit() {
    super.startEdit();
    textField.setText(converter.toString(getItem()));
    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
    if (isPredefined) {
        comboBox.requestFocus();
    } else {
        textField.requestFocus();
    }
}

// revert to text display
@Override
public void cancelEdit() {
    super.cancelEdit();
    setContentDisplay(ContentDisplay.TEXT_ONLY);
}

// commits the edit. Update property if possible and revert to text display
@Override
public void commitEdit(T item) {

    // This block is necessary to support commit on losing focus, because the baked-in mechanism
    // sets our editing state to false before we can intercept the loss of focus.
    // The default commitEdit(...) method simply bails if we are not editing...
    if (! isEditing() && item != null && !item.equals(getItem())) {
        TableView<S> table = getTableView();
        if (table != null) {
            TableColumn<S, T> column = getTableColumn();
            CellEditEvent<S, T> event = new CellEditEvent<>(table,
                    new TablePosition<S,T>(table, getIndex(), column),
                    TableColumn.editCommitEvent(), item);
            Event.fireEvent(column, event);
        }
    }

    super.commitEdit(item);

    setContentDisplay(ContentDisplay.TEXT_ONLY);
}

private TableColumn<S, ?> getNextColumn(boolean forward, TableColumn currentCol) {
    List<TableColumn<S, ?>> columns = new ArrayList<>();
    for (TableColumn column : tableView.getColumns()) {
        columns.addAll(getLeaves(column));
    }
    //There is no other column that supports editing.
    if (columns.size() < 2) {
        return null;
    }
    int currentIndex = -1;
    for (int i = 0; i < columns.size(); i++) {
        if (columns.get(i) == currentCol) {
            currentIndex = i;
            break;
        }
    }

    int nextIndex = currentIndex;
    if (forward) {
        nextIndex++;
        if (nextIndex > columns.size() - 1) {
            nextIndex = 0;
        }
    } else {
        nextIndex--;
        if (nextIndex < 0) {
            nextIndex = columns.size() - 1;
        }
    }
    return columns.get(nextIndex);
}

. , .

}

Я ищу способ перехода от ячейки к ячейке независимо от того, является ли ячейка textField или ComboBox.

...