Мне скоро придется иметь дело с 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 . |