Мне скоро придется иметь дело с JavaFX в толстом клиенте на основе Swing — о, извините, конечно, я имел в виду «многослойный богатый клиент»!
Так что это заставляет меня взглянуть на JFXPanel . JFXPanel является компонентом javax.swing.J для встраивания содержимого JavaFX в Swing-UI. JFXPanel может использоваться аналогично JPanel, и доступ к нему можно получить через EDT как общий компонент Swing, за исключением того, что работа с компонентом JavaFX должна выполняться через поток приложения JavaFX .
Чтобы поиграть с этим, я создал две одинаковые панели (Swing + JavaFX), каждая из которых имеет кнопку, текстовое поле и метку, и поместил их в JSplitPane и JFrame:
Присмотритесь внутрь
Чтобы попробовать взаимодействие Swing <-> JavaFX, действия кнопок устанавливают текст из TextField в JLabel и наоборот.
В JPanel нет ничего особенного, так как он обрабатывает общие вещи Swing, но с JFXPanel, содержащей элементы управления JavaFX:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public class SwingFXPanel extends JFXPanel { private Button testButton; private TextField testTextField; private Label testLabel; private VBox pane; public SwingFXPanel() { init(); } private void init() { testButton = new Button( "I am a JavaFX Button" ); testTextField = new TextField(); testLabel = new Label( "empty" ); pane = new VBox(); pane.setAlignment(Pos.CENTER); pane.getChildren().addAll(testTextField, testButton, testLabel); Platform.runLater( this ::createScene); } private void createScene() { Scene scene = new Scene(pane); setScene(scene); } public Button getTestButton() { return testButton; } public TextField getTestTextField() { return testTextField; } public Label getTestLabel() { return testLabel; } } |
Важно здесь: добавить сцену в JFXPanel в потоке приложений JavaFX:
1
|
Platform.runLater( this ::createScene); |
Если вы позвоните:
1
|
createScene() |
из другого потока вы получаете Runtime-Exception:
1
|
java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue- 0 |
Кроме того, каждое взаимодействие с JavaFX должно быть размещено в потоке приложений JavaFX:
Например:
1
2
3
|
Platform.runLater(() -> { swingFXPanel.getTestLabel().setText(swingPanel.getTestTextField().getText()); }); |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
public class InteropFrame extends JFrame { private JSplitPane centralSplitPane; private SwingPanel swingPanel; private SwingFXPanel swingFXPanel; public InteropFrame(){ init(); } private void init() { setTitle( "Swing <-> JavaFX Interoperatbiliy" ); setSize( 500 , 500 ); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout( new BorderLayout()); centralSplitPane = new JSplitPane(); centralSplitPane.setDividerLocation( 0.5 ); centralSplitPane.setResizeWeight( 0.3 ); swingPanel = new SwingPanel(); swingFXPanel = new SwingFXPanel(); swingPanel.getTestButton().addActionListener((ActionEvent e) -> { Platform.runLater(() -> { swingFXPanel.getTestLabel().setText(swingPanel.getTestTextField().getText()); }); }); swingFXPanel.getTestButton().setOnAction((javafx.event.ActionEvent t) -> { swingPanel.getTestLabel().setText(swingFXPanel.getTestTextField().getText()); }); centralSplitPane.setLeftComponent(swingPanel); centralSplitPane.setRightComponent(swingFXPanel); add(centralSplitPane, BorderLayout.CENTER); } } |
Кроме того, работа с FXML довольно проста:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
public class SwingFXMLPanel extends JFXPanel { @FXML private Button testButton; @FXML private TextField testTextField; @FXML private Label testLabel; private VBox rootPane; private URL fxmlResource; public SwingFXMLPanel(URL fxmlResource){ this .fxmlResource = fxmlResource; init(); } private void init(){ rootPane = new VBox(); FXMLLoader loader = new FXMLLoader(fxmlResource); loader.setController( this ); loader.setRoot(rootPane); try { loader.load(); } catch (IOException ex) { Logger.getLogger(SwingFXMLPanel. class .getName()).log(Level.SEVERE, null , ex); } testButton.setText( "I am a JavaFX Button" ); testLabel.setText( "empty" ); Platform.runLater( this ::createScene); } private void createScene() { Scene scene = new Scene(rootPane); setScene(scene); } public Button getTestButton() { return testButton; } public TextField getTestTextField() { return testTextField; } public Label getTestLabel() { return testLabel; } } |
Для меня очень важно получить максимально возможное признание моих коллег использовать JavaFX в Swing.
Поэтому я хочу упростить конкретную обработку потоков приложения FX. Так что, возможно, этого можно достичь, если основное отличие от использования JPanel состоит в том, чтобы просто добавить:
1
2
3
4
|
private void createScene() { Scene scene = new Scene(rootPane); setScene(scene); } |
и позвонить:
1
|
Platform.runLater( this ::createScene); |
внутри JFXPanel .
- Вы можете найти полный пример кода здесь .
Ссылка: | Swing и JavaFX: работа с JFXPanel от нашего партнера JCG Дженса Детерса в блоге JavaFX Delight . |