桌面应用JavaFx

admin 8430 2025-12-07 21:54:03

官网

https://openjfx.cn/

JavaFX 是什么?

JavaFX 是 Java 平台上的下一代 GUI 工具包,最初由 Sun Microsystems 推出,后来归于 Oracle。它的设计理念与 Swing 完全不同,更偏向现代 UI 开发:

•支持 CSS 样式化

•FXML 结构化布局

•内置动画和媒体支持

•更易于绑定与响应式编程

与 Swing 相比,JavaFX 组件更美观、灵活性更强,同时更适合使用 MVVM 模式进行架构设计。

OpenJFX 与 JavaFX 的关系

JavaFX 在 Java 8 中曾是 JDK 的一部分。但从 JDK 11 开始,Oracle 将其剥离出了 JDK,转为一个独立的开源项目:OpenJFX。

名称

说明

JavaFX

Oracle 的 GUI 工具包

OpenJFX

JavaFX 的开源实现版本

目前主流的 JavaFX 开发,基本上都基于 OpenJFX,比如:

•Gluon 提供的 OpenJFX 二进制发布

•Scene Builder 等工具的支持

JavaFX 的核心组成

JavaFX 的体系庞大但清晰,可分为以下模块:

•javafx-base:基本类,如属性绑定

•javafx-controls:UI 控件,如 Button、TableView

•javafx-graphics:场景图、Canvas、绘图等

•javafx-fxml:FXML 解析器

•javafx-media:音视频播放支持

•javafx-web:WebView,嵌入浏览器

此外还有社区维护的扩展库,如:

•ControlsFX:增强 UI 控件

•Flowless:高性能虚拟滚动

•MVVMFX、DataFX:MVVM 框架支持

使用场景

JavaFX 并不是“老掉牙”的选择,它在以下场景中仍然大有可为:

•企业内网应用(无需浏览器)

•数据可视化与监控面板

•工控/医疗设备界面

•教育培训软件

•跨平台桌面客户端

MVVM 架构(推荐)

推荐使用 JDK 17+ 搭配 OpenJFX,同时使用 Maven 或 Gradle 来进行依赖管理。

项目结构

student-http-mvvm/

├── model/

│ └── Student.java

├── service/

│ └── StudentService.java <-- 调用 HTTP 接口

├── view/

│ └── StudentView.fxml

├── viewmodel/

│ └── StudentViewModel.java <-- 绑定属性 + 调用接口

├── controller/

│ └── StudentController.java <-- UI事件 → ViewModel

└── Main.java

mvvm对应类

类解释

调用关系流程

StudentView.fxml (View)

└── 绑定 fx:controller → StudentController.java (Controller)

└── UI事件转发 → StudentViewModel.java (ViewModel)

└── 调用 → StudentService.java (Service)

└── 请求/响应 → 后端 HTTP 接口

└── JSON 映射 → Student.java (Model)

代码

Maven 依赖(hutool + javafx)

cn.hutool

hutool-all

5.8.26

org.openjfx

javafx-controls

17

model/Student.java

package model;

@Data

public class Student {

private String name;

private int age;

}

service/StudentService.java(使用 Hutool HTTP)

package service;

import cn.hutool.http.HttpRequest;

import cn.hutool.http.HttpResponse;

import cn.hutool.json.JSONUtil;

import model.Student;

import java.util.Arrays;

import java.util.List;

public class StudentService {

private final String BASE_URL = "http://localhost:8080";

public List fetchStudents() {

String resp = HttpRequest.get(BASE_URL + "/students").execute().body();

return JSONUtil.toList(resp, Student.class);

}

public void addStudent(Student student) {

String json = JSONUtil.toJsonStr(student);

HttpRequest.post(BASE_URL + "/students")

.body(json)

.contentType("application/json")

.execute();

}

}

viewmodel/StudentViewModel.java

package viewmodel;

import javafx.beans.property.*;

import javafx.collections.FXCollections;

import javafx.collections.ObservableList;

import model.Student;

import service.StudentService;

import java.util.List;

public class StudentViewModel {

private final StringProperty name = new SimpleStringProperty();

private final IntegerProperty age = new SimpleIntegerProperty();

private final ObservableList studentList = FXCollections.observableArrayList();

private final StudentService studentService = new StudentService();

public void fetchStudents() {

List students = studentService.fetchStudents();

studentList.setAll(students);

}

public void saveStudent() {

Student student = new Student(name.get(), age.get());

studentService.addStudent(student);

fetchStudents();

}

public StringProperty nameProperty() { return name; }

public IntegerProperty ageProperty() { return age; }

public ObservableList getStudentList() { return studentList; }

}

view/StudentView.fxml

controller/StudentController.java(UI事件 → ViewModel)

package controller;

import javafx.fxml.FXML;

import javafx.scene.control.ListView;

import javafx.scene.control.TextField;

import javafx.util.converter.NumberStringConverter;

import viewmodel.StudentViewModel;

public class StudentController {

@FXML private TextField nameField;

@FXML private TextField ageField;

@FXML private ListView studentListView;

private final StudentViewModel viewModel = new StudentViewModel();

@FXML

public void initialize() {

nameField.textProperty().bindBidirectional(viewModel.nameProperty());

ageField.textProperty().bindBidirectional(viewModel.ageProperty(), new NumberStringConverter());

// 简单地绑定名称

viewModel.getStudentList().addListener((obs, old, updated) -> {

studentListView.getItems().clear();

viewModel.getStudentList().forEach(s -> {

studentListView.getItems().add(s.getName() + " (" + s.getAge() + ")");

});

});

viewModel.fetchStudents();

}

@FXML

public void onSave() {

viewModel.saveStudent();

}

@FXML

public void onFetch() {

viewModel.fetchStudents();

}

}

启动类 Main.java

import javafx.application.Application;

import javafx.fxml.FXMLLoader;

import javafx.scene.Scene;

import javafx.stage.Stage;

public class Main extends Application {

@Override

public void start(Stage stage) throws Exception {

stage.setTitle("学生管理系统");

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/view/StudentView.fxml"));

Scene scene = new Scene(fxmlLoader.load(), 400, 300);

stage.setScene(scene);

stage.show();

}

public static void main(String[] args) {

launch(args);

}

}

总结

ViewModel作用

为什么要使用ViewModel,而不是controller直接调用service:

ViewModel 是“逻辑中枢”,Controller 不做业务,Controller 只做桥梁。

如果真的想在某些极简 demo 中简化,也可以跳过 ViewModel,但是只适合玩具项目。在生产系统或教学中,需要坚守 MVVM 架构。

🏆 为什么推荐 MVVM?

• ViewModel 专注做状态和行为管理,职责单一

• Controller 简洁清晰,没有业务逻辑

• FXML 可绑定 ViewModel 的属性:

• 便于写单元测试,只测试 ViewModel,不依赖 UI

⚠️ 非 MVVM主要问题

• 视图字段(原本ViewModel) name/age/students 都散落在 Controller,状态不集中

• UI 控件和数据逻辑搅在一起,难维护

• 无法绑定:TextField 不支持自动双向绑定

• 无法测试:Controller 依赖 UI 元素,无法单元测试

总结:

非 MVVM 架构一时爽,MVVM 架构保项目后期不爆炸 💥。

开发体验补充推荐

Scene Builder:所见即所得

拖拖拽拽构建 FXML,一键绑定 Controller 和 ViewModel,很适合 UI 开发人员和程序员协作。

IntelliJ IDEA + MVVMFX 插件

提升开发效率,尤其适合模块化开发与大型应用维护。

上一篇
下一篇
相关文章