java - 事件处理程序中的 JavaFX 设置加速器不起作用?
问题描述
为漫长的背景故事道歉。但我认为你有必要了解我的意图并了解错误。
所以这里是:我有一个包含一个按钮的 JavaFX GUI。我的意图是通过右键单击按钮,用户可以调出上下文菜单,此时他们可以使用单次击键来触发菜单项。所以我这是我的start()
方法:
FlowPane root = new FlowPane();
Scene scene = new Scene(root, 300, 100);
Button btn = new Button("Test");
// Add context menu and define actions.
ContextMenu cM = new ContextMenu();
MenuItem mI0 = new MenuItem("First");
mI0.setOnAction(aE ->
{
System.out.println("First Action");
cM.hide();
});
MenuItem mI1 = new MenuItem("Second");
mI1.setOnAction(aE ->
{
System.out.println("Second Action");
cM.hide();
});
cM.getItems().addAll(mI0, mI1);
// Set accelerators.
mI0.setAccelerator(new KeyCodeCombination(KeyCode.F));
mI1.setAccelerator(new KeyCodeCombination(KeyCode.S));
btn.setContextMenu(cM);
root.getChildren.add(btn);
primaryStage.setScene(scene);
primaryStage.show();
这工作正常。我可以右键单击按钮,键入f
或s
,然后打印相应的文本。目前一切都很好。
但在我的 GUI 中,我实际上有几个这样的按钮,每个代表一个可执行文件并有自己的上下文菜单。其上下文菜单中的项目是“运行”和“使用参数运行”,触发它们应该运行特定的可执行文件。所以我的代码变成了这个。为简单起见,我使用水果作为类比。
FlowPane root = new FlowPane();
Scene scene = new Scene(root, 300, 100);
String[] buttonNames = { "Apple", "Pear", "Orange" };
for (String s : buttonNames)
{
Button btn = new Button(s);
// Add context menu and define actions.
ContextMenu cM = new ContextMenu();
MenuItem mI0 = new MenuItem("Eat");
mI0.setOnAction(aE ->
{
System.out.println("Eat " + btn.getText());
cM.hide();
});
MenuItem mI1 = new MenuItem("Cut");
mI1.setOnAction(aE ->
{
System.out.println("Cut " + btn.getText());
cM.hide();
});
cM.getItems().addAll(mI0, mI1);
// Set accelerators.
mI0.setAccelerator(new KeyCodeCombination(KeyCode.E));
mI1.setAccelerator(new KeyCodeCombination(KeyCode.C));
btn.setContextMenu(cM);
root.getChildren().add(btn);
}
primaryStage.setScene(scene);
primaryStage.show();
现在,如果您保持警惕,您可能会立即注意到问题。加速器是为场景设置的,所以即使上下文菜单没有显示,按下e
或c
键盘触发器。更糟糕的是,现在唯一吃掉或切开的水果是橙子,因为它的加速器已经覆盖了苹果和梨的加速器。
所以我对此的解决方案如下。在显示上下文菜单时设置加速器,并在隐藏时移除它们。听起来很容易。
FlowPane root = new FlowPane();
Scene scene = new Scene(root, 300, 100);
String[] buttonNames = { "Apple", "Pear", "Orange" };
for (String s : buttonNames)
{
Button btn = new Button(s);
// Add context menu and define actions.
ContextMenu cM = new ContextMenu();
MenuItem mI0 = new MenuItem("Eat");
mI0.setOnAction(aE ->
{
System.out.println("Eat " + btn.getText());
cM.hide();
});
MenuItem mI1 = new MenuItem("Cut");
mI1.setOnAction(aE ->
{
System.out.println("Cut " + btn.getText());
cM.hide();
});
cM.getItems().addAll(mI0, mI1);
// Set accelerator on context menu show.
cM.setOnShown(wE ->
{
mI0.setAccelerator(new KeyCodeCombination(KeyCode.E));
mI1.setAccelerator(new KeyCodeCombination(KeyCode.C));
System.out.println("Accelerators set for " + btn.getText());
});
// Remove accelerator on context menu hide.
cM.setOnHiding(wE ->
{
cM.getItems().forEach(mI -> mI.setAccelerator(null));
System.out.println("Accelerators removed for " + btn.getText());
});
btn.setContextMenu(cM);
root.getChildren().add(btn);
}
primaryStage.setScene(scene);
primaryStage.show();
没有理由不工作。仅使用鼠标时,它似乎正在工作:
但是当我按下e
或c
打开上下文菜单后,会发生这种情况:
(按e
)
什么都没发生。
现在您可以清楚地看到设置和删除加速器的代码行确实运行了。菜单中E
和C
旁边的Eat
和Cut
表示已设置相应的加速器,控制台打印输出确认了这一点。但是由于某种原因,加速器没有响应我的按键。
有人可以告诉我为什么以及如何解决这个问题吗?
解决方案
推荐阅读
- flutter - Flutter Dropdownbutton选择的值没有改变
- android - 将手机位置从移动应用程序发送到服务器的最佳方式是什么?
- azure-devops - DevOps Release Pipeline 本地 TaskModuleSqlUtility
- docker - 有没有办法将保存的 docker tarball 目录传递给 Anchore 内联扫描?
- firebase - 我可以从数据库中搜索所有推送 id 而不必在应用程序端进行吗
- git - Git Fetch:权限被拒绝
- javascript - 在输入字段内显示复选框
- javascript - 在 router.post 或 router.get 之外使用 req.user
- html - div中的右对齐按钮
- postgresql - Postgresql jsonb 列到行提取值