文档



JavaFX:互操作性

7 在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引入了位于javafx.embed.swing包中的SwingNode类。该类使您能够在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("点击我!"));
        });
    }
}

运行此代码将产生图7-1中显示的输出。

图7-1 在JavaFX应用程序中嵌入的Swing JButton

图7-1的描述
图7-1 在JavaFX应用程序中嵌入的Swing JButton的描述

嵌入Swing内容和处理事件

Swing教程中的ButtonHtmlDemo示例中,为示例7-2示例7-3中显示的三个按钮添加了字体、颜色和其他格式。这些按钮响应鼠标和键盘事件,如示例7-5示例7-6所示。在ButtonHtmlDemo中使用Swing创建的这三个按钮现在嵌入到了一个JavaFX应用程序(SwingNodeSample)中,图7-2展示了这个应用程序。您将创建SwingNodeSample应用程序,并确保所有事件都传递给适当的Swing按钮并进行处理。

图7-2 ButtonHtmlDemo嵌入到JavaFX应用程序中

图7-2的描述
"图7-2 ButtonHtmlDemo嵌入到JavaFX应用程序中"的描述

左右两个按钮使用HTML格式实现了多行文本,如示例7-2所示。

示例7-2

b1 = new JButton("<html><center><b><u>禁用</u></b><br>"
                 + "<font color=#ffffdd>中间按钮</font>",
                 leftButtonIcon);

b3 = new JButton("<html><center><b><u>启用</u></b><br>"
                 + "<font color=#ffffdd>中间按钮</font>",
                 rightButtonIcon);

中间按钮的简单格式不需要HTML,因此它使用字符串标签和图像进行初始化,如示例7-3所示。

示例7-3

b2 = new JButton("中间按钮", middleButtonIcon);

这三个按钮都有工具提示和助记符,如示例7-4所示。

示例7-4

b1.setToolTipText("单击此按钮以禁用中间按钮。");
b2.setToolTipText("单击此中间按钮时不会发生任何操作。");
b3.setToolTipText("单击此按钮以启用中间按钮。");

b1.setMnemonic(KeyEvent.VK_D);
b2.setMnemonic(KeyEvent.VK_M);
b3.setMnemonic(KeyEvent.VK_E);

左右按钮分别用于禁用和启用中间按钮。为了使应用程序能够检测和响应用户对这些按钮的操作,需要附加动作监听器并设置动作命令,如示例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. 文件菜单中选择新建项目

  2. JavaFX应用程序类别中选择JavaFX应用程序,然后点击下一步

  3. 将项目命名为SwingNodeSample,并选择基于JDK 8的JavaFX平台。点击完成

  4. 项目窗口中,右键单击Source Packages下的swingnodesample文件夹。选择新建,然后选择Java类

  5. 将新类命名为ButtonHtml,然后点击完成

  6. 复制ButtonHtmlDemo.java类的代码,并粘贴到项目中。

  7. 在磁盘上打开swingnodesample文件夹,并创建images文件夹。

  8. 通过右键单击图像并选择另存为,下载图像left.gifmiddle.gifright.gif,并将它们保存在images文件夹中。

  9. SwingNodeSample类中,删除NetBeans自动生成的start方法中的代码。

  10. 相反,创建一个SwingNode对象,并按照示例7-7中所示实现start方法。

    示例7-7

    @Override
    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嵌入到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应用程序的源代码,请点击SwingNodeSample.zip链接。

运行SwingNodeSample项目,并确保所有按钮提供的交互方式都正常工作:

  • 用鼠标悬停在按钮上,查看工具提示。

  • 点击左右按钮分别禁用和启用中间按钮。

  • 按下Alt + D和Alt + E键分别禁用和启用中间按钮。

在Swing和JavaFX组件之间添加互操作性

您可以在JavaFX按钮和Swing按钮之间提供互操作性。例如,EnableFXButton 应用程序(如图7-3所示)允许用户单击Swing按钮以禁用或启用JavaFX按钮。相反,EnableButtons 应用程序(如图7-4所示)允许用户单击JavaFX按钮以激活Swing按钮。

图7-3 启用JavaFX按钮示例

图7-3的描述
"图7-3 启用JavaFX按钮示例"的描述

使用Swing按钮操作JavaFX按钮

通过修改SwingNodeSample应用程序并将中间按钮设置为javafx.scene.control.Button类的实例,创建了EnableFXButton应用程序。在修改后的应用程序中,使用Swing按钮(禁用FX按钮)和(启用FX按钮)来禁用和启用JavaFX按钮(FX按钮)。图7-3显示了EnableFXButton应用程序。

按照以下步骤创建EnableFXButton应用程序:

  1. 文件菜单中选择新建项目

  2. JavaFX应用程序类别中选择JavaFX应用程序,然后点击下一步

  3. 将项目命名为EnableFXButton

  4. 项目窗口中,右键单击Source Packages下的enablefxbutton文件夹。选择新建,然后选择Java类

  5. 将新类命名为ButtonHtml,然后点击完成

  6. 复制ButtonHtmlDemo.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. 删除NetBeans IDE自动生成的start方法内的代码,并按照示例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按钮");
        
        pane.setTop(swingNode);
        pane.setCenter(fxbutton);
    
        Scene scene = new Scene(pane, 300, 100);
        stage.setScene(scene);
        stage.setTitle("启用JavaFX按钮");
        stage.show();
    }
    
  12. 添加SwingNode类的导入语句,如示例7-11所示。

    示例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,添加一个导入语句到javax.swing.SwingUtilities类。

  15. fxbutton的初始化替换为示例7-13中所示的代码,以添加图像并为JavaFX按钮设置提示和样式。

    示例7-13

    Image fxButtonIcon = new Image(
    getClass().getResourceAsStream("images/middle.gif"));
    
    fxbutton = new Button("FX按钮", new ImageView(fxButtonIcon));
    fxbutton.setTooltip(
    new Tooltip("当您点击它时,这个中间按钮不会执行任何操作。"));
    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. 使用down.gif图像作为b1(禁用FX按钮)和b3(启用FX按钮)按钮的图像,如示例7-15所示。

    示例7-15

    ImageIcon buttonIcon = createImageIcon("images/down.gif");
    b1 = new JButton("<html><center><b><u>禁用</u></b><br>"
                             + "<font color=#ffffdd>FX按钮</font>", 
                             buttonIcon);
    b3 = new JButton("<html><center><b><u>启用</u></b><br>"
                             + "<font color=#ffffdd>FX按钮</font>", 
                             buttonIcon);
    
  19. 修改actionPerformed方法,实现禁用和启用fxbutton,如示例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按钮操作Swing按钮

您可以进一步修改EnableFXButton应用程序,并为JavaFX按钮实现setOnAction方法,以便单击JavaFX按钮激活Swing按钮。修改后的应用程序(EnableButtons)如图7-4所示。

图7-4 启用按钮示例

图7-4的描述
"图7-4 启用按钮示例"的描述

创建EnableButtons应用程序的步骤如下:

  1. 复制EnableFXButton项目,并将其保存为EnableButtons名称。

  2. 将EnableFXButton类重命名为EnableButtons,将enablefxbutton包重命名为enablebuttons。

  3. 在ButtonHtml和EnableButtons类中修正包语句。

  4. 打开EnableButtons类,并将pane实例化为FlowPane类,如示例7-18所示。

    示例7-18

    FlowPane pane = new FlowPane();
    
  5. 将fxButtonIcon变量的初始化修改为使用left.gif图像,如示例7-19所示。

    示例7-19

    Image fxButtonIcon = new Image(
    getClass().getResourceAsStream("images/left.gif"));
    
  6. 更改fxbutton的文本、工具提示和字体大小,并将disableProperty设置为true,如示例7-20所示。

    示例7-20

    fxbutton = new Button("启用JButton", new ImageView(fxButtonIcon));
    fxbutton.setTooltip(
    new Tooltip("单击此按钮以启用Swing按钮。"));
    fxbutton.setStyle("-fx-font: 18 arial; -fx-base: #cce6ff;");
    fxbutton.setDisable(true);
    
  7. 使用lambda表达式实现setOnAction方法,如示例7-21所示。注意,只能在事件分派线程上更改Swing对象。

    示例7-21

    fxbutton.setOnAction(ActionEvent e) {
        SwingUtilities.invokeLater(() -> {
            ButtonHtml.b1.setEnabled(true);
        });
        fxbutton.setDisable(true);
        }
    });
    

    注意:

    忽略出现在启用b1行左侧的错误标记。您将在第11步中纠正此错误。

  8. 按下Ctrl(或Cmd)+ Shift + I,将import语句添加到javafx.event.ActionEvent类中。

  9. swingNodefxbutton对象添加到布局容器中,如示例7-22所示。

    示例7-22

    pane.getChildren().addAll(swingNode, fxbutton);
    
  10. 将应用程序标题更改为"启用按钮示例",如示例7-23所示。

    示例7-23

    stage.setTitle("启用按钮示例");
    
  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对象之间提供互操作性。将Swing内容嵌入到JavaFX应用程序中的能力使开发人员能够迁移使用复杂的第三方Swing组件的Swing应用程序,这些组件没有源代码,或者存在仅处于维护模式的遗留模块的应用程序。

关闭窗口

目录

JavaFX: 互操作性

展开 折叠