我在JavaFx的SwingNode显示它在Java 1.8.0_102-b14中持有的组件时遇到了问题。我不确定这个问题是由于我的Java版本太旧,当前(如果我的是当前)Java版本中的错误,还是我做错了一些SwingNode进程。我知道这个问题在JavaFX和SwingNode -部分黑窗之前已经报告过了,所以我真的在寻找关于我的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中的内容纠正了这个简单代码的问题,但不适合我的大型项目。所以我猜这是内存泄漏,但是我不能从我的机器上判断出来。
有人可以测试这段代码,看看他们是否得到类似的结果?编辑:谢谢你的快速反馈,请不要把注意力集中在按钮上,因为它们只是一个展示我问题的工具。这个奇怪的功能以同样的方式作用于其他对象而不是按钮。您必须在AWT事件调度线程上创建和显示Swing组件(请参阅Swing的线程策略)。Application.start()
方法是在FX应用线程上调用的。
所以你需要
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);
}
}
在SwingNode中使用JTextArea(使用JDK 1.8.0_202)时,我再次看到了这个渲染问题。对我来说,这个问题发生在两种情况下:
为了解决这个问题,我添加了一个侦听器来设置每次调整窗口大小时摆动节点的内容。
On SplitPane分隔器位置更新:由于swingNode在SplitPane中,我也添加了侦听器。
这两个更新似乎是有效的,但如果我移动分隔线太快,黑色背景又会回来。为了解决这个问题,我将SwingNode上的缓存更改为true,并将cacheHint更改为CacheHint.SPEED
。这消除了所有渲染问题,但它仍然有一个副作用,因为textArea被缓存并显示为位图,它将在一小段时间内不响应用户交互。这对我的情况有效,因为我的文本区域是不可编辑的。
注意swingutility的用法。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。
我通过在显示Stage之后以延迟的方式重新绘制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);
}
}
我希望它有帮助!
有一个关于这个和类似问题的错误报告,据说已经解决了,但显然它并没有完全修复,因为我仍然看到黑色方块而不是启动按钮(1.8.0_91-b15)。
这是因为JavaFX组件是在Swing组件之前创建的。您可以通过在每个组件上调用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在他的回答中提到的,不要忘记您已经在EDT上创建了Swing组件。