java - 使用箭头键控制连接到 TextField 的 JavaFX ContextMenu

标签 java javafx focus contextmenu textfield

我正在尝试制作一个自动完成样式 TextField,它使用 ContextMenu 在 TextField 下方显示建议。我希望当用户在焦点位于 TextField 上时按下向下键时显示 ContextMenu。这是我目前的解决方案:

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;
        }
    });

Source: ContextMenu and programmatically selecting an item

使用此代码,向下箭头始终“选择”(蓝色)列表中的第一项。问题是有时(对我来说似乎是随机的),第二个箭头按键不会在 ContextMenu 中产生任何响应 - 第一个项目将保持选中状态。按下之后,它将始终正常工作。

我还希望在选择第一个元素时按下按钮会隐藏 ContextMenu,并且该空格不会触发 MenuItemonAction 方法,尽管我真的不明白这个菜单的焦点/事件监听是如何工作的。键盘似乎同时具有两个焦点 - 上/下、空格键和在 ContextMenu 上输入,而其他所有内容都转到 TextField。

编辑: 这是一个完整的例子。使用向下箭头键显示 ContextMenu 时,有时会导致问题行为,有时则不会。

主.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;
            }
        });


    }
}

最佳答案

我根据 this 创建了一个解决方案和 ContextMenuContent.class

ContextMenuContent,正如 kleopatra 所建议的那样,完成了大部分的键绑定(bind)。在内部,有一个名为 requestFocusOnIndex() 的方法可以让我摆脱这种奇怪的行为。

所以你的代码可以是:

textField.addEventFilter(KeyEvent.KEY_PRESSED, event->{
    if(event.getCode() == KeyCode.DOWN) {
        if(!suggestionMenu.isShowing())
            suggestionMenu.show(textField, Side.BOTTOM, 0, 0);
        suggestionMenuKeyBindings = (ContextMenuContent) suggestionMenu.getSkin().getNode();
        suggestionMenuKeyBindings.requestFocusOnIndex(0);
    }
});

此外,您还需要放置

--add-exports javafx.controls/com.sun.javafx.scene.control=ALL-UNNAMED

在编译和运行时,否则你可能会得到一个 IllegalAccessError

关于java - 使用箭头键控制连接到 TextField 的 JavaFX ContextMenu,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55077121/

相关文章:

java - spring mvc 使用 post 方法传递对象

Javafx - 打印 DPI 大于 72 的节点

jquery-ui - jQuery 自动完成和焦点事件

Javafx- 鼠标单击事件可撤消上一次鼠标单击所做的操作

javascript - 通过触发输入焦点打开 iOS 键盘

java - 如何防止 Java Swing 中的工具栏按钮焦点?

java - Android AsyncTask 语法错误

javax.net.ssl.SSLException : Certificate for <> doesn't match any of the subject alternative names: [] 异常

java - 如何在 Tor 中使用 HtmlUnit?

java - 在没有 GUI 的情况下启动 JavaFX 应用程序线程