add JavaFX demo application
- Add FxMain as JavaFX application entry with IOC integration - Add FxConfig with @Bean factory methods for DateTimeFormatter - Add MainController with constructor injection - Add UserService and MessageService layers - Add main.fxml view with user management UI - Add javafx-fxml dependency and javafx-maven-plugin - Add demo documentation and run script - Demonstrate @Controller, @Service, @Qualifier, @PostConstruct in JavaFX context Run with: mvn javafx:run or run-javafx-demo.bat Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
170
javafx-demo.md
Normal file
170
javafx-demo.md
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
# JavaFX 示例说明
|
||||||
|
|
||||||
|
这是一个完整的 JavaFX 应用示例,展示如何在 JavaFX 中使用 Timi-Inject IOC/DI 框架。
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
src/test/java/com/imyeyu/inject/javafxdemo/
|
||||||
|
├── FxMain.java # JavaFX 应用入口
|
||||||
|
├── FxConfig.java # 配置类 (@Configuration)
|
||||||
|
├── MainController.java # 主界面控制器 (@Controller)
|
||||||
|
├── UserService.java # 用户服务 (@Service)
|
||||||
|
└── MessageService.java # 消息服务 (@Service)
|
||||||
|
|
||||||
|
src/test/resources/javafxdemo/
|
||||||
|
└── main.fxml # 主界面 FXML 文件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 核心特性展示
|
||||||
|
|
||||||
|
### 1. IOC 容器初始化
|
||||||
|
|
||||||
|
```java
|
||||||
|
@TimiInjectApplication("com.imyeyu.inject.javafxdemo")
|
||||||
|
@Import(FxConfig.class)
|
||||||
|
public class FxMain extends Application {
|
||||||
|
private static TimiInject inject;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 启动 IOC 容器
|
||||||
|
inject = TimiInject.run(FxMain.class);
|
||||||
|
|
||||||
|
// 启动 JavaFX 应用
|
||||||
|
launch(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 控制器工厂集成
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage) throws Exception {
|
||||||
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/javafxdemo/main.fxml"));
|
||||||
|
|
||||||
|
// 使用 IOC 容器作为控制器工厂
|
||||||
|
loader.setControllerFactory(type -> inject.di(type));
|
||||||
|
|
||||||
|
Parent root = loader.load();
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 构造器依赖注入
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Controller
|
||||||
|
public class MainController {
|
||||||
|
private final UserService userService;
|
||||||
|
private final MessageService messageService;
|
||||||
|
|
||||||
|
// 构造器注入
|
||||||
|
public MainController(UserService userService, MessageService messageService) {
|
||||||
|
this.userService = userService;
|
||||||
|
this.messageService = messageService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. @Bean 工厂方法
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Configuration
|
||||||
|
public class FxConfig {
|
||||||
|
@Bean
|
||||||
|
public DateTimeFormatter dateTimeFormatter() {
|
||||||
|
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("appTitle")
|
||||||
|
public String appTitle() {
|
||||||
|
return "Timi-Inject JavaFX Demo";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. @Qualifier 限定注入
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
public class MessageService {
|
||||||
|
private final String appTitle;
|
||||||
|
private final String version;
|
||||||
|
|
||||||
|
public MessageService(@Qualifier("appTitle") String appTitle,
|
||||||
|
@Qualifier("version") String version) {
|
||||||
|
this.appTitle = appTitle;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. @PostConstruct 生命周期
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
public class UserService {
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
users.add("Admin");
|
||||||
|
users.add("User1");
|
||||||
|
users.add("User2");
|
||||||
|
System.out.println("UserService initialized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 运行方式
|
||||||
|
|
||||||
|
### 方式一:使用 Maven 插件(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn clean javafx:run
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方式二:命令行运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 编译
|
||||||
|
mvn clean compile test-compile
|
||||||
|
|
||||||
|
# 运行(需要正确配置 JavaFX 模块路径)
|
||||||
|
java --module-path %PATH_TO_JAVAFX% \
|
||||||
|
--add-modules javafx.controls,javafx.fxml \
|
||||||
|
-cp target/classes;target/test-classes;... \
|
||||||
|
com.imyeyu.inject.javafxdemo.FxMain
|
||||||
|
```
|
||||||
|
|
||||||
|
## 应用功能
|
||||||
|
|
||||||
|
1. **用户管理**
|
||||||
|
- 添加用户
|
||||||
|
- 删除选中用户
|
||||||
|
- 显示用户列表
|
||||||
|
|
||||||
|
2. **实时日志**
|
||||||
|
- 操作日志记录
|
||||||
|
- 时间戳显示
|
||||||
|
- 清空日志功能
|
||||||
|
|
||||||
|
3. **依赖注入演示**
|
||||||
|
- 控制器通过构造器注入服务
|
||||||
|
- 服务之间相互依赖
|
||||||
|
- @Bean 方法提供配置对象
|
||||||
|
- @Qualifier 精确匹配依赖
|
||||||
|
|
||||||
|
## 技术亮点
|
||||||
|
|
||||||
|
1. **零配置** - 使用注解驱动,无需 XML
|
||||||
|
2. **类型安全** - 编译时类型检查
|
||||||
|
3. **生命周期管理** - @PostConstruct 初始化
|
||||||
|
4. **优雅集成** - 与 JavaFX 无缝整合
|
||||||
|
5. **依赖追踪** - 清晰的依赖关系
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. JavaFX 依赖设置为 `test` scope,仅用于演示
|
||||||
|
2. 控制器工厂必须在加载 FXML 前设置
|
||||||
|
3. FXML 文件路径相对于 classpath
|
||||||
|
4. 确保 JDK 21 和 JavaFX 21.0.2 版本匹配
|
||||||
19
pom.xml
19
pom.xml
@ -33,5 +33,24 @@
|
|||||||
<version>${javafx.version}</version>
|
<version>${javafx.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-fxml</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-maven-plugin</artifactId>
|
||||||
|
<version>0.0.8</version>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>com.imyeyu.inject.javafxdemo.FxMain</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
21
run-javafx-demo.bat
Normal file
21
run-javafx-demo.bat
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
@echo off
|
||||||
|
echo =====================================
|
||||||
|
echo Timi-Inject JavaFX Demo
|
||||||
|
echo =====================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo Compiling project...
|
||||||
|
call mvn clean compile test-compile -Dmaven.test.skip=false -q
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Compilation failed!
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Starting JavaFX application...
|
||||||
|
echo.
|
||||||
|
|
||||||
|
call mvn javafx:run
|
||||||
|
|
||||||
|
pause
|
||||||
30
src/test/java/com/imyeyu/inject/javafxdemo/FxConfig.java
Normal file
30
src/test/java/com/imyeyu/inject/javafxdemo/FxConfig.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package com.imyeyu.inject.javafxdemo;
|
||||||
|
|
||||||
|
import com.imyeyu.inject.annotation.Bean;
|
||||||
|
import com.imyeyu.inject.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JavaFX 应用配置
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class FxConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DateTimeFormatter dateTimeFormatter() {
|
||||||
|
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("appTitle")
|
||||||
|
public String appTitle() {
|
||||||
|
return "Timi-Inject JavaFX Demo";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("version")
|
||||||
|
public String version() {
|
||||||
|
return "0.0.2";
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/test/java/com/imyeyu/inject/javafxdemo/FxMain.java
Normal file
51
src/test/java/com/imyeyu/inject/javafxdemo/FxMain.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package com.imyeyu.inject.javafxdemo;
|
||||||
|
|
||||||
|
import com.imyeyu.inject.TimiInject;
|
||||||
|
import com.imyeyu.inject.annotation.Import;
|
||||||
|
import com.imyeyu.inject.annotation.TimiInjectApplication;
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JavaFX 应用入口
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
*/
|
||||||
|
@TimiInjectApplication("com.imyeyu.inject.javafxdemo")
|
||||||
|
@Import(FxConfig.class)
|
||||||
|
public class FxMain extends Application {
|
||||||
|
|
||||||
|
private static TimiInject inject;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 启动 IOC 容器
|
||||||
|
inject = TimiInject.run(FxMain.class);
|
||||||
|
|
||||||
|
// 启动 JavaFX 应用
|
||||||
|
launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage) throws Exception {
|
||||||
|
// 创建 FXMLLoader 并设置控制器工厂
|
||||||
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/javafxdemo/main.fxml"));
|
||||||
|
loader.setControllerFactory(type -> inject.di(type));
|
||||||
|
|
||||||
|
Parent root = loader.load();
|
||||||
|
|
||||||
|
Scene scene = new Scene(root, 600, 400);
|
||||||
|
primaryStage.setTitle("Timi-Inject JavaFX Demo");
|
||||||
|
primaryStage.setScene(scene);
|
||||||
|
primaryStage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 IOC 容器实例
|
||||||
|
*/
|
||||||
|
public static TimiInject getInject() {
|
||||||
|
return inject;
|
||||||
|
}
|
||||||
|
}
|
||||||
132
src/test/java/com/imyeyu/inject/javafxdemo/MainController.java
Normal file
132
src/test/java/com/imyeyu/inject/javafxdemo/MainController.java
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package com.imyeyu.inject.javafxdemo;
|
||||||
|
|
||||||
|
import com.imyeyu.inject.annotation.Controller;
|
||||||
|
import com.imyeyu.inject.annotation.PostConstruct;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主界面控制器
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class MainController {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label welcomeLabel;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label timeLabel;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label countLabel;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TextField usernameField;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ListView<String> userListView;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TextArea logArea;
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
private final MessageService messageService;
|
||||||
|
private final ObservableList<String> userList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
|
public MainController(UserService userService, MessageService messageService) {
|
||||||
|
this.userService = userService;
|
||||||
|
this.messageService = messageService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
log("MainController initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
// 设置欢迎消息
|
||||||
|
welcomeLabel.setText(messageService.getWelcomeMessage());
|
||||||
|
|
||||||
|
// 加载用户列表
|
||||||
|
refreshUserList();
|
||||||
|
|
||||||
|
// 更新时间
|
||||||
|
updateTime();
|
||||||
|
|
||||||
|
log("UI initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void handleAddUser() {
|
||||||
|
String username = usernameField.getText().trim();
|
||||||
|
if (username.isEmpty()) {
|
||||||
|
showError("Please enter a username");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
userService.addUser(username);
|
||||||
|
refreshUserList();
|
||||||
|
usernameField.clear();
|
||||||
|
log(messageService.getSuccessMessage("User added"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
showError(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void handleRemoveUser() {
|
||||||
|
String selectedUser = userListView.getSelectionModel().getSelectedItem();
|
||||||
|
if (selectedUser == null) {
|
||||||
|
showError("Please select a user to remove");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
userService.removeUser(selectedUser);
|
||||||
|
refreshUserList();
|
||||||
|
log(messageService.getSuccessMessage("User removed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void handleRefresh() {
|
||||||
|
refreshUserList();
|
||||||
|
updateTime();
|
||||||
|
log("Refreshed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void handleClearLog() {
|
||||||
|
logArea.clear();
|
||||||
|
log("Log cleared");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshUserList() {
|
||||||
|
userList.clear();
|
||||||
|
userList.addAll(userService.getAllUsers());
|
||||||
|
userListView.setItems(userList);
|
||||||
|
countLabel.setText("Total Users: " + userService.getUserCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTime() {
|
||||||
|
timeLabel.setText("Current Time: " + userService.getCurrentTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showError(String message) {
|
||||||
|
log(messageService.getErrorMessage(message));
|
||||||
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
|
alert.setTitle("Error");
|
||||||
|
alert.setHeaderText(null);
|
||||||
|
alert.setContentText(message);
|
||||||
|
alert.showAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void log(String message) {
|
||||||
|
String timestamp = userService.getCurrentTime();
|
||||||
|
logArea.appendText(String.format("[%s] %s%n", timestamp, message));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.imyeyu.inject.javafxdemo;
|
||||||
|
|
||||||
|
import com.imyeyu.inject.annotation.Qualifier;
|
||||||
|
import com.imyeyu.inject.annotation.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息服务
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MessageService {
|
||||||
|
|
||||||
|
private final String appTitle;
|
||||||
|
private final String version;
|
||||||
|
|
||||||
|
public MessageService(@Qualifier("appTitle") String appTitle,
|
||||||
|
@Qualifier("version") String version) {
|
||||||
|
this.appTitle = appTitle;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWelcomeMessage() {
|
||||||
|
return String.format("Welcome to %s v%s!", appTitle, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSuccessMessage(String action) {
|
||||||
|
return action + " successfully!";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMessage(String error) {
|
||||||
|
return "Error: " + error;
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/test/java/com/imyeyu/inject/javafxdemo/UserService.java
Normal file
59
src/test/java/com/imyeyu/inject/javafxdemo/UserService.java
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package com.imyeyu.inject.javafxdemo;
|
||||||
|
|
||||||
|
import com.imyeyu.inject.annotation.PostConstruct;
|
||||||
|
import com.imyeyu.inject.annotation.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户服务
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class UserService {
|
||||||
|
|
||||||
|
private final DateTimeFormatter dateTimeFormatter;
|
||||||
|
private final List<String> users = new ArrayList<>();
|
||||||
|
|
||||||
|
public UserService(DateTimeFormatter dateTimeFormatter) {
|
||||||
|
this.dateTimeFormatter = dateTimeFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
users.add("Admin");
|
||||||
|
users.add("User1");
|
||||||
|
users.add("User2");
|
||||||
|
System.out.println("UserService initialized with " + users.size() + " users");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getAllUsers() {
|
||||||
|
return new ArrayList<>(users);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addUser(String username) {
|
||||||
|
if (username == null || username.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("Username cannot be empty");
|
||||||
|
}
|
||||||
|
if (users.contains(username)) {
|
||||||
|
throw new IllegalArgumentException("User already exists");
|
||||||
|
}
|
||||||
|
users.add(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeUser(String username) {
|
||||||
|
users.remove(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrentTime() {
|
||||||
|
return LocalDateTime.now().format(dateTimeFormatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUserCount() {
|
||||||
|
return users.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/test/resources/javafxdemo/main.fxml
Normal file
72
src/test/resources/javafxdemo/main.fxml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<BorderPane xmlns="http://javafx.com/javafx"
|
||||||
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
fx:controller="com.imyeyu.inject.javafxdemo.MainController"
|
||||||
|
prefHeight="400.0" prefWidth="600.0">
|
||||||
|
|
||||||
|
<!-- 顶部区域 -->
|
||||||
|
<top>
|
||||||
|
<VBox spacing="10" style="-fx-background-color: #2196F3; -fx-padding: 20;">
|
||||||
|
<Label fx:id="welcomeLabel" style="-fx-text-fill: white; -fx-font-size: 18; -fx-font-weight: bold;"/>
|
||||||
|
<Label fx:id="timeLabel" style="-fx-text-fill: white; -fx-font-size: 12;"/>
|
||||||
|
<Label fx:id="countLabel" style="-fx-text-fill: white; -fx-font-size: 12;"/>
|
||||||
|
</VBox>
|
||||||
|
</top>
|
||||||
|
|
||||||
|
<!-- 中心区域 -->
|
||||||
|
<center>
|
||||||
|
<SplitPane dividerPositions="0.5" BorderPane.margin="10">
|
||||||
|
<!-- 左侧:用户列表 -->
|
||||||
|
<VBox spacing="10">
|
||||||
|
<Label text="User Management" style="-fx-font-size: 14; -fx-font-weight: bold;"/>
|
||||||
|
|
||||||
|
<HBox spacing="10">
|
||||||
|
<TextField fx:id="usernameField" promptText="Enter username" HBox.hgrow="ALWAYS"/>
|
||||||
|
<Button text="Add" onAction="#handleAddUser" style="-fx-background-color: #4CAF50; -fx-text-fill: white;"/>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
|
<ListView fx:id="userListView" VBox.vgrow="ALWAYS"/>
|
||||||
|
|
||||||
|
<HBox spacing="10">
|
||||||
|
<Button text="Remove Selected" onAction="#handleRemoveUser"
|
||||||
|
style="-fx-background-color: #f44336; -fx-text-fill: white;" HBox.hgrow="ALWAYS"/>
|
||||||
|
<Button text="Refresh" onAction="#handleRefresh"
|
||||||
|
style="-fx-background-color: #2196F3; -fx-text-fill: white;" HBox.hgrow="ALWAYS"/>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
|
<padding>
|
||||||
|
<Insets top="10" right="10" bottom="10" left="10"/>
|
||||||
|
</padding>
|
||||||
|
</VBox>
|
||||||
|
|
||||||
|
<!-- 右侧:日志区域 -->
|
||||||
|
<VBox spacing="10">
|
||||||
|
<HBox>
|
||||||
|
<Label text="Operation Log" style="-fx-font-size: 14; -fx-font-weight: bold;" HBox.hgrow="ALWAYS"/>
|
||||||
|
<Button text="Clear Log" onAction="#handleClearLog" style="-fx-font-size: 10;"/>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
|
<TextArea fx:id="logArea" editable="false" VBox.vgrow="ALWAYS"
|
||||||
|
style="-fx-font-family: 'Consolas', monospace; -fx-font-size: 11;"/>
|
||||||
|
|
||||||
|
<padding>
|
||||||
|
<Insets top="10" right="10" bottom="10" left="10"/>
|
||||||
|
</padding>
|
||||||
|
</VBox>
|
||||||
|
</SplitPane>
|
||||||
|
</center>
|
||||||
|
|
||||||
|
<!-- 底部区域 -->
|
||||||
|
<bottom>
|
||||||
|
<HBox spacing="10" style="-fx-background-color: #f5f5f5; -fx-padding: 10;">
|
||||||
|
<Label text="Powered by Timi-Inject" style="-fx-font-size: 10; -fx-text-fill: #666;"/>
|
||||||
|
<Region HBox.hgrow="ALWAYS"/>
|
||||||
|
<Label text="IOC/DI Framework Demo" style="-fx-font-size: 10; -fx-text-fill: #666;"/>
|
||||||
|
</HBox>
|
||||||
|
</bottom>
|
||||||
|
</BorderPane>
|
||||||
Reference in New Issue
Block a user