JavaGUI---JavaFX---未完结

一、Java事件处理机制的应用

JavaFX:JavaFX是Java平台上的一个GUI工具包,它提供了一些内置的事件处理机制。

Swing:Swing是Java平台上的另一个GUI工具包,它也提供了一些内置的事件处理机制。

二、JavaFX和Swing的关键区别:

以下是JavaFX和Swing之间的一些关键区别:

  • JavaFX是比Swing更新的技术,旨在最终取代它。
  • JavaFX旨在比Swing更现代和视觉上更吸引人,支持动画、3D图形和其他高级功能。
  • JavaFX使用场景图模型进行渲染,而Swing使用更传统的基于小部件的方法。
  • JavaFX比Swing更好地支持CSS样式,使创建视觉上一致的UI更容易。
  • JavaFX比Swing更好地支持多媒体和Web内容。

三、 使用idea创建JavaFX应用

在这里插入图片描述
BootstrapFX:https://github.com/kordamp/bootstrapfx

提供特殊的CSS样式表用于美化JavaFX的GUI

ControlsFX:https://controlsfx.github.io/ 提供更多JavaFX中没有的组件

FormsFX:https://github.com/dlsc-software-consulting-gmbh/FormsFX/ 可以快速创建和设计表单

FXGL:https://github.com/AlmasB/FXGL?tab=readme-ov-file

Ikonli:https://kordamp.org/ikonli/

图标包

TilesFX:https://github.com/HanSolo/tilesfx?tab=readme-ov-file
游戏开发框架

ValidatorFX: https://github.com/effad/ValidatorFX

用于表单验证等

三、笔记

本笔记大部分根据此视频整理:https://www.bilibili.com/video/BV1Qf4y1F7Zv/?spm_id_from=333.337.search-card.all.click&vd_source=4085910f7c5c4dddcc04446ebf3aed6b

1. 基本机构

在这里插入图片描述

一个javaFX程序一般会有一个或多个窗口(Stage类的实例),
窗口可以设置一个场景(Scene类的实例),窗口可以切换不同的场景,但是一次只能设置一个,每个场景中可以添加一个或多个节点(node),每个node中也可以嵌套多个(node),node需有一个根节点

基本代码结构

Test就相当于程序的入口类,这个入口类必须继承Application,然后重写Application中的start方法,start方法中有个Stage 参数,这个就是表示的程序的窗口类,然后在重写的start方法中去实现一些场景,布局,节点等。

public class Test extends Application {public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage stage) throws Exception {//窗口stage.setTitle("我时窗口");//标签Label label = new Label("我是标签");//场景Scene scene = new Scene(label,300 , 300);stage.setScene(scene);stage.show();}
}

2. 涉及类介绍

Application

Application类是程序入口类继承之后,重写其中的start()方法即可,但如果你要在窗口的创建前后做一些其他事情,那可以重写其init()方法和stop()方法,因为Application的生命周期为init() ----->start() ----->stop()(窗口关闭时自动调用)。

在idea中使用alt+insert ,点击Override Method 重写 init() 和stop()

Stage

窗口
常用方法:

  • Title

  • icon 设置程序的
    在这里插入图片描述

    此icon图片在resources下的images目录,resources目录的属性为 Rsources Root
    在这里插入图片描述

stage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/images/img.png"))));
  • resiziable
    窗口大小是否可变,默认true可变,false 不可变

    stage.setResizable(false);
    
  • x,y,width,height
    窗口的宽高,一般不设置,都是设置场景的宽高

  • StageStyye
    窗口样式,比如不显示关闭和图片等外边样式。

    //默认样式,系统样式
    stage.initStyle(StageStyle.DECORATED);
    

    具体查看StageStyle中的其他枚举

  • Modality
    窗口的模态,也就是窗口之间的影响关系,比如子窗口打开之后不能点击父窗口这种功能。

    stage.initModality(Modality.NONE);
    

    具体查看Modality中的其他枚举

  • event
    事件

       //设置关闭窗口时,程序是否退出 默认为true 退出 false 不退出Platform.setImplicitExit(false);stage.setOnCloseRequest(event -> {System.out.println("关闭窗口");//取消默认关闭窗口事件event.consume();Alert alert = new Alert(Alert.AlertType.CONFIRMATION);alert.setTitle("退出程序");alert.setHeaderText(null);alert.setContentText("点击确定退出");alert.showAndWait().ifPresent(response -> {if (response == ButtonType.OK) {stage.close();Platform.exit();}});});

Scene

场景

  1. 场景切换

创建button --> 设置button位置—>把button放入锚点布局中—>创建场景,把锚点布局放入场景中 —>给button设置事件(因为是切换场景,所以给button设置事件要有第二个场景对象,所以此处给button设置事件写在最后,也就是第二个场景创建完成之后)

    public void start(Stage stage) throws Exception {//创建一个buttonButton button0 = new Button("切换场景");//设置button的位置button0.setLayoutX(150);button0.setLayoutY(150);//把button放入锚点布局 AnchorPane anchorPane = new AnchorPane(button0);//创建场景,把锚点布局放入场景Scene scene = new Scene(anchorPane, 300, 300);Button button1 = new Button("返回场景");button1.setLayoutX(150);button1.setLayoutY(150);//标签Label label = new Label("我是标签");label.setLayoutX(100);label.setLayoutY(100);AnchorPane anchorPane1 = new AnchorPane(button1, label);//场景2Scene scene2 = new Scene(anchorPane1, 300, 300);//给button0 添加事件button0.setOnAction(event -> {stage.setScene(scene2);});button1.setOnAction(event -> {stage.setScene(scene);});//窗口stage.setTitle("我时窗口");stage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/images/img.png"))));stage.setScene(scene);stage.show();}
  1. 鼠标箭头的样式
scene.setCursor(new ImageCursor(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/images/1xxx.png")))));
scene2.setCursor(new ImageCursor(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/images/2xxx.png")))));

Node

Node类是一个抽象类,所有控件都是的父类都是最终继承的Node抽象类,包括但不限于 按钮、复选框、颜色选择、日期选择、文字输入框、导航栏以及所有的可见控件。
常用方法
下面以Label标签为例来展示Node中的一些常用方法

        //标签Label label = new Label("我是标签");//设置标签的位置label.setLayoutX(100);label.setLayoutY(100);//设置标签的样式label.setStyle("-fx-font-size: 20px; -fx-border-color: blue; -fx-border-width: 3px");//设置标签的宽高label.setPrefWidth(200);label.setPrefHeight(50);//设置标签的对齐方式label.setAlignment(Pos.CENTER);//设置标签的可见性
//        label.setVisible(false);//设置标签的混合模式 比如两个图层交叉部分的混合样式,不常用
//        label.setBlendMode(BlendMode.ADD);//设置标签的透明度label.setOpacity(0.5);//设置标签的旋转角度label.setRotate(45);//设置标签的平移label.setTranslateX(20);label.setTranslateY(20);//设置3D的旋转角度label.setScaleX(2);label.setScaleY(2);label.setScaleY(2);//获取父节点Parent parent = label.getParent();//获取节点所在的场景Scene scene1 = label.getScene();//获取节点的idString id = label.getId();

Node属性的 单向绑定 和 监听器

Circle circle = new Circle();circle.setCenterX(50);circle.setCenterY(50);circle.setRadius(25);circle.setFill(Color.WHITE);circle.setStroke(Color.BLACK);//Node属性的 单向绑定 ,例如 当scene的宽高改变时,circle的宽高也会改变circle.centerXProperty().bind(scene2.widthProperty().divide(2));circle.centerYProperty().bind(scene2.heightProperty().divide(2));//Node属性的 监听器 ,监听属性的变化circle.centerXProperty().addListener((observable, oldValue, newValue) -> {System.out.println("X 轴位置改变了,原来是 "+oldValue+",现在是 "+newValue);});circle.centerYProperty().addListener((observable, oldValue, newValue) -> {System.out.println("Y 轴位置改变了,原来是 "+oldValue+",现在是 "+newValue);});

控件事件绑定

控件也就是继承node的那些控件,比如按钮,文本框,标签等,见上面Node介绍。
控件事件绑定就是给按钮绑定点击事件,键盘事件,鼠标事件,拖拽等。
其使用方法基本都是 控件.setOn事件(event) ,具体使用查看文档,事件非常多。

示例为给按钮绑定点击事件,给场景绑定键盘按下释放时的事件

        Button button3 = new Button("向上移动");//设置button的位置button3.setLayoutX(200);button3.setLayoutY(200);//button3按钮绑定事件 label 向上移动5px   ---- 主要方法button3.setOnAction(event -> {label.setLayoutY(label.getLayoutY()-5);});AnchorPane anchorPane1 = new AnchorPane(button1, label,circle,button3);//场景2Scene scene2 = new Scene(anchorPane1, 300, 300);//给场景2添加键盘事件 如果按键盘向下键击,label 向下移动5pxscene2.setOnKeyReleased(event -> {KeyCode code = event.getCode();if (code == KeyCode.DOWN){label.setLayoutY(label.getLayoutY()+5);}});

Color、Font、Image

color

        Color black = Color.BLACK;Color rgb = Color.rgb(255, 0, 0);Color hsb = Color.hsb(0, 0, 0);Color web = Color.web("#ff0000");

Font

      Font font1 = new Font("微软雅黑", 20);Font font = Font.font("微软雅黑", 20);// 字体,自重(bold是加粗),大小Font font2 = Font.font("仿宋", FontWeight.BOLD, 20);//使用资源文件种的字体 或者加载网络中的字体Font font3 = Font.loadFont(Objects.requireNonNull(Test.class.getResource("")).toExternalForm(), 20);

Image
可以使用本地或者网络中的图片

  ImageView imageView = new ImageView();Image image = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/images/img.png")));imageView.setImage(image);

3. FXML布局文件

在这里插入图片描述
想写什么控件,就用什么标签,标签里的属性与写类代码时的属性一直

4. SceneBuilder

首先下载SceneBuilder: https://openjfx.cn/scene-builder/
一路下一步安装,安装之后在idea中配置
在这里插入图片描述
配置完之后在idea中打开fxml使用SceneBuilder打开方式
在这里插入图片描述
在SceneBuilder中创建FXMl,拖拽创建控件,然后修改控件属性,绑定事件
在这里插入图片描述
出现控制器中的代码
在这里插入图片描述
file–>save 保存 FXML

5. Controller中的initialize方法

布局文件 和 此controller 设置的属性和事件都初始化完毕,则会自动调用 initialize
也就是说,在initialize 方法中,可以获取布局文件中的控件,并做相应的初始化,如果布局文件中控件已经设置了对应的属性或事件,则initialize方法中会覆盖。

示例:以下代码中initialize会覆盖moveLable方法。因为moveLable是bu在FXMl中绑定的setOnAction事件,但是initialize又给bu绑定了另一个setOnAction事件,又因为initialize是在控件所有属性和事件都初始化完毕之后才执行的,所以就覆盖掉了之前绑定的事件。

public class HelloController2 {@FXMLpublic Label la2;@FXMLpublic Button bu;@FXMLvoid moveLable() {System.out.println("点击");
//        la2.setLayoutY(la2.getLayoutY() - 10);}//布局文件 和 此controller 设置的属性和事件都初始化完毕,则会自动调用 initialize//也就是说, 在initialize 方法中,可以获取布局文件中的控件,并做相应的初始化,如果布局文件中控件已经设置了对应的属性或事件,则initialize方法中会覆盖public void initialize() {bu.setOnAction(event -> {System.out.println("xxxxxx");});}
}

6. 入口类Application中操作controller

比如,当需要图形根据scene 的大小的变化而变化时,也就是scene 的操作需要影响控件。
主要方法:fxmlLoader.getController()

public class HelloApplication extends Application {@Overridepublic void start(Stage stage) throws IOException {FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("demo.fxml"));Scene scene = new Scene(fxmlLoader.load(), 600, 400);//-----主要方法HelloController2 controller = fxmlLoader.getController();//circleBind 为controller中自己定义的方法controller.circleBind(scene);//---主要方法stage.setTitle("Hello!");stage.setScene(scene);stage.show();}public static void main(String[] args) {launch();}
}
public class HelloController2 {@FXMLprivate Circle uu;public void circleBind(Scene scene){//单向数据绑定uu.centerYProperty().bind(scene.heightProperty().divide(2));uu.centerXProperty().bind(scene.widthProperty().divide(2));}}

7. Platform.runLater()

javaFX程序中,为了避免其他线程污染ui界面,其不允许除主线程以外的其他线程去更改或刷新ui,也就是说,刷新界面只能通过main方法来实现,也就是继承Application那个类。

如果想在主线程刷新ui界面,可以使用Platform.runLater(),该方法给让主线程空闲时候允许Platform.runLater()队列里的内容。也就是说把对ui操作的代码放在Platform.runLater()中。

Platform.runLater() 不是开启多线程,因为其和主线程的线程名称都一样。
参考:https://blog.csdn.net/weixin_57792864/article/details/127025819

很多控件的事件方法其实内部都是使用了Platform.runLater()

错误示例:

Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
public class Test2 extends Application {@Overridepublic void start(Stage stage) throws Exception {Button button = new Button("获取姓名");button.setLayoutX(200);button.setLayoutY(200);Label label = new Label("我的姓名是");label.setLayoutX(200);label.setLayoutY(100);//错误代码  ----------------------------button.setOnAction(event -> {new Thread(() -> {label.setText("我的姓名是 - 王二小");}).start();});AnchorPane anchorPane  = new AnchorPane(button,label);Scene scene = new Scene(anchorPane,400,400);stage.setScene(scene);stage.show();}public static void main(String[] args) {launch(args);}
}

正确示例:

public class Test2 extends Application {@Overridepublic void start(Stage stage) throws Exception {Button button = new Button("获取姓名");button.setLayoutX(200);button.setLayoutY(200);Label label = new Label("我的姓名是");label.setLayoutX(200);label.setLayoutY(100);//主要代码 -----------------------------------button.setOnAction(event -> {Platform.runLater(() -> {label.setText("我的姓名是 - 王二小");});});AnchorPane anchorPane  = new AnchorPane(button,label);Scene scene = new Scene(anchorPane,400,400);stage.setScene(scene);stage.show();}public static void main(String[] args) {launch(args);}
}

8. Canvas 画布

https://www.bilibili.com/video/BV1Qf4y1F7Zv?p=14

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/13356.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20232906 2023-2024-2 《网络与系统攻防技术》第十次作业

20232906 2023-2024-2 《网络与系统攻防技术》第十次作业 1.实验内容 一、SEED SQL注入攻击与防御实验 我们已经创建了一个Web应用程序,并将其托管在http://www.seedlabsqlinjection.com/(仅在SEED Ubuntu中可访问)。该Web应用程序是一个简…

算法day08

第一题 1. 两数之和 由上述题意所知,本题要采用二分法的解题思路,二分法主要是面向有序的数组且也满足二段性的数组,所谓二段性就是在一定的规则下能把该数组分成两个部分; 本题注意要点: 1、循环结束的条件&#xff…

【Leetcode每日一题】 综合练习 - 括号生成(难度⭐⭐)(76)

1. 题目解析 题目链接:22. 括号生成 这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了。 2.算法原理 问题描述 我们需要找出所有可能的、有效的括号序列。一个有效的括号序列指的是一个仅由(和)组成的字符串,…

ssm132医院住院综合服务管理系统设计与开发+vue

医院住院综合服务管理系统的设计与实现 摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对医院住院信息管理混乱&…

【高阶数据结构(四)】图的最短路径问题

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:高阶数据结构专栏⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多数据结构   🔝🔝 高阶数据结构 1. 前言2. 单源最短…

第八篇 Asciidoc 输出 All In One HTML 解决图片无法显示问题

问题:我的图片显示不出来了 小明使用 Asciidoc 来记笔记,他将笔记输出为 HTML 文件。小丽向小明借笔记。小明将 Asciidoc 笔记输出为 HTML文件,并拷贝给了小丽。 但是,小丽发现,图片都显示不出来了。 小丽:小明,你给我的笔记,图片都显示不出来啊。 小明:是我给你的…

析构函数详解

目录 析构函数概念特性对象的销毁顺序 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 🐒🐒🐒 个人主页 🥸🥸🥸 C语言 🐿️🐿️🐿️ C语言例题 &…

yolov8实战之 .pt 转. tensorRT

1 yolo 训练 1.1修改自己的数据集合 我是有3个类别,差不多这么些数据 1.2 训练 from ultralytics import YOLO # Load a model model YOLO("yolov8m.yaml") # build a new model from scratch #model YOLO(E:/pythonCode/pythonProject1/runs/detec…

风电功率预测 | 基于PSO-BP神经网络实现风电功率预测(附matlab完整源码)

风电功率预测 风电功率预测完整代码风电功率预测 基于粒子群优化算法(Particle Swarm Optimization, PSO)的BP神经网络是一种常见的方法,用于实现风电功率预测。下面是一个基于PSO-BP神经网络实现风电功率预测的一般步骤: 数据准备:收集与风电场发电功率相关的数据,包括…

农林科学SCI期刊,IF=6+,影响力高,对国人非常友好!

一、期刊名称 Crop Journal 二、期刊简介概况 期刊类型:SCI 学科领域:农林科学 影响因子:6.6 中科院分区:1区 出版方式:开放出版 版面费:$900 三、期刊征稿范围 《作物杂志》是一份双月刊、国际、同…

PHP使用Browsershot进行网页截图

Browsershot是什么 Spatie Browsershot 是一个开源PHP库,它允许开发者在PHP应用程序中生成网页的截图。 这个库特别适用于Laravel框架,但也可以在其他 PHP 应用程序中使用。 主要特点 无头浏览器截图:使用无头版本的 Chrome 或 Chromium 浏…

10W 3KVAC隔离 宽电压输入 AC/DC 电源模块 ——TP10AF系列

TP10AF系列输出功率为10W,具有可靠性高、更小的体积、性价比高等特点,广泛用于工控和电力仪器、仪表、智能家居等相关行业。

SMB攻击利用之-mimikatz上传/下载流量数据包逆向分析

SMB协议作为windows环境下最为常见的一种协议,在历史上出现过无数的通过SMB协议进行网络攻击利用的案例,包括针对SMB协议本身以及通过SMB协议实施网络攻击。 本文将介绍一种通过SMB协议的常见利用方式,即向远程主机传输mimikatz,作为我的专栏《SMB攻击流量数据包分析》中的…

前端学习第一课

AJAX 事先说明,这只是记录,并不是从零到一的教学内容,如果想要学习的话,可以跳过本文章了 ok,转回正题,正如上面所说,这只是记录。其实我是有一定的前端基础的,也做过涉及相关的开发…

【工具】macOS、window11访问limux共享目录\共享磁盘,samba服务安装使用

一、samba服务安装 Samba是一个免费的开源软件实现,使得非Windows操作系统能够与Windows系统进行文件和打印服务共享。它实现了SMB/CIFS协议,并且能够在Linux、Unix、BSD等多种系统上运行。 安装 samba: sudo yum install samba配置 samba…

【介绍下Python多线程,什么是Python多线程】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…

【气象常用】时间序列的线性拟合

效果图: 主要步骤: 1. 数据准备:下载Hadley Centre observations datasets的HadSST数据 可参考【气象常用】时间序列图-CSDN博客 2. 数据处理:计算线性拟合 3. 图像绘制:绘制折线及拟合线,并添加文本 …

其他自动化工程师都在偷偷学习AI技术,你再不学就落后了!一篇文章教会你使用AI!

其他自动化工程师都在偷偷学习AI技术,你再不学就落后了!一篇文章教会你使用AI! 哈喽,大家好,我是小叔。了解小叔的朋友都清楚,我从来都不是标题党,我只会用美女图片来吸引你们😂&am…

python 六句话让电脑告诉你,刚才插入的串口编号

六句话让电脑告诉你,我的串口号 第一步,安装python 编译器以及pyserial 模块第二步,写入代码 import serial.tools.list_ports usart_list list(serial.tools.list_ports.comports()) input("Please insert your serial port:")…