本文面向已经会基础 Java 的读者,目标是用实战示例带你快速上手 JavaFX,掌握界面布局、事件处理、样式定制、多线程与打包部署等常用技巧。文章按章节展开,代码示例尽量完整,可直接复制运行。

JavaFX 是 Oracle/开源社区维护的现代 Java 桌面 GUI 框架,支持响应式布局、CSS 样式、矢量图形、硬件加速和富媒体(音视频)等特性。相比 Swing,JavaFX 更现代、组件更丰富、易于使用 CSS 美化,且与 Java 生态兼容(Maven/Gradle)。

org.openjfx:javafx 依赖,或使用 SDKMAN/手动下载 OpenJFX SDK 并配置运行参数。<!-- pom.xml 中关键片段(仅示意) -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<javafx.version>21.0.0</javafx.version> <!-- 请根据实际版本调整 -->
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>com.example.todo.MainApp</mainClass>
</configuration>
</plugin>
</plugins>
</build>构建一个简单的 To-Do 列表应用,功能:
我们使用纯代码(非 FXML)实现,便于快速理解控件与布局关系。
package com.example.todo;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class MainApp extends Application {
private final ObservableList<TodoItem> items = FXCollections.observableArrayList();
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("简易 To-Do");
// 顶部:输入框 + 添加按钮
TextField input = new TextField();
input.setPromptText("输入任务,按 Enter 添加");
input.setPrefWidth(300);
Button addBtn = new Button("添加");
HBox topBar = new HBox(10, input, addBtn);
topBar.setPadding(new Insets(10));
// 中间:ListView 显示任务
ListView<TodoItem> listView = new ListView<>(items);
listView.setCellFactory(lv -> new TodoCell());
VBox center = new VBox(listView);
center.setPadding(new Insets(0, 10, 10, 10));
VBox.setVgrow(listView, Priority.ALWAYS);
// 底部:状态栏 + 模拟加载按钮(演示后台任务)
Label status = new Label("就绪");
Button loadBtn = new Button("模拟加载(后台)");
HBox bottomBar = new HBox(10, status, new Region(), loadBtn);
HBox.setHgrow(bottomBar.getChildren().get(1), Priority.ALWAYS);
bottomBar.setPadding(new Insets(10));
BorderPane root = new BorderPane();
root.setTop(topBar);
root.setCenter(center);
root.setBottom(bottomBar);
Scene scene = new Scene(root, 500, 400);
scene.getStylesheets().add(getClass().getResource("/styles.css").toExternalForm());
// 事件:添加任务
addBtn.setOnAction(e -> addTask(input));
input.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ENTER) addTask(input);
});
// 模拟后台加载任务
loadBtn.setOnAction(e -> {
status.setText("正在加载...");
Task<Void> loadTask = new Task<>() {
@Override
protected Void call() throws Exception {
Thread.sleep(2000); // 模拟耗时
Platform.runLater(() -> {
items.addAll(new TodoItem("示例任务 A"), new TodoItem("示例任务 B"));
});
return null;
}
@Override
protected void succeeded() {
status.setText("加载完成");
}
@Override
protected void failed() {
status.setText("加载失败");
}
};
new Thread(loadTask, "loader-thread").start();
});
primaryStage.setScene(scene);
primaryStage.show();
}
private void addTask(TextField input) {
String text = input.getText().trim();
if (!text.isEmpty()) {
items.add(new TodoItem(text));
input.clear();
}
}
public static void main(String[] args) {
launch(args);
}
}// TodoItem.java
package com.example.todo;
public class TodoItem {
private final String text;
private boolean done = false;
public TodoItem(String text) { this.text = text; }
public String getText() { return text; }
public boolean isDone() { return done; }
public void setDone(boolean done) { this.done = done; }
}// TodoCell.java
package com.example.todo;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
public class TodoCell extends ListCell<TodoItem> {
private final CheckBox checkBox = new CheckBox();
private final Label label = new Label();
private final Button delBtn = new Button("删除");
private final HBox container = new HBox(10, checkBox, label, new Separator(), delBtn);
public TodoCell() {
container.setPadding(new Insets(6));
container.setStyle("-fx-alignment: center-left;");
HBox.setHgrow(label, Priority.ALWAYS);
delBtn.setOnAction(e -> {
getListView().getItems().remove(getItem());
});
checkBox.setOnAction(e -> {
if (getItem() != null) {
getItem().setDone(checkBox.isSelected());
updateItem(getItem(), false);
}
});
}
@Override
protected void updateItem(TodoItem item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
label.setText(item.getText());
label.setStyle(item.isDone() ? "-fx-strikethrough: true;" : "-fx-strikethrough: false;");
checkBox.setSelected(item.isDone());
setGraphic(container);
}
}
}.root {
-fx-font-family: "Microsoft YaHei", "Segoe UI", sans-serif;
}
.button {
-fx-font-size: 13px;
-fx-padding: 6 12 6 12;
}
.list-cell {
-fx-border-color: transparent;
}
@FXML 注入控件。module-info.java 中 requires javafx.controls; requires javafx.fxml; 并 opens 控制器包给 javafx.fxml。Task<V> / Service<V> 或在后台线程运行并通过 Platform.runLater() 更新 UI。Task + new Thread(task).start())。StringProperty、IntegerProperty 等)和绑定 API,方便实现 UI 与数据同步。 label.textProperty().bind(textField.textProperty());-fx- 前缀)。jlink 或 jpackage(JDK 14+ 自带 jpackage)打包运行时镜像。 jpackage --name MyApp --input target/ --main-jar myapp.jar --main-class com.example.todo.MainAppjlink 定制运行时,再用 jpackage 生成 installer。NoClassDefFoundError: javafx/application/Application:表示未正确添加 JavaFX 运行时或 VM 参数缺失。 --module-path /path/to/javafx-sdk/lib --add-modules javafx.controls,javafx.fxmlcom.example.app:MainApp(启动)controller(FXML 控制器)view(FXML / 资源)model(数据模型)service(业务逻辑、IO、后台任务)ListView 本身是虚拟化的,TableView 也提供虚拟化)。Bindings 实现“剩余任务计数”自动显示。Service 定期同步(模拟远程备份)并在任务栏显示进度。
本文从 JavaFX 的特点与优势 出发,逐步带你完成了一个 完整的 To-Do 桌面应用。通过实战示例,你掌握了:
Stage、Scene、布局容器(BorderPane、HBox、VBox 等)组织 UI。ListCell 实现可复用的任务显示逻辑。Task 和 Platform.runLater 实现后台任务加载。jpackage 打包为原生安装包的流程。JavaFX 不仅能让 Java 程序拥有现代化的 UI 界面,还支持 CSS、FXML、硬件加速与响应式绑定,适合快速开发 跨平台桌面应用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。