单击 JFXPanel 中嵌入的打开 JavaFX 菜单不会将其关闭
Click on open JavaFX Menu embedded in JFXPanel does not close it
通过 JFXPanel
在 Swing window 中嵌入菜单时,我无法通过单击关闭菜单。有时它会闪烁,好像它关闭并立即重新打开。
package testjavafx;
public class TestMenuJavaFX extends Application {
@Override
public void start(Stage primaryStage) {
MenuBar menuBar = new MenuBar(
new Menu("Menu 1", null,
new MenuItem("Menu item 1-1"),
new MenuItem("Menu item 1-2")),
new Menu("Menu 2", null,
new MenuItem("Menu item 2-1"),
new MenuItem("Menu item 2-2")),
new Menu("Menu 3", null,
new MenuItem("Menu item 3-1"),
new MenuItem("Menu item 3-1")));
menuBar.setPrefWidth(300);
Region root = new Pane(menuBar);
root.setPrefSize(300, 185);
useJFXPanel(root);
//usePrimaryStage(primaryStage, root);
}
private static void useJFXPanel(Region root) {
JFXPanel jfxPanel = new JFXPanel();
jfxPanel.setScene(new Scene(root));
JFrame jFrame = new JFrame("test menu JavaFX");
jFrame.setSize((int) root.getWidth(), (int) root.getHeight());
jFrame.add(jfxPanel);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
}
private static void usePrimaryStage(Stage primaryStage, Parent root) {
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(TestMenuJavaFX.class, args);
}
}
通过使用方法 usePrimaryStage
我得到了预期的行为(点击菜单打开它,再次点击关闭它),但是 useJFXPanel
问题出现了。
这是一个事件处理问题,鼠标单击首先作为 Swing 鼠标事件分派到 JFXPanel,然后 JFXPanel
在内部将 JavaFX 鼠标事件分派到其嵌入的 Scene
。
看起来,在 Swing 部分,菜单失去焦点并关闭,当事件到达 Menu 实例时,它发现它关闭并因此打开它。
我试图继承Menu
class来给它添加一个鼠标点击事件处理程序,但是它不处理鼠标点击,并且使用showing/shown和hiding/hidden 提供的事件对它没有帮助(因为问题发生得更早)。
我还尝试通过 subclass MenuBar
添加鼠标单击事件处理程序,但只有在菜单外的栏上单击时才会调用该处理程序,所以这里没有运气,而 subclass JFXPanel
覆盖 processMouseEvent
并通过反射黑魔法检索 MenuBarButton
实例,但我无法使其工作。
这是一个错误,对吧?是否有解决此问题的(简单干净,理想情况下)解决方法?
我正在使用 OpenJDK 11.0.10.9 和 JavaFX 17.0.0.1。
在我的系统上,这不会 运行,但会在启动时挂起,因为 JFrame
是在错误的线程上创建和显示的。更正确实显示了您描述的行为,这似乎是一个错误。
我找到了一个解决方法,即捕获一个 ON_HIDING
事件并使用 Platform.runLater(...)
安排调用以隐藏事件队列中更靠后的菜单。生成的代码如下所示;
public class TestMenuJavaFX extends Application {
@Override
public void start(Stage primaryStage) {
MenuBar menuBar = new MenuBar(
new Menu("Menu 1", null,
new MenuItem("Menu item 1-1"),
new MenuItem("Menu item 1-2")),
new Menu("Menu 2", null,
new MenuItem("Menu item 2-1"),
new MenuItem("Menu item 2-2")),
new Menu("Menu 3", null,
new MenuItem("Menu item 3-1"),
new MenuItem("Menu item 3-1")));
menuBar.setPrefWidth(300);
menuBar.getMenus().forEach(menu -> {
menu.addEventHandler(Menu.ON_HIDING, e -> {
Platform.runLater(menu::hide);
});
});
Region root = new Pane(menuBar);
root.setPrefSize(300, 185);
useJFXPanel(root);
//usePrimaryStage(primaryStage, root);
}
private static void useJFXPanel(Region root) {
JFXPanel jfxPanel = new JFXPanel();
jfxPanel.setScene(new Scene(root));
SwingUtilities.invokeLater(() -> {
JFrame jFrame = new JFrame("test menu JavaFX");
jFrame.setSize((int) root.getWidth(), (int) root.getHeight());
jFrame.add(jfxPanel);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
});
}
private static void usePrimaryStage(Stage primaryStage, Parent root) {
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(TestMenuJavaFX.class, args);
}
}
通过 JFXPanel
在 Swing window 中嵌入菜单时,我无法通过单击关闭菜单。有时它会闪烁,好像它关闭并立即重新打开。
package testjavafx;
public class TestMenuJavaFX extends Application {
@Override
public void start(Stage primaryStage) {
MenuBar menuBar = new MenuBar(
new Menu("Menu 1", null,
new MenuItem("Menu item 1-1"),
new MenuItem("Menu item 1-2")),
new Menu("Menu 2", null,
new MenuItem("Menu item 2-1"),
new MenuItem("Menu item 2-2")),
new Menu("Menu 3", null,
new MenuItem("Menu item 3-1"),
new MenuItem("Menu item 3-1")));
menuBar.setPrefWidth(300);
Region root = new Pane(menuBar);
root.setPrefSize(300, 185);
useJFXPanel(root);
//usePrimaryStage(primaryStage, root);
}
private static void useJFXPanel(Region root) {
JFXPanel jfxPanel = new JFXPanel();
jfxPanel.setScene(new Scene(root));
JFrame jFrame = new JFrame("test menu JavaFX");
jFrame.setSize((int) root.getWidth(), (int) root.getHeight());
jFrame.add(jfxPanel);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
}
private static void usePrimaryStage(Stage primaryStage, Parent root) {
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(TestMenuJavaFX.class, args);
}
}
通过使用方法 usePrimaryStage
我得到了预期的行为(点击菜单打开它,再次点击关闭它),但是 useJFXPanel
问题出现了。
这是一个事件处理问题,鼠标单击首先作为 Swing 鼠标事件分派到 JFXPanel,然后 JFXPanel
在内部将 JavaFX 鼠标事件分派到其嵌入的 Scene
。
看起来,在 Swing 部分,菜单失去焦点并关闭,当事件到达 Menu 实例时,它发现它关闭并因此打开它。
我试图继承Menu
class来给它添加一个鼠标点击事件处理程序,但是它不处理鼠标点击,并且使用showing/shown和hiding/hidden 提供的事件对它没有帮助(因为问题发生得更早)。
我还尝试通过 subclass MenuBar
添加鼠标单击事件处理程序,但只有在菜单外的栏上单击时才会调用该处理程序,所以这里没有运气,而 subclass JFXPanel
覆盖 processMouseEvent
并通过反射黑魔法检索 MenuBarButton
实例,但我无法使其工作。
这是一个错误,对吧?是否有解决此问题的(简单干净,理想情况下)解决方法?
我正在使用 OpenJDK 11.0.10.9 和 JavaFX 17.0.0.1。
在我的系统上,这不会 运行,但会在启动时挂起,因为 JFrame
是在错误的线程上创建和显示的。更正确实显示了您描述的行为,这似乎是一个错误。
我找到了一个解决方法,即捕获一个 ON_HIDING
事件并使用 Platform.runLater(...)
安排调用以隐藏事件队列中更靠后的菜单。生成的代码如下所示;
public class TestMenuJavaFX extends Application {
@Override
public void start(Stage primaryStage) {
MenuBar menuBar = new MenuBar(
new Menu("Menu 1", null,
new MenuItem("Menu item 1-1"),
new MenuItem("Menu item 1-2")),
new Menu("Menu 2", null,
new MenuItem("Menu item 2-1"),
new MenuItem("Menu item 2-2")),
new Menu("Menu 3", null,
new MenuItem("Menu item 3-1"),
new MenuItem("Menu item 3-1")));
menuBar.setPrefWidth(300);
menuBar.getMenus().forEach(menu -> {
menu.addEventHandler(Menu.ON_HIDING, e -> {
Platform.runLater(menu::hide);
});
});
Region root = new Pane(menuBar);
root.setPrefSize(300, 185);
useJFXPanel(root);
//usePrimaryStage(primaryStage, root);
}
private static void useJFXPanel(Region root) {
JFXPanel jfxPanel = new JFXPanel();
jfxPanel.setScene(new Scene(root));
SwingUtilities.invokeLater(() -> {
JFrame jFrame = new JFrame("test menu JavaFX");
jFrame.setSize((int) root.getWidth(), (int) root.getHeight());
jFrame.add(jfxPanel);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
});
}
private static void usePrimaryStage(Stage primaryStage, Parent root) {
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(TestMenuJavaFX.class, args);
}
}