I am currently working on a JavaFx Application. Fx is supposed to only be responsible for UI Content, while the pretty complex functionality is inside a different already finished project, which was created using Swing. To accomplish this, I built an FXML using Scenebuilder, then passed a number of Swing Panels into seperate SwingNodes and passed the SwingNodes into different Tabs of a TabPane (all done inside the start() method of my Application class). Upon starting the Program everything looks fine, the Swing and Fx Content is shown correctly and the functionality works as well. However when resizing the Application Window manually, the SwingNode Content misbehaves, sometimes the Tab remains empty, sometimes only a part of the Node is painted, sometimes it just shows completly black.
Right now, the actual started Program is the "old" Swing Project, which at some Point uses Platform.startup() to start the FX Application. This is necessary for functionality reasons. The Swing Panels at that point get passed into SwingNodes, which are located within the Fx Project.
I have tried to "update" the SwingNodes by continuosly setting the SwingNode-Content on Window Resizing. Also I tried to repaint Swing Content. Both attempts to no success.
What am I missing? Why is the SwingNode Content not resizing with the rest of the window? Is the Swing Content possibly too large to function properly? Or is there possibly some multi-threading Problem?
I understand that this problem might be hard to follow without any Code Examples. I am currently working on creating a minimalistic Version of both projects, to reproduce my Problem and will update as soon as it is done.
EDIT:
I believe i was able to reproduce the problem and have tried to include everything down below. fx is passed to the swing BuildPath, but not the other way around.
When running swing a FX window opens, containing three tabs, all filled with SwingNodes. However when this window gets resized by the user, only the active tab´s SwingNode gets repainted properly. The other two tabs still contain the Nodes, however the Elements only reappear once the mouse has hovered over them -this doesnt work for the label. I have experimented with using repaint on the SwingNodes, to no success so far, so I have chosen to not include it here.
SECOND EDIT: Removed the FXML and FXML Controller Class, to make the question a little bit smaller. The FXML is just a simple TabPane with 3 Tabs built in SceneBuilder, the Controller only contains the Getters for the 3 Tabs.
Tab 2 after resizing and hovering over 3 of the 10 Buttons
The Structure of the Fx Project in ProjectExplorer
The Structure of the Swing Project in ProjectExplorer
The Project fx contains the class MainFx which extends Application and a Controller DebugWindowController for the FXML File. Also there is an Interface
MainInterface which is implemented by the class Main in the project swing
Class MainFx
package controllers;
import interfaces.MainInterface;
import javafx.application.Application;
import javafx.embed.swing.SwingNode;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class MainFx extends Application {
private DebugWindowController debugWindowController;
private AnchorPane mainRoot;
private final SwingNode swingNode1 = new SwingNode();
private final SwingNode swingNode2 = new SwingNode();
private final SwingNode swingNode3 = new SwingNode();
private MainInterface mainInterface = null;
@Override
public void start(Stage primaryStage) {
try {
FXMLLoader debugWindowLoader = new FXMLLoader(getClass().getResource("/view/DebugWindow.fxml"));
mainRoot = debugWindowLoader.load();
debugWindowController = debugWindowLoader.getController();
Scene scene1 = new Scene(mainRoot);
fillFxTabPane();
primaryStage.setScene(scene1);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
private void fillFxTabPane() {
swingNode1.setContent(mainInterface.getPanel1());
swingNode2.setContent(mainInterface.getPanel2());
swingNode3.setContent(mainInterface.getPanel3());
debugWindowController.getTab1().setContent(swingNode1);
debugWindowController.getTab2().setContent(swingNode2);
debugWindowController.getTab3().setContent(swingNode3);
}
public MainInterface getMainInterface() {
return mainInterface;
}
public void setMainInterface(MainInterface mainInterface) {
this.mainInterface = mainInterface;
}
}
Interface MainInterface
package interfaces;
import javax.swing.JComponent;
public interface MainInterface {
JComponent getPanel1();
JComponent getPanel2();
JComponent getPanel3();
}
The project swing consists of only one Class which contains the main() Method that is used to start the program.
Class Main
package swing;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import controllers.MainFx;
import interfaces.MainInterface;
import javafx.application.Platform;
import javafx.stage.Stage;
public class Main implements MainInterface {
private JPanel panel1;
private JPanel panel2;
private JPanel panel3;
public Main() {
panel1 = new JPanel();
JLabel label1 = new JLabel("Panel1");
panel1.add(label1);
for (int i = 0; i < 10; i++) {
JButton button = new JButton("B" + (i + 1));
panel1.add(button);
}
panel2 = new JPanel();
JLabel label2 = new JLabel("Panel2");
panel2.add(label2);
for (int i = 0; i < 10; i++) {
JButton button = new JButton("B" + (i + 1));
panel2.add(button);
}
panel3 = new JPanel();
JLabel label3 = new JLabel("Panel3");
panel3.add(label3);
for (int i = 0; i < 10; i++) {
JButton button = new JButton("B" + (i + 1));
panel3.add(button);
}
MainFx mainFx = new MainFx();
mainFx.setMainInterface(this);
Platform.startup(() -> {// launch JavaFx application
Stage stage = new Stage();
try {
mainFx.start(stage);
} catch (Exception ex) {
ex.printStackTrace();
}
});
}
public static void main(String[] args) {
Main main = new Main();
}
@Override
public JComponent getPanel1() {
return panel1;
}
@Override
public JComponent getPanel2() {
return panel2;
}
@Override
public JComponent getPanel3() {
return panel3;
}
}