如何基于JavaFX开发桌面程序

作者:这样正好 时间:2023-10-30 11:06:19 

基于JavaFX开发桌面程序

注:我也是JAVA FX的初学者之一,自己在学习的时候踩了许多的坑,中文英文的资料查了不少,但是觉得FX技术和其他热门技术相比,教程还是太少了。这里就尽量做一点微小的贡献吧

使用环境

注:写这个只是为了说明我的环境,使用和我的不一样的环境在理解这篇教程的时候并没有什么问题,例如使用Windows平台、使用Oracle JDK(这样就不需要再单独安装FX组件了,可以不用MAVEN)、使用Oracle的SceneBuilder。可能唯一一个比较影响体验的就是不使用IDEA而是使用eclipse了

  • Ubuntu18.04LTS

  • OpenJDK 1.8

  • IDEA(with MAVEN):使用MAVEN安装FX环境(OpenJDK不附带FX环境)

  • SceneBuilder(glounhq):这是一个fxml可视化设计环境,使用上不如C#,但起码比纯命令设计强一百倍

搭建JAVA FX环境

下载IDEA、OpenJDK1.8、SceneBuilder(glounhq).

SceneBuilder下载地址:https://gluonhq.com/products/scene-builder/#download

在IDEA中关联SceneBuilder.关联的目的是为了之后可以从IDEA快速打开SceneBuilder来设计页面

IDEA->File->Settings->Language->Java FX->输入SceneBuilder的路径

如果是Linux环境,你会发现这个路径还不好找,我是使用locate SceneBuilder命令找到的,路径是: /opt/SceneBuilder/SceneBuilder

因为OpenJDK没有FX环境,需要我们自己安装。为了便于管理,我们在这里使用MAVEN

在IDEA中创建一个Java FX项目

在项目名上右键,选择'Add framework support',选择MAVEN

在pom.xml文件中加入以下依赖:


<dependencies>
   <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
   <dependency>
     <groupId>org.openjfx</groupId>
     <artifactId>javafx-controls</artifactId>
     <version>13</version>
   </dependency>
   <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-fxml -->
   <dependency>
     <groupId>org.openjfx</groupId>
     <artifactId>javafx-fxml</artifactId>
     <version>13</version>
   </dependency>
 </dependencies>

设计流程

这里只写一些我已经探索出来的设计流程,如果有不对的请指出~

先在Resources中创建fxml文件(之所以放在Resources文件夹下,是为了加载的时候方便,之后能看到),创建完成后在文件名上右击,选择'Open in SceneBuilder',之后就可以在SceneBuilder中进行可视化设计了。设计时要注意,对有响应的元素要在code栏下的fx:id中设置id,以便于之后的调用。设计完成后Ctrl+s保存文件

设计第一个加载的界面。这个可以放在入口的java类的main方法下,举个例子:


package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

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

Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("Entry.fxml"));//从Resources中获取资源
   primaryStage.setTitle("Course Registration System");
   primaryStage.setScene(new Scene(root, 800, 600));
   primaryStage.show();
 }

设计触发器:

对于每一个Panel,我们要指定一个触发器类,这个是放在该fxml文件中的,例如IDEA中默认创建的就是AnchorPane对象,在它那一行就能找到:fx:controller="sample.MainController" ,这个MainController就是我创建的一个类

之后,我们可以对该panel下各个控件设计触发事件后的反映,这个可以在SceneBuilder中填写,在Code那一栏下面。设计了之后,它就会到我们指定的那个触发器类下寻找这个方法,如果没有的话IDEA会提示你创建

注意,触发器类可以创建多个,这样更便于管理,降低耦合度

在触发器中获取fxml中的控件对象

有时候,我们需要在事件相应中获取对象的值,例如设计登录页面时点击'提交'的按钮,我们需要知道输入框的字符串。这时候我们可以在触发器中获取这些元素,前提是我们为这些控件输入了fx:id,它是全局性的,不允许重复。例如我们可以通过声明:


 @FXML
 private TextField username;
 @FXML
 private TextField password;

获取两个TextField对象下的值:


usernameString=username.getText();
passwordString=password.getText();

页面跳转

我们需要为每一个页面设计一个Java类,例如我设计了一个SignIn_Student.java:


package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class SignIn_Student extends Application{
 private String usernameString;
 private String passwordString;
 @Override
 public void start(Stage stage) throws Exception{
   Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("SignIn_Student.fxml"));//加载页面
   Scene anotherScene=new Scene(root);
   stage.setTitle("Please log in");
   stage.setScene(anotherScene);
   stage.show();
 }
}

TableView的使用

这个控件用起来着实有点麻烦。折腾了好久。

我们肯定需要在某一个fxml页面中加入了这个TableView,并且输入了Table和它每一个TableColumn的fx:id.

我们需要为有TableView的fxml文件单独创建一个控制器类,之后会说为什么

我们需要创建一个类来表示要储存的数据,例如我这里创建了一个Courses.class:(下面的get和set方法是IDEA自动生成的)


package sample;
import javafx.beans.property.*;
import java.time.LocalDate;
import java.time.LocalTime;
public class Courses {
 private final StringProperty department;
 private final StringProperty lecturer;
 private final ObjectProperty<LocalDate> Time;
 private final StringProperty location;
 private final IntegerProperty ID;

public Courses(String name, String department, String lecturer, LocalDate time, String location, Integer ID) {
   this.name = new SimpleStringProperty(name);
   this.department = new SimpleStringProperty(department);
   this.lecturer = new SimpleStringProperty(lecturer);
   this.Time = new SimpleObjectProperty<LocalDate>(time);
   this.location = new SimpleStringProperty(location);
   this.ID = new SimpleIntegerProperty(ID);
 }
 //String,String,String, Date,String,Integer
 private final StringProperty name;

public String getName() {
   return name.get();
 }

public StringProperty nameProperty() {
   return name;
 }

public void setName(String name) {
   this.name.set(name);
 }

public String getDepartment() {
   return department.get();
 }

public StringProperty departmentProperty() {
   return department;
 }

public void setDepartment(String department) {
   this.department.set(department);
 }

public String getLecturer() {
   return lecturer.get();
 }

public StringProperty lecturerProperty() {
   return lecturer;
 }

public void setLecturer(String lecturer) {
   this.lecturer.set(lecturer);
 }

public LocalDate getTime() {
   return Time.get();
 }

public ObjectProperty<LocalDate> timeProperty() {
   return Time;
 }

public void setTime(LocalDate time) {
   this.Time.set(time);
 }

public String getLocation() {
   return location.get();
 }

public StringProperty locationProperty() {
   return location;
 }

public void setLocation(String location) {
   this.location.set(location);
 }

public int getID() {
   return ID.get();
 }

public IntegerProperty IDProperty() {
   return ID;
 }

public void setID(int ID) {
   this.ID.set(ID);
 }
}

我们需要实现的效果是,在加载这个页面时,表格中自动加载数据。填写我们创建的控制器类如下:


package sample;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;

import java.time.LocalDate;

public class MainController {
 @FXML
 private TextField username;
 @FXML
 private TextField password;
 @FXML
 private TableView<Courses> allCoursesTable;
 @FXML
 private TableColumn<Courses,String> CourseNameAttribute;
 @FXML
 private TableColumn<Courses,String> DepartmentAttribute;
 @FXML
 private TableColumn<Courses,String> LectureAttribute;
 @FXML
 private TableColumn<Courses, LocalDate> TimeAttribute;
 @FXML
 private TableColumn<Courses,String> LocationAttribute;
 @FXML
 private TableColumn<Courses,Number> CourseIDAttribute;
 @FXML
 private void initialize() {
   ObservableList<Courses> data= FXCollections.observableArrayList(new Courses("MACHINE LEARNING","COMPUTER","ZHANGYI",LocalDate.of(2012,01,01),"A101",4011));//创建ObservableList对象,将数据装进去
   CourseNameAttribute.setCellValueFactory(cellData->cellData.getValue().nameProperty());
   DepartmentAttribute.setCellValueFactory(cellData->cellData.getValue().departmentProperty());
   LectureAttribute.setCellValueFactory(cellData->cellData.getValue().lecturerProperty());
   TimeAttribute.setCellValueFactory(cellData->cellData.getValue().timeProperty());
   LocationAttribute.setCellValueFactory(cellData->cellData.getValue().locationProperty());
   CourseIDAttribute.setCellValueFactory(cellData->cellData.getValue().IDProperty());
   allCoursesTable.setItems(data);//加载数据
 }
}

这就是为什么要用单独的控制器类了,否则initialize方法会在每次创建页面的时候都加载一次,而只有某一个页面有我们说的这些Tabel和Column对象,会报错的。

写一个方法来跳转到这个页面。

如何实现页面之间的传参呢?

对于要传参的页面,我们就不能直接获取parent对象了,而是先要获取FXMLLoader对象:


FXMLLoader fxmlLoader = new FXMLLoader(getClass().getClassLoader().getResource("MainPanel.fxml"));
Parent root = fxmlLoader.load();
MainController mc=fxmlLoader.getController();

注意这个MainController是我为这个页面写的控制器类

获取了Controller对象后,我们就可以调用方法,将参数传进去了:


   mc.setPassword(pass);
   mc.setUsername(user);
   mc.handleAllCourses();

我在MainController这个类中是这样写的:


 public void setUsername(String username){
   usernameString=username;
 }
 public void setPassword(String password){
   passwordString=password;
 }

这就是入门的FX教程了,有了这些基本的方法,相信设计一个稍微复杂一点的桌面应用程序已经不是问题了。

来源:https://www.cnblogs.com/jiading/p/11823872.html

标签:java,fx,开发,桌面,程序
0
投稿

猜你喜欢

  • Flutter 实现虎牙/斗鱼 弹幕功能

    2023-07-11 04:11:11
  • c++中数字与字符串之间的转换方法(推荐)

    2023-02-22 17:58:09
  • Android安装apk文件并适配Android 7.0详解

    2022-11-11 01:41:28
  • Android中post请求传递json数据给服务端的实例

    2022-04-21 01:51:18
  • Android 7.0中拍照和图片裁剪适配的问题详解

    2022-09-27 07:29:57
  • java实现邮件发送

    2022-06-03 02:48:20
  • 解决SpringBoot跨域的三种方式

    2021-06-20 13:20:08
  • C#实现创建,删除,查找,配置虚拟目录实例详解

    2022-09-27 06:38:16
  • Java中的字节流文件读取教程(二)

    2023-09-27 04:59:02
  • Java的内部类总结

    2022-08-13 01:33:41
  • 通过Android trace文件分析死锁ANR实例过程

    2023-06-11 04:58:03
  • Java中的内部类你了解吗

    2022-12-11 08:29:10
  • Java设计模式之观察者模式(Observer模式)介绍

    2022-10-16 04:40:42
  • SpringBoot与Postman实现REST模拟请求的操作

    2022-12-22 04:06:14
  • 详解C#如何利用爬虫技术实现快捷租房

    2021-11-02 21:49:38
  • Springboot2.1.6集成activiti7出现登录验证的实现

    2022-08-03 10:44:48
  • Java毕业设计实战之图片展览馆管理系统的实现

    2021-06-16 08:23:18
  • Java开发人员需知的十大戒律

    2023-09-17 07:33:50
  • Android setButtonDrawable()的兼容问题解决办法

    2021-12-11 04:33:52
  • 微信小程序获取手机号,后端JAVA解密流程代码

    2023-11-29 07:57:26
  • asp之家 软件编程 m.aspxhome.com