Embedding swing in JavaFX which is also embedded in Swing, causing extra COMPONENT_SHOWN events

huangapple 未分类评论69阅读模式
英文:

Embedding swing in JavaFX which is also embedded in Swing, causing extra COMPONENT_SHOWN events

问题

好的,以下是翻译好的部分:

这个有点奇怪。

我在一个JavaFX组件中嵌入了Swing组件,而这个JavaFX组件又被嵌入在一个Swing GUI中,由于某种原因,这导致我的组合框无法正常工作。

我知道我将会得到的第一个回答是:“看在宇宙万物的一切善良之名下,你为什么要做这样的事情”。如果这是你的初始反应,那么你并没有错,但我仍然想要理解发生了什么。简要地回答为什么我要这样做,我们的工具集中有大量的Swing代码,但我们已经开始在任何新的GUI组件上使用JavaFX。有时这些JavaFX组件会在其中使用一些旧的Swing组件,因为我们经常没有时间/预算来重新编写所有我们想要更新的内容。因此,在这个最小的可复现示例中,去掉内部的Swing组件会很容易,但我感兴趣的实际软件要复杂得多。

这是我的最小可复现示例:

  1. public class BadComboBox {
  2. public static void main(String[] args) {
  3. SwingUtilities.invokeLater(BadComboBox::createGUI);
  4. }
  5. private static void createGUI() {
  6. JFrame frame = new JFrame();
  7. JTabbedPane tabPane = new JTabbedPane();
  8. JComboBox<String> comboBox = new JComboBox<>();
  9. comboBox.addItem("one");
  10. comboBox.addItem("two");
  11. tabPane.add("1", getFxPanelWithEmbeddedSwing());
  12. tabPane.add("2", comboBox);
  13. frame.add(tabPane);
  14. frame.setVisible(true);
  15. frame.setSize(300, 100);
  16. }
  17. private static JFXPanel getFxPanelWithEmbeddedSwing() {
  18. JFXPanel jfxPaneWithEmbeddedSwing = new JFXPanel();
  19. Platform.runLater(() -> {
  20. Scene scene = new Scene(new PaneWithSwingNode());
  21. jfxPaneWithEmbeddedSwing.setScene(scene);
  22. });
  23. return jfxPaneWithEmbeddedSwing;
  24. }
  25. private static class PaneWithSwingNode extends Pane {
  26. public PaneWithSwingNode() {
  27. SwingNode swingNode = new SwingNode();
  28. this.getChildren().add(swingNode);
  29. SwingUtilities.invokeLater(() -> swingNode.setContent(new JPanel()));
  30. }
  31. }
  32. }

正如你所看到的,我有一个带有两个选项卡的选项卡窗格。第一个选项卡包含一个包含嵌入式Swing节点的JavaFX窗格。如果启动程序,点击第二个选项卡,然后点击组合框的下拉按钮,它似乎不会展开。实际上,它展开然后立即再次折叠。

我进行了一些调试,涉及步进AWT事件分派代码的细节,发现由于某种原因,触发了一个COMPONENT_SHOWN事件,这最终会调用组合框的ancestorAdded侦听器,从而隐藏组合框的弹出窗口。

如果我删除将SwingNode添加到JavaFX窗格的那一行,那么组合框将会正常工作。

英文:

OK, this is a weird one.

I'm embedding swing components in a JavaFX component which in turn is embedded in a Swing GUI and for some reason it is causing my combo boxes to not work.

I know that the first answers I'm going to get are "For the love of all that is good in this universe, why would you ever do anything like this". If that's your initial response, then you are not wrong, but still I would like to understand what is going on. To briefly answer why I am doing this at all, we have a large amount of swing code in our toolset, but we've started using JavaFX for any new GUI components. Sometimes those JavaFX components will use some of our older swing components inside them since we often don't have the time/budget to re-write everything we'd like to update. So in this minimum reproducible example, it would be easy to just get rid of the internal swing component, but the actual software I'm interested in is much larger.

Here is my minimum reproducible example:

  1. public class BadComboBox {
  2. public static void main(String[] args) {
  3. SwingUtilities.invokeLater(BadComboBox::createGUI);
  4. }
  5. private static void createGUI() {
  6. JFrame frame = new JFrame();
  7. JTabbedPane tabPane = new JTabbedPane();
  8. JComboBox&lt;String&gt; comboBox = new JComboBox&lt;&gt;();
  9. comboBox.addItem(&quot;one&quot;);
  10. comboBox.addItem(&quot;two&quot;);
  11. tabPane.add(&quot;1&quot;, getFxPanelWithEmbeddedSwing());
  12. tabPane.add(&quot;2&quot;, comboBox);
  13. frame.add(tabPane);
  14. frame.setVisible(true);
  15. frame.setSize(300, 100);
  16. }
  17. private static JFXPanel getFxPanelWithEmbeddedSwing() {
  18. JFXPanel jfxPaneWithEmbeddedSwing = new JFXPanel();
  19. Platform.runLater(() -&gt; {
  20. Scene scene = new Scene(new PaneWithSwingNode());
  21. jfxPaneWithEmbeddedSwing.setScene(scene);
  22. });
  23. return jfxPaneWithEmbeddedSwing;
  24. }
  25. private static class PaneWithSwingNode extends Pane {
  26. public PaneWithSwingNode() {
  27. SwingNode swingNode = new SwingNode();
  28. this.getChildren().add(swingNode);
  29. SwingUtilities.invokeLater(() -&gt; swingNode.setContent(new JPanel()));
  30. }
  31. }
  32. }

As you can see I've got a tabbed pane with two tabs. The first contains a JavFX pane which contains an embedded swing node. If you launch the program, click on the second tab and then click on the dropdown button on the combo box, it will appear to not expand. In actuality, it expands and then immediately collapses again.

I did some debugging that involved stepping through the bowels of the AWT event dispatch code and found that for whatever reason, a COMPONENT_SHOWN event is getting triggered, which ends up calling the combo box's ancestorAdded listener, which hides the combo box popup.

If I remove the line that adds the SwingNode to the JavaFX pane, then the combo box will work just fine.

huangapple
  • 本文由 发表于 2020年7月28日 23:37:34
  • 转载请务必保留本文链接:https://java.coder-hub.com/63137860.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定