【发布时间】:2019-03-09 11:59:03
【问题描述】:
我正在尝试制作一个自动完成样式 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;
}
});
使用此代码,向下箭头始终“选择”(蓝色)列表中的第一项。问题是有时(对我来说似乎是随机的),第二个箭头按键不会在 ContextMenu 中产生任何响应 - 第一项将保持选中状态。按下之后,它总是能正常工作。
我还希望在选择第一个元素时按下会隐藏 ContextMenu,并且该空间不会触发 MenuItem 的 onAction 方法,不过我真的不明白这个菜单的焦点/事件监听是如何工作的。键盘似乎同时有两个焦点 - 上/下、空格键和 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;
}
});
}
}
【问题讨论】:
-
当然,我加了一个例子。
-
ooookay .. 无法重现未选择,但看过它,所以似乎很随机 ;) 至于您的要求的细节:有点难以理解 - 穿着你的鞋子我会看一下 ContextMenuSkin 和 ContextMenuContent,后者负责所有的键绑定、选择等 - 你可能能够连接到它们(如果你的上下文不太复杂,比如有多个级别的子菜单)。
标签: java javafx focus contextmenu textfield