为漫长的背景故事道歉。但我认为你有必要了解我的意图并理解这个错误。
所以这就是:我有一个包含按钮的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
表示已设置相应的加速器,控制台打印输出确认了这一点。但由于某种原因,加速器没有响应我的按键。
有人可以告诉我为什么以及可能如何解决这个问题?