JavaFX 8 下简化自定义控件的外部调用以及流式布局示例

栏目: Java · 发布时间: 7年前

内容简介:JavaFX 8 下简化自定义控件的外部调用以及流式布局示例

「博客搬家」原地址:简书 原发表时间: 2017-05-21

有一个项目,需要模拟数千台设备的工作情况,这数千个设备分为若干组,每组 100 台。故需要设计一款 GUI 程序,包含 100 个自定义控件,模拟一组设备的工作情况,通过 ListView 对设备组进行选择,即可成功模拟数千台设备。

由于 Java 拥有丰富的第三方库,便于项目的底层实现,故基于最新的 Java GUI 框架「JavaFX 8」实现该 GUI 界面,该应用程序需使用 100 个相同的自定义控件,故需要使用流面板 (FlowPane) 对这些自定义控件进行有效布局。

最终实现效果如下图所示:

JavaFX 8 下简化自定义控件的外部调用以及流式布局示例

FlowPane 布局面板中包含的自定义控件会在水平方向上按行连续地平铺放置,并且会在边界处自动换行,点击左侧 ListView 中的 Item,右侧的自定义控件组会显示选定设备组的状态信息。综上,该设计可实现预定目标。

1. Java FX 8 基本说明

可以使用这篇「JavaFX 8 教程」作为 JavaFX 8 的入门使用,拥有 GUI 设计经验的开发人员均可快速入门 Java FX 8,

1.1 界面生成方式

Java FX 8 与大多数现代 GUI 开发相同,用户界面有两种创建方式:

  • XML文件定义
  • java代码创建

本文为了更加清晰直观,采用两种界面布局方法相结合的方式。

1.2 问题说明

由于 Java FX 8 并不主流,遇到问题很难在中文网站上找到解决方法,故有许多坑需要填补,所以本文遇到一些坑时不进行说明,而是在另一篇文章中列出了这些坑的填补方法。

2. 界面根布局的设计

使用「Scene Builder」打开 FXML 布局文件,在如图所示左下角,填入一个自定义 Class 作为控制器类,激活需要操作的控件,在右侧「fx:id」处填入 Class 的 Field,下方填入事件处理方法,之后通过 View -> Show Sample Controller skeleton 可查看填入 Controller 中的代码示例。

JavaFX 8 下简化自定义控件的外部调用以及流式布局示例

在程序的入口类中填入如下代码:

public class Main extends Application {

    //入口方法已隐式实现,故可删除
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        primaryStage.setTitle("bitkyApp");
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sample.fxml"));
        AnchorPane anchorPane = fxmlLoader.load();           //返回类型设置为布局文件根节点类型
        Controller controller = fxmlLoader.getController();  //可获取该布局的 Controller 类

        BorderPane rootLayout = FXMLLoader.load(getClass().getResource("rootLayout.fxml"));
        rootLayout.setCenter(anchorPane);
        primaryStage.setScene(new Scene(rootLayout, 800, 650));
        primaryStage.show();
    }
}

该方法为教程中的方法,为了实现 Controller 和外部的交互,将 FXML 布局文件和 Controller 均耦合在了外部类中,显得较为繁琐。故可采用自定义控件的方式简化外部的代码调用。

3. 自定义控件的设计

JavaFX 2 版本之后,FXML 提供 fx:root/ 写法,此时要求 Controller 必须继承自 FXML 节点对象,使用 FXMLLoader 加载时,必须调用 setRoot() 方法。

不要在 FXML 中指定 Controller,通常情况下一个 FXML 可以对应多个 Controller,为了灵活性,我们应当在 FXMLLoader 中指定 Controller。

根据具体实践,可以采用如下方式:

Scene Builder 左下角的 Controller 面板中,勾选使用 fx:root 构造,并且不应该填入 Controller 类,如图,此时 fx:root/ 作为根节点,:

JavaFX 8 下简化自定义控件的外部调用以及流式布局示例

此时在 FXML 文件中的代码例如:

<fx:root xmlns:fx="http://javafx.com/fxml/1"
         type="TabPane"
         xmlns="http://javafx.com/javafx/8.0.111">
    
......

</fx:root>

此时,Controller 类继承根节点的类型,例如「TabPane」。可选实现「Initializable」接口进行控件生成之后的初始化操作,代码示例如下:

//Controller 类继承 FXML 布局文件的根节点类型「TabPane」
public class DeviceView extends TabPane implements Initializable {

    public DeviceView() {
        loadFxml();
    }

    private void loadFxml() {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("device_view.fxml"));
        loader.setRoot(this);
        loader.setController(this);
        try {
            loader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //该方法在构造方法执行完毕后执行
    @Override
    public void initialize(URL location, ResourceBundle resources) {
    }
}

此时,在主布局对应的 Controller 中,直接生成该类「DeviceView」的对象作为自定义控件,通过 FlowPane 控件的引用添加该对象为 FlowPane 的子控件,即可实现设计目的,具体代码如下:

for (int i = 1; i <= 100; i++) {

    //在 FlowPane 中添加自定义控件「DeviceView」
    DeviceView deviceView = new DeviceView(i);
    deviceFlowPane.getChildren().add(deviceView);
	
	//使用观察者模式添加子控件「DeviceView」的监听器
    deviceView.setListener((status -> {
        if (listener != null) listener.btnChanged(status);
    }));
}

4. 使用自定义控件的方式简化主界面的外部调用代码

综上所述,最终实现的主界面代码示例如下:

public class MainView extends BorderPane implements Initializable {

    private static MainView mainView;

    private MainView() throws IOException {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("rootLayout.fxml"));
        loader.setRoot(this);
        loader.setController(this);
        loader.load();
    }

    public static MainView getInstance() {
        if (mainView == null) {
            try {
                mainView = new MainView();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return mainView;
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
    }
}

此段代码使用了自定义控件的方式,并且使用了单例模式中的懒汉式方便外部调用,外部调用代码如下:

public class MainLauncher extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
           startApp(primaryStage);
    }

    private void startApp(Stage primaryStage) {
        primaryStage.setTitle("设备模拟客户端");
        primaryStage.setScene(new Scene(MainView.getInstance()));
        primaryStage.setMaximized(true);
        primaryStage.show();
    }
}

5. 参考资料

  1. 使用内置的布局面板
  2. JavaFX 8 教程「中文」
  3. JavaFX 8 API Document
  4. Gluon Scene Builder
  5. JavaFX 创建自定义控件

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Software Engineering for Internet Applications

Software Engineering for Internet Applications

Eve Andersson、Philip Greenspun、Andrew Grumet / The MIT Press / 2006-03-06 / USD 35.00

After completing this self-contained course on server-based Internet applications software, students who start with only the knowledge of how to write and debug a computer program will have learned ho......一起来看看 《Software Engineering for Internet Applications》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具