JavaFx SwingNode - 随机显示黑色,背景或组件

时间:2016-08-17 18:10:54

标签: java swing debugging javafx

我遇到了JavaFx的SwingNode问题,显示它在Java 1.8.0_102-b14中保存的组件。我不确定这个问题是否是由于我的Java版本老了,当前(如果我的是当前的)Java版本中的错误,或者我正在做错的一些SwingNode进程。我知道在JavaFX and SwingNode - partial black Window之前已经报告了这个问题,所以我真的在寻找关于我的Java版本的反馈。

此代码通常会显示" button1"错误,如黑色或背景颜色,直到鼠标悬停在它上面或点击它。这对我来说不是一个理想的解决方法,因为我的项目在Fx项目中使用更复杂的摆动面板而且纯粹的Fx不幸是不可选择的。

import javafx.application.Application;
import javafx.embed.swing.SwingNode;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import javax.swing.JButton;

public class Test extends Application {

  @Override
  public void start(Stage stage) {
      final SwingNode swingNode1 = new SwingNode();
      final SwingNode swingNode2 = new SwingNode();

      swingNode2.setContent(new JButton("Click me!"+2));
      swingNode1.setContent(new JButton("Click me!"+1));

      BorderPane pane = new BorderPane();
      pane.setLeft(swingNode1);
      pane.setRight(swingNode2);

      stage.setScene(new Scene(pane, 200, 50));
      stage.show();
  }

  public static void main(String[] args) {
      launch(args);
  }
}

在创建此sssce时,我发现在设置右侧SwingNode中的内容之前在左侧SwingNode中设置内容更正了这个简单代码的问题,但不适用于我的大型项目。所以我猜这是一个内存泄漏,但我无法通过我的机器告诉你。

有人可以测试此代码并查看它们是否会得到类似的结果吗?

编辑:感谢您的快速反馈,请不要专注于按钮,因为它们只是展示我问题的工具。奇怪的功能与其他对象的作用方式相同,而不是按钮。

4 个答案:

答案 0 :(得分:3)

必须在AWT事件调度线程上创建和显示Swing组件(请参阅Swing's threading policy)。 Application.start()方法为invoked on the FX Application Thread

因此你需要

public class Test extends Application {

  @Override
  public void start(Stage stage) {
      final SwingNode swingNode1 = new SwingNode();
      final SwingNode swingNode2 = new SwingNode();

      SwingUtilities.invokeLater(() -> {
          swingNode2.setContent(new JButton("Click me!"+2));
          swingNode1.setContent(new JButton("Click me!"+1));
      });

      BorderPane pane = new BorderPane();
      pane.setLeft(swingNode1);
      pane.setRight(swingNode2);

      stage.setScene(new Scene(pane, 200, 50));
      stage.show();
  }

  public static void main(String[] args) {
      launch(args);
  }
}

答案 1 :(得分:1)

有一个bug report关于这个和类似的问题据说已经解决,但显然它并没有完全修复,因为我仍然在启动时看到黑色方块而不是按钮(1.8。 0_91-B15)。

这种情况正在发生,因为您的Swing组件之前正在创建JavaFX组件。您可以通过在每个组件上调用requestFocus()来确保它们得到正确呈现来修复此行为:

SwingUtilities.invokeLater(() -> {
    swingNode1.setContent(new JButton("Click me!"+1));
    swingNode1.requestFocus();
    swingNode2.setContent(new JButton("Click me!"+2));
    swingNode2.requestFocus();
});

或者使用invokeAndWait(),以便您的应用程序等待,直到Swing组件的创建完成。

SwingUtilities.invokeAndWait(() -> {
    swingNode1.setContent(new JButton("Click me!"+1));
    swingNode2.setContent(new JButton("Click me!"+2));
});

另外,正如James_D在answer中提到的那样,不要忘记你已经在EDT上创建了Swing组件。

答案 2 :(得分:1)

在显示舞台之后,我通过延迟方式重新绘制Swing组件来解决此问题:

new Timer().schedule(new TimerTask() {
        public void run() {
            swingNode1.getContent().repaint();
            swingNode2.getContent().repaint();
        }
    }, 100L);

因此,您的代码将如下所示:

import javafx.application.Application;
import javafx.embed.swing.SwingNode;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import javax.swing.JButton;

public class Test extends Application {

  @Override
  public void start(Stage stage) {
      final SwingNode swingNode1 = new SwingNode();
      final SwingNode swingNode2 = new SwingNode();

      swingNode2.setContent(new JButton("Click me!"+2));
      swingNode1.setContent(new JButton("Click me!"+1));

      BorderPane pane = new BorderPane();
      pane.setLeft(swingNode1);
      pane.setRight(swingNode2);

      stage.setScene(new Scene(pane, 200, 50));
      stage.show();

      new Timer().schedule(new TimerTask() {
           public void run() {
                swingNode1.getContent().repaint();
                swingNode2.getContent().repaint();
           }
       }, 100L);
  }

  public static void main(String[] args) {
      launch(args);
  }
}

希望对您有帮助!

答案 3 :(得分:0)

在SwingNode中使用JTextArea时(使用JDK 1.8.0_202),我再次看到了此渲染问题。对我而言,此问题发生在两种情况下:

在每次尝试调整窗口大小时:为了解决这个问题,我添加了一个侦听器,以在窗口的每次调整大小时设置swing节点的内容。

在SplitPane分隔器位置更新上:由于swingNode在SplitPane中,因此我也将侦听器添加到了它。

这两个更新似乎可以解决问题,除非我将分隔线移得太快,黑色背景会再次出现。为了解决这个问题,我将SwingNode上的缓存更改为true,并将cacheHint更改为CacheHint.SPEED。这消除了所有渲染问题,但是仍然有一个副作用,因为textArea被缓存并显示为位图,因此它在很短的时间内不会响应用户交互。这适用于我的情况,因为我的文本区域不可编辑。

请注意,使用SwingUtilities.invokelater似乎对渲染没有任何影响,因此我将其排除在代码之外。

swingNode.setContent(textArea);

ChangeListener<Number> sizeListener = (o, oldSize, newSize) -> {
  swingNode.setContent(textArea);
};

splitPane.getDividers().forEach( divider -> divider.positionProperty().addListener(sizeListener));
primaryStage.heightProperty().addListener(sizeListener);
primaryStage.widthProperty().addListener(sizeListener);

swingNode.setCache(true);
swingNode.setCacheHint(CacheHint.SPEED);

此问题似乎已针对JButton修复。