Управление контекстным меню JavaFX, подключенным к TextField, с помощью клавиш со стрелками - PullRequest
1 голос
/ 09 марта 2019

Я пытаюсь создать стиль автозаполнения TextField , который использует ContextMenu для отображения подсказок под TextField.Мне бы хотелось, чтобы ContextMenu отображалось, когда пользователь нажимает клавишу «Вниз», когда фокус находится на TextField.Это мое текущее решение:

setOnKeyPressed(event -> {
        System.out.println("pressed " + event.getCode());
        switch (event.getCode()) {
            case DOWN:
                if(getText().length()>0) {
                    if (!suggestionMenu.isShowing()) {
                        suggestionMenu.show(AutoCompleteTextField.this, Side.BOTTOM, 0, 0);
                    }
                    suggestionMenu.getSkin().getNode().lookup(".menu-item").requestFocus();
                }
                break;
        }
    });

Источник: ContextMenu и программный выбор элемента

Использование этого кодастрелка вниз всегда «выделяет» (синего цвета) первый элемент в списке.Проблема в том, что иногда (для меня это кажется случайным), второе нажатие клавиши со стрелкой не даст никакого ответа в ContextMenu - первый элемент останется выбранным.После этого нажатия он всегда будет работать нормально.

Я бы также предпочел, чтобы нажатие вверх при выделении первого элемента скрывало бы ContextMenu, и это пробел не вызывал бы метод onAction MenuItem s, хотя я не совсем понимаю, как работает фокус / прослушивание события для этого меню.Кажется, что клавиатура имеет два фокуса одновременно - вверх / вниз, пробел и ввод в ContextMenu, а все остальное идет в TextField.

Редактировать: Вот полный пример.При отображении ContextMenu с помощью клавиши со стрелкой вниз иногда это вызывает проблемное поведение, в других случаях нет.

Main.java

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Main extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        BorderPane pane = new BorderPane();
        AutoCompleteTextField actf = new AutoCompleteTextField();
        pane.setTop(actf);
        stage.setScene(new Scene(pane));
        stage.show();
    }
}

AutoCompleteTextField.java

import javafx.geometry.Side;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;

public class AutoCompleteTextField extends TextField {
    private ContextMenu suggestionMenu;

    public AutoCompleteTextField(){
        super();
        suggestionMenu = new ContextMenu();
        for(int i = 0; i<5; i++) {
            CustomMenuItem item = new CustomMenuItem(new Label("Item "+i), true);
            item.setOnAction(event -> {
                setText("selected");
                positionCaret(getText().length());
                suggestionMenu.hide();
            });
            suggestionMenu.getItems().add(item);
        }

        textProperty().addListener((observable, oldValue, newValue) -> {
            if(getText().length()>0){
                if (!suggestionMenu.isShowing())
                    suggestionMenu.show(AutoCompleteTextField.this, Side.BOTTOM, 0, 0);
            } else {
                suggestionMenu.hide();
            }
        });

        setOnKeyPressed(event -> {
            System.out.println("pressed " + event.getCode());
            switch (event.getCode()) {
                case DOWN:
                    if(getText().length()>0) {
                        if (!suggestionMenu.isShowing()) {
                            suggestionMenu.show(AutoCompleteTextField.this, Side.BOTTOM, 0, 0);
                        }
                        suggestionMenu.getSkin().getNode().lookup(".menu-item").requestFocus();
                    }
                    break;
            }
        });


    }
}
...