资讯专栏INFORMATION COLUMN

JavaFX 学习笔记——窗口与控件

Pocher / 1294人阅读

摘要:创建窗口添加类为元素间空隙与主窗口创建过程相同,新建布局及控件,最后使用的方法显示出来。设置主窗口中的按钮事件,点击按钮后会显示一个窗口。这时我们可以通过函数设置窗口关闭时触发的事件在关闭窗口时,首先执行这一事件处理函数,再将窗口关闭。

前言

如今比较流行的桌面gui框架有WPF、WinForm、Qt、javafx等。其中WPF和WinForm目前还只能在运行Winsows上。Qt(widget)是一个很强大的跨平台C++框架(不只是UI),但用C++写界面实在有点蛋疼,且编译出来的体积很大。

JavaFX是基于JAVA的开源桌面框架,笔者曾学习过Qt,打算尝试使用Java写桌面应用,现在网上关于JavaFX的教程不时很多,因此在这里记录一下学习过程。

安装和配置

JavaFX11的环境不包括在JDK中,因此要在配置好JDK11的基础上多带带配置,具体方法可以参考JavaFX官网。

窗口构成

新建工程,在Main.java中输入下列代码:

public class Main extends Application {

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

        VBox layout = new VBox();
        Label label = new Label("Hello world");
        layout.getChildren().add(label);

        Scene scene = new Scene(layout, 300, 300);

        primaryStage.setTitle("Hello World");
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

JavaFX中的Stage可以看作是窗口,Scene是窗口中的内容,调用StagesetScene函数来设置窗口内容,窗口可以在运行时切换显示的Scene,实现Tab页面的效果。

VBox是JavaFX中的一种布局,其中的元素纵向排列,向VBox中添加元素需要调用vbox.getChildren().add(control),如上所示。

构造Scene时传入顶层的布局(类似Qt中QMainWindowCentralWidget)及大小。最后调用show函数将窗口显示出来。

按钮控件

控件(Control)是GUI框架中最重要的部分,也是用户与程序进行交互的媒介。

在JavaFX中使用控件需要导入包,例如

import javafx.scene.control.Label;
import javafx.scene.control.*;

框架中不同控件的使用方法大同小异,这里用最常用的按钮作为示例。

在窗口中添加按钮

构造一个Button对象并添加到VBox中:

Button button = new Button("Click me");
VBox layout = new VBox();
layout.getChildren().add(button);

Scene scene = new Scene(layout, 300, 300);
primaryStage.setScene(scene);
处理按钮点击事件 使用EventHandler接口

创建Handler类实现EventHandler接口

class Handler implements EventHandler {

    @Override
    public void handle(ActionEvent actionEvent) {
        if(actionEvent.getSource() instanceof Button)
            ((Button) actionEvent.getSource()).setText("Click me again");
    }
}

为按钮注册点击方法

button.setOnAction(new Handler());

Button还有setOnMouseClicked,setOnTouchPressed等方法,这些是专门为处理鼠标事件及触摸事件,setOnAction函数用来处理按钮触发事件(不管按钮被哪种方式触发,具体参考文档)。

由代码可以得出,setOnAction函数接收一个EventHandler接口,接口的handle方法用来处理事件。

使用匿名内部类

与上一方法同理,我们可以使用匿名内部类创建接口

button.setOnAction(new EventHandler() {
    @Override
    public void handle(ActionEvent actionEvent) {
        if(actionEvent.getSource() instanceof Button)
            ((Button) actionEvent.getSource()).setText("Click me again");
    }
});
使用Lambda表达式

Java中的一些接口可以由lambda表达式代替,因此可以在setOnAction中传入lambda表达式:

button.setOnAction(actionEvent -> {
    if(actionEvent.getSource() instanceof Button){
        ((Button) actionEvent.getSource()).setText("Click me again");
    }
});

这样就可以在实现简单的事件处理器时不必再特意实现接口。

其他控件

使用其他控件的方法也都类似按钮,使用时可以查询文档,或者根据IDE的代码提示获知函数签名及使用方法。

多窗口

在一个桌面程序中往往有多个窗口,下面介绍添加窗口的方法。

创建窗口

添加MsgBox

public class MsgBox {
    public static void show(String title) {
        Stage window = new Stage();
        window.setTitle(title);


        Button trueButton = new Button("True");
        Button falseButton = new Button("False");

        HBox hBox = new HBox(10);    //10为元素间空隙
        hBox.getChildren().addAll(trueButton, falseButton);
        Scene scene = new Scene(hBox, 100, 100);
        window.setScene(scene);
        window.show();
    }
}

与主窗口创建过程相同,新建stageScene、布局及控件,最后使用Stageshow方法显示出来。

调用MsgBox类的show方法即可显示窗口,函数的参数为窗口的标题。

设置主窗口中的按钮事件,点击按钮后会显示一个MsgBox窗口。

button.setOnAction(actionEvent -> MsgBox.show("SubWindow"));
窗口模态

Stage对象可以使用initModality方法设置窗口模态类型

window.initModality(Modality.WINDOW_MODAL);

类型包括 Modality.NONE, Modality.WINDOW_MODAL, Modality.APPLICATION_MODAL

Modality.NONE: 不阻塞任何窗口

Modality.WINDOW_MODAL: 窗口级别的模态,仅仅阻塞与对话框关联的窗口,用户可以正常访问其他窗口,适合用于多窗口的程序。

Modality.APPLICATION_MODAL(默认值): 应用程序级别的模态,窗口将阻塞整个程序,无法访问程序中其他的窗口

返回子窗口的值

有时我们需要得到用户在子窗口中的操作,例如在本文的例子中,获知用户点了哪一个按钮。

接下来实现这样的功能——点击True按钮就在控制台打印true,否则打印"false"。

更改MsgBox中的代码

public static boolean show(String title) {
    Stage window = new Stage();
    window.setTitle(title);

    Button trueButton = new Button("True");
    Button falseButton = new Button("False");

    trueButton.setOnAction(actionEvent -> {
        answer = true;
        window.close();
    });

    falseButton.setOnAction(actionEvent -> {
        answer = false;
        window.close();
    });

    HBox hBox = new HBox(10);
    hBox.getChildren().addAll(trueButton, falseButton);
    Scene scene = new Scene(hBox, 100, 100);
    window.setScene(scene);
    window.showAndWait();

    return answer;
}

show函数返回一个boolean类型的值,这个值是由点击的按钮决定的,按钮点击后会关闭窗口,返回布尔值。

设置主窗口中按钮点击事件

button.setOnAction(actionEvent ->
{
        var result = MsgBox.show("SubWindow");
        System.out.println(result);
});
showAndWait函数

这个函数会阻塞当前事件,直到窗口被关闭后才会返回,并执行接下类的语句。在上例中,我们显示窗口并等待,直到点击按钮使窗口被关闭,才执行后面的return answer语句。

可以尝试改为调用show方法,观察返回的结果。

窗口的关闭

有时在用户关闭窗口时,需要执行一定的操作,例如保存设置、确认是否退出等。

这时我们可以通过setOnCloseRequest函数设置窗口关闭时触发的事件

window.setOnCloseRequest(windowEvent ->
{
    System.out.println("The window will be closed!");
});

JavaFX在关闭窗口时,首先执行这一事件处理函数,再将窗口关闭。但在某些情况下(例如确认是否关闭),我们需要在处理事件时取消窗口的关闭,这种情况下可以调用windowEventconsume方法,告诉事件系统,此事件已经被处理完毕,不必再执行其他处理动作(如关闭窗口)。

将主窗口的代码改为:

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

    Button button = new Button("Click me");
    button.setOnAction(actionEvent ->
    {
        var result = MsgBox.show("SubWindow");
        System.out.println(result);
    });
    VBox layout = new VBox();
    layout.getChildren().add(button);

    Scene scene = new Scene(layout, 300, 300);
    primaryStage.setScene(scene);

    primaryStage.setTitle("Hello World");
    primaryStage.setOnCloseRequest(windowEvent -> {
        var result = MsgBox.show("Do you want to CLOSE?");
        if (result == false) {
            windowEvent.consume();
        }
    });
    primaryStage.show();
}

当用户点击关闭按钮时,将会弹窗询问是否关闭,若用户点击False按钮窗口就不会被关闭。

链接

推荐一个很好的JavaFX教程视频:https://youtu.be/FLkOX4Eez6o

一个适合初学者的Qt教程:https://www.devbean.net/2012/...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77425.html

相关文章

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

    摘要:故可采用自定义控件的方式简化外部的代码调用。自定义控件的设计版本之后,提供写法,此时要求必须继承自节点对象,使用加载时,必须调用方法。 「博客搬家」 原地址: 简书 原发表时间: 2017-05-21 有一个项目,需要模拟数千台设备的工作情况,这数千个设备分为若干组,每组 100 台。故需要设计一款 GUI 程序,包含 100 个自定义控件,模拟一组设备的工作情况,通过 List...

    MartinHan 评论0 收藏0
  • 「译」Maven 集成 JavaFX 8 以及 <fx:root> 问题探讨

    摘要:本文探讨使用构建集成的可执行程序的方法,以及根节点问题。而使用后,可指导类作为根节点,避免了嵌套的情况。文件设计如下文件同时指明了根节点的类型,资源文件对应的设计如下此时可实现开始时,纯代码方式的自定义控件设计。 「博客搬家」 原地址: 简书 原发表时间: 2017-05-22 上一篇文章探讨了使用 IntelliJ IDEA 创建 JavaFX 工程,进而开发了所需应用程序。更...

    joywek 评论0 收藏0
  • JavaFx中Controller获取Stage并自定义窗口移动缩放逻辑

    摘要:中获取并自定义窗口移动与缩放逻辑由于去掉了平台自带了标题栏,窗口就无法移动和缩放了,需要我们自己来实现。 JavaFx中Controller获取Stage并自定义窗口移动与缩放逻辑 由于去掉了平台自带了标题栏,窗口就无法移动和缩放了,需要我们自己来实现。 去除窗口标题栏 public class Main extends Application { @Override ...

    Alliot 评论0 收藏0
  • Java™ 教程(匿名类)

    匿名类 匿名类可以使你代码更简洁,它们使你能够同时声明和实例化一个类,它们就像局部类,除了它们没有名称,如果你只需要使用局部类一次,请使用它们。 声明匿名类 虽然局部类是类声明,但匿名类是表达式,这意味着你在另一个表达式中定义该类,以下示例HelloWorldAnonymousClasses在局部变量frenchGreeting和spanishGreeting的初始化语句中使用匿名类,但使用局部类...

    xietao3 评论0 收藏0
  • Java9模块化学习笔记一之快速入门

    摘要:如果你想查看运行时模块的加载过程输出结果表示为模块,由于我限制了不再往下输出了,而我们模块又没有别的额外依赖,所以仅有这行输出。 jdk9模块快速入门 列出自带模块:java --list-modulesmac多版本jdk共存:http://adolphor.com/blog/2016...模块规则示意图:showImg(https://segmentfault.com/img/bVb...

    cjie 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<