在JavaFX程式中嵌入Swing內容

茅坤寶駿氹發表於2018-10-18

轉載自  在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 ButtonHtmlDemo嵌入在JavaFX應用程式中

左按鈕和右按鈕有多行用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.gifmiddle.gifright.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.gifmiddle.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應用程式,或者包含只進行維護的遺留模組的應用程式。

應用程式資源

原始碼

● SwingNodeSample.java

● ButtonHtml.java

● EnableButtons.java

● EnableFXButton.java

NetBeans工程

● EnableButtons.zip

● EnableFXButton.zip

● SwingNodeSample.zip

相關文章