在JavaFX程式中嵌入Swing內容
本教程描述如何在JavaFX應用程式中嵌入Swing元件。本文將討論執行緒限制並提供一個可執行的應用程式來說明在JavaFX應用程式中嵌入帶HTML內容的Swing按鈕,以及Swing與JavaFX按鈕間的協作性。
從JavaFX 2.0版本開始,就可以在Swing應用程式中嵌入JavaFX內容。為了增強JavaFX和Swing之間的協作性,JavaFX 8引入了一個新的類,提供了反向整合並使得開發者能夠在JavaFX應用程式中嵌入Swing元件。
在執行本章程式碼之前,需要在計算機上安裝JDK 8。
SwingNode類
JavaFX 8中引入了SwingNode類,其位於javafx.embed.swing包中。這個類使你可以在JavaFX應用程式中嵌入Swing內容。要指定SwingNode物件的內容,呼叫setContent方法,可以傳入一個javax.swing.JComponent類的例項。你可以在JavaFX應用程式執行緒或者EDT中呼叫setContent方法。但是為了訪問Swing內容,確保程式碼執行在EDT上,因為標準Swing執行緒限制。
例7-1的程式碼展示例使用SwingNode類的通常模式。
例7-1
import javafx.application.Application; import javafx.embed.swing.SwingNode; import javafx.scene.Scene; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javax.swing.JButton; import javax.swing.SwingUtilities; public class SwingFx extends Application { @Override public void start (Stage stage) { final SwingNode swingNode = new SwingNode(); createSwingContent(swingNode); StackPane pane = new StackPane(); pane.getChildren().add(swingNode); stage.setTitle("Swing in JavaFX"); stage.setScene(new Scene(pane, 250, 150)); stage.show(); } private void createSwingContent(final SwingNode swingNode) { SwingUtilities.invokeLater(() -> { swingNode.setContent(new JButton("Click me!")); }); } }
執行程式碼後,輸出如圖7-1所示。
圖7-1 在JavaFX程式中嵌入Swing的JButton
嵌入Swing內容並處理事件
在Swing教程中的ButtonHtmlDemo為3個按鈕添加了字型、顏色和的其他格式,如例7-2和例7-3所示。按鈕響應滑鼠和鍵盤事件,如例7-5和例7-6所示。圖7-2展示了在ButtonHtmlDemo中用Swing建立的三個按鈕嵌入在一個JavaFX應用程式(SwingNodeSample)中的效果。你將建立SwingNodeSample應用程式以及確保所有事件被傳遞到適當的Swing按鈕中並得到處理。
圖7-2
左按鈕和右按鈕有多行用HTML格式實現的文字,如例7-2所示。
例7-2
b1 = new JButton("<html><center><b><u>D</u>isable</b><br>"
+ "<font color=#ffffdd>middle button</font>",
leftButtonIcon);
b3 = new JButton("<html><center><b><u>E</u>nable</b><br>"
+ "<font color=#ffffdd>middle button</font>",
rightButtonIcon);
中間按鈕格式簡單不需要HTML,所以只需要用一個字串標籤和一個圖片來初始化,如例7-3所示。
例7-3
b2 = new JButton("middle button", middleButtonIcon);
所有3個按鈕都有工具提示和助記符字元,如例7-4所示。
例7-4
b1.setToolTipText("Click this button to disable the middle button.");
b2.setToolTipText("This middle button does nothing when you click it.");
b3.setToolTipText("Click this button to enable the middle button.");
b1.setMnemonic(KeyEvent.VK_D);
b2.setMnemonic(KeyEvent.VK_M);
b3.setMnemonic(KeyEvent.VK_E);
左按鈕和右按鈕分別用來禁用和啟用中間按鈕。為了使程式能夠檢測並響應使用者對3個按鈕的操作,如例7-5所示附加操作監聽器並設定操作指令。
例7-5
b1.addActionListener(this);
b3.addActionListener(this);
b1.setActionCommand("disable");
b3.setActionCommand("enable");
如例7-6所示實現actionPerformed方法。此方法當用戶點選左按鈕或右按鈕時會被呼叫。
例7-6
public void actionPerformed(ActionEvent e) {
if ("disable".equals(e.getActionCommand())) {
b2.setEnabled(false);
b1.setEnabled(false);
b3.setEnabled(true);
} else {
b2.setEnabled(true);
b1.setEnabled(true);
b3.setEnabled(false);
}
}
檢視ButtonHtmlDemo.java類的完整程式碼。
現在建立一個JavaFX工程並執行SwingNodeSample應用程式。
為了建立SwingNodeSample應用程式:
確保電腦已經安裝JDK 8。然後在NetBeans IDE中建立一個JavaFX工程。
1. 在File選單中,選擇New Project。
2. 在JavaFX應用程式分類中,選擇JavaFX Application並點選Next。
3. 將工程命名為SwingNodeSample並選擇基於JDK 8的JavaFX平臺。點選Finish。
4. 在Projects視窗中,右鍵點選swingnodesample資料夾。選擇New,然後選擇Java class。
5. 命名新的類為ButtonHtml並點選Finish。
6. 複製ButtonHtml.java類的程式碼到這個工程裡。
7. 開啟磁碟中的swingnodesample資料夾並新建images資料夾。
8. 右鍵點選圖片,選擇圖片另存為,下載left.gif, middle.gif和right.gif圖片,並儲存在images資料夾中。
9. 在SwingNodeSample類中,刪除start方法裡NetBeans自動生成的程式碼。
10. 相應的建立SwingNode物件和實現start方法,如例7-7所示。
例7-7
public void start(Stage stage) {
final SwingNode swingNode = new SwingNode();
createSwingContent(swingNode);
StackPane pane = new StackPane();
pane.getChildren().add(swingNode);
Scene scene = new Scene(pane, 450, 100);
stage.setScene(scene);
stage.setTitle("ButtonHtmlDemo Embedded in JavaFX");
stage.show();
}
11. 為了嵌入ButtonHtml類生成的三個按鈕,將SwingNode物件的內容設定為ButtonHtml類的一個例項,如例7-8所示。
例7-8
private void createSwingContent(final SwingNode swingNode) {
SwingUtilities.invokeLater(() -> {
swingNode.setContent(new ButtonHtml());
});
}
12. 按Ctrl(或Cmd)+Shift+I來修正引入宣告。
可以點選SwingNodeSample.zip連結來下來SwingNodeSample應用程式的原始碼。
執行SwingNodeSample工程並確認所有的按鈕提供的互動方法都執行正常:
● 對於滑鼠,越過按鈕時可以看見工具提示。
● 點選左按鈕和右按鈕可以對應禁用和啟用中間按鈕。
● 按Alt+D和Alt+E可以對應禁用和啟用中間按鈕。
新增Swing和JavaFX元件之間的協作性。
你可以提供JavaFX按鈕和Swing按鈕之間的協作性。例如圖7-3所示的EnableFXButton程式可以使使用者點選Swing按鈕來禁用或啟用一個JavaFX按鈕。相反的,圖7-4所示的EnableButtons程式可以使使用者點選一個JavaFX按鈕來觸發一個Swing按鈕。
圖7-3 啟用JavaFX按鈕樣例
使用Swing按鈕來操作一個JavaFX按鈕
修改SwingNodeSample程式並將中間按鈕改為javafx.scene.control.Button類的一個例項,來建立EnableFXButton應用程式。在修改後的應該程式中,Swing按鈕(Disable FX button和Enable FX button)用來禁用和啟用一個JavaFX按鈕(FX Button)。圖7-3展示了EnableFXButton程式。
按以下步驟來建立EnableFXButton應用程式:
1. 在File選單中選擇New Project。
2. 在JavaFX應用程式分類中,選擇JavaFX Application並點選Next。
3. 將工程命名為EnableFXButton。
4. 在Projects視窗中,右鍵點選enablefxbutton資料夾。選擇New然後選擇Java class。
5. 將新的類命名為ButtonHtml並點選Finish。
6. 複製ButtonHtml.java類的程式碼並貼上到這個工程中。
7. 將包宣告改為enablefxbutton。
8. 開啟磁碟中的enablefxbutton資料夾並建立images資料夾。
9. 右鍵點選圖片並選擇圖片另存為,下載down.gif和middle.gif圖片並儲存在images資料夾中。
10. 在EnableFXButton類中,宣告一個Button物件,如例7-9所示。
例7-9
public class EnableFXButton extends Application {
public static Button fxbutton;
11. 刪除start方法中NetBeans IDE自動生成的程式碼,並按例7-10所示實現start方法。
例7-10
@Override
public void start(Stage stage) {
final SwingNode swingNode = new SwingNode();
createSwingContent(swingNode);
BorderPane pane = new BorderPane();
fxbutton = new Button("FX button");
pane.setTop(swingNode);
pane.setCenter(fxbutton);
Scene scene = new Scene(pane, 300, 100);
stage.setScene(scene);
stage.setTitle("Enable JavaFX Button");
stage.show();
}
12. 如例7-11所示新增SwingNode類的引入宣告。
例7-11
import javafx.embed.swing.SwingNode;
13. 實現createSwingContent方法來設定SwingNode物件的內容,如例7-12所示。
例7-12
private void createSwingContent(final SwingNode swingNode) {
SwingUtilities.invokeLater(() -> {
swingNode.setContent(new ButtonHtml());
});
}
14. 按Ctrl(或Cmd)+Shift+I來新增swing.SwingUtilities類的引入宣告。
15. 用例7-13中所示的程式碼替換fxbutton的初始化程式碼,為JavaFX按鈕新增一個圖片並設定一個工具提示和樣式。
例7-13
Image fxButtonIcon = new Image(
getClass().getResourceAsStream("images/middle.gif"));
fxbutton = new Button("FX button", new ImageView(fxButtonIcon));
fxbutton.setTooltip(
new Tooltip("This middle button does nothing when you click it."));
fxbutton.setStyle("-fx-font: 22 arial; -fx-base: #cce6ff;");
16. 按Ctrl(或Cmd)+Shift+I來新增引入宣告,如例7-14所示。
例7-14
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.control.Tooltip;
17. 開啟ButtonHtml類並刪除中間按鈕b2的所有相關程式碼。
18. 如例7-15所示為b1((Disable FX button)和b3(Enable FX button)按鈕設定gif圖片。
例7-15
ImageIcon buttonIcon = createImageIcon("images/down.gif");
b1 = new JButton("<html><center><b><u>D</u>isable</b><br>"
+ "<font color=#ffffdd>FX button</font>",
buttonIcon);
b3 = new JButton("<html><center><b><u>E</u>nable</b><br>"
+ "<font color=#ffffdd>FX button</font>",
buttonIcon);
19. 修改actionPerformed方法來實現禁用和啟用fxbuttons,如例7-16所示。注意禁用和啟用JavaFX按鈕必須發生在JavaFX應用程式執行緒上。
例7-16
@Override
public void actionPerformed(ActionEvent e) {
if ("disable".equals(e.getActionCommand())) {
Platform.runLater(() -> {
EnableFXButton.fxbutton.setDisable(true);
});
b1.setEnabled(false);
b3.setEnabled(true);
} else {
Platform.runLater(() -> {
EnableFXButton.fxbutton.setDisable(false);
});
b1.setEnabled(true);
b3.setEnabled(false);
}
}
20. 按Ctrl(或Cmd)+Shift+I來新增引入宣告,如例7-17所示。
例7-17
import javafx.application.Platform;
21. 執行程式並點選Swing按鈕來禁用或者啟用JavaFX按鈕,如圖7-3所示。
使用JavaFX按鈕來操作Swinig按鈕
你可以繼續修改EnableFXButton程式並實現JavaFX按鈕的setOnAction方法,然後可以點選JavaFX按鈕來啟用Swing按鈕。修改後的程式(EnableButtons)如圖7-4所示。
圖7-4 EnableButtons樣例
建立EnableButtons應用程式:
1. 複製EnableFXButtons工程並命名為EnableButtons然後儲存。
2. 將EnableButtons類重新命名為EnableButtons,將enablefxbutton包重新命名為enablebuttons。
3. 修正ButtonHtml和EnableButtons類的包宣告。
4. 開啟EnableButtons類,新增一個FlowPane類的例項pane,如例7-18所示。
例7-18
FlowPane pane = new FlowPane();
5. 使用gif圖片來修改fxButtonIcon變數的初始化,如例7-19所示。
例7-19
Image fxButtonIcon = new Image(getClass().getResourceAsStream("images/left.gif"));
6. 如例7-20所示,改變fxbutton的文字,工具提示和字型,並設定disableProperty為true。
例7-20
fxbutton = new Button("Enable JButton", new ImageView(fxButtonIcon));
fxbutton.setTooltip(new Tooltip("Click this button to enable the Swing button."));
fxbutton.setStyle("-fx-font: 18 arial; -fx-base: #cce6ff;");
fxbutton.setDisable(true);
7. 如例7-21所示使用一個lambda表示式來實現setOnAction方法。注意必須在EDT執行緒上改變Swing物件。
例7-21
fxbutton.setOnAction(ActionEvent e) {
SwingUtilities.invokeLater(() -> {
ButtonHtml.b1.setEnabled(true);
});
fxbutton.setDisable(true);
}
});
注意:忽略啟用b1程式碼左邊的錯誤提示,你將在第11步修正錯誤。
8. 按Ctrl(或Cmd)+Shift+I來新增event.ActionEvent類的引入宣告。
9. 在佈局容器中新增swingNode和fxbutton物件,如例7-22所示。
例7-22
pane.getChildren().addAll(swingNode, fxbutton);
10. 將應用程式標題改為“Enable Buttons Sample”,如例7-23所示。
例7-23
pane.getChildren().addAll(swingNode, fxbutton);
11. 開啟ButtonHtml類,將b1按鈕的修飾改為public static。注意EnableButtons類的錯誤提示已經消失。
12. 刪除b3按鈕相關的所有程式碼,刪除設定b1行為指令的程式碼行。
13. 使用lambda表示式來修改actionPerformed方法,如例7-24所示。
例7-24
@Override
public void actionPerformed(ActionEvent e) {
Platform.runLater(() -> {
EnableButtons.fxbutton.setDisable(false);
});
b1.setEnabled(false);
}
結論
在本章中你學會了如何在JavaFX應用程式中嵌入已存在的Swing元件,並提供Swing和JavaFX物件之間的協作性。在JavaFX程式中嵌入Swing內容可以使開發者移植使用了複雜第三方Swing元件但沒有原始碼的Swing應用程式,或者包含只進行維護的遺留模組的應用程式。
應用程式資源
原始碼
NetBeans工程