I'm trying to put one component written in Swing (it's JPanel) into a JavaFX application. I managed to do it using code showed on this website: click here
But I'm building my application using FXML file and scene builder. I was trying to put my Swing component on a Pane container with a SwingNode (like it's showed on the picture below):
But unfortunately, I didn't manage to do it. I was looking everywhere and I didn't find anything useful in my case.
I'm quite new to JavaFX and it's really important for me to use scene builder. Is that what I'm trying to do possible at all?
My trials:
Main.JAVA
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Letter Recognition with Neural Networks");
primaryStage.setScene(new Scene(root, 1150, 650));
primaryStage.setResizable(false);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.JAVA
package application;
import application.gui.DrawingPanel;
import javafx.embed.swing.SwingNode;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javax.swing.*;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
@FXML
private Pane pane;
@FXML
private SwingNode swingNode;
@Override
public void initialize(URL location, ResourceBundle resources) {
swingNode = new SwingNode();
pane = new Pane();
createAndSetSwingDrawingPanel(swingNode);
pane.getChildren().add(swingNode);
}
public void createAndSetSwingDrawingPanel(final SwingNode swingNode) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
swingNode.setContent(new DrawingPanel(400, 400 , 20));
}
});
}
}
FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.embed.swing.SwingNode?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<GridPane gridLinesVisible="true" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Pane fx:id="pane" prefHeight="200.0" prefWidth="200.0">
<children>
<SwingNode fx:id="swingNode" />
</children>
</Pane>
<Button mnemonicParsing="false" prefHeight="39.0" prefWidth="80.0" text="Click" GridPane.rowIndex="2">
<font>
<Font size="18.0" />
</font>
</Button>
</children>
</GridPane>
The swing node is already a child of the pane, because in the FXML you have the <SwingNode>
element inside the <children>
element, inside the <Pane>
element. So you should not add it to the child nodes of the pane a second time in the controller.
Furthermore, the FXMLLoader
is going to initialize the pane
and swingNode
fields in the controller to the values created corresponding to the FXML file (that is the whole point of annotating them @FXML
). It is always a mistake to initialize fields that are annotated @FXML
.
So all you need in the initialize
method is
@Override
public void initialize(URL location, ResourceBundle resources) {
createAndSetSwingDrawingPanel(swingNode);
}
Finally, you seem to be missing the <fx:controller>
attribute from your FXML file. In Scene Builder, expand the "controller" panel in the far bottom left, and enter application.Controller
in the "Controller Class" field.