JavaFX 表格组件详解及案例

1. 表格组件简介

  1. TableView:用于显示数据的二维表格,支持列排序、选择、编辑等功能。
  2. TreeTableView:类似于 TableView,但支持分层数据展示,适合树形结构的数据。

2. TableView 的常用方法

2.1 构造方法
  • TableView():创建一个空的表格视图。
  • TableView(ObservableList items):使用指定的初始数据创建表格。
2.2 列定义相关方法
  • TableColumn:定义表格的一列,其中 S 是表的模型类,T 是列的数据类型。

常见方法如下:

方法名说明示例
setCellValueFactory()设置列的值工厂,用于指定列数据的来源。nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
setCellFactory()自定义单元格的渲染方式(如格式化日期)。priceColumn.setCellFactory(column -> new CurrencyCell());
setSortable(boolean value)设置列是否支持排序,默认值为 truenameColumn.setSortable(false);
setPrefWidth(double value)设置列的首选宽度。priceColumn.setPrefWidth(150);
2.3 表格数据操作方法
方法名说明示例
setItems(ObservableList items)设置表格的数据集合。tableView.setItems(dataList);
getItems()获取表格当前的数据集合。ObservableList items = tableView.getItems();
refresh()刷新表格以更新显示内容。tableView.refresh();
2.4 选择相关方法
方法名说明示例
getSelectionModel()获取表格的选择模型,用于处理选中行的操作。tableView.getSelectionModel().getSelectedItem();
setSelectionMode()设置选择模式(单选或多选)。tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

3. 常见问题及解决方案

3.1 列数据绑定问题

问题: 数据类的字段未使用 JavaFX 属性(Property),导致表格数据无法自动更新。

解决方法: 使用 SimpleStringProperty 等属性包装字段,并在数据类中提供 getter 和 setter 方法。

public class Person {
    private final SimpleStringProperty name;
    private final SimpleIntegerProperty age;

    public Person(String name, int age) {
        this.name = new SimpleStringProperty(name);
        this.age = new SimpleIntegerProperty(age);
    }

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

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

    public int getAge() {
        return age.get();
    }

    public void setAge(int age) {
        this.age.set(age);
    }
}

3.2 表格刷新问题

问题: 更新数据后表格未自动刷新。

解决方法: 调用 refresh() 方法强制刷新表格。

tableView.refresh();

3.3 自定义单元格样式

问题: 默认样式不满足需求,例如高亮特定数据行。

解决方法: 使用 setCellFactory 自定义渲染逻辑。

statusColumn.setCellFactory(column -> new TableCell<Person, String>() {
    @Override
    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (item != null && !empty) {
            setText(item);
            setStyle(item.equals("Active") ? "-fx-background-color: lightgreen;" : "-fx-background-color: lightcoral;");
        } else {
            setText(null);
            setStyle("");
        }
    }
});

4. 完整案例

以下是一个完整的 TableView 案例,展示如何定义表格、绑定数据、自定义单元格渲染,以及处理常见问题。

4.1 数据模型
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;

public class Person {
    private final SimpleStringProperty name;
    private final SimpleIntegerProperty age;
    private final SimpleStringProperty status;

    public Person(String name, int age, String status) {
        this.name = new SimpleStringProperty(name);
        this.age = new SimpleIntegerProperty(age);
        this.status = new SimpleStringProperty(status);
    }

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

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

    public SimpleStringProperty nameProperty() {
        return name;
    }

    public int getAge() {
        return age.get();
    }

    public void setAge(int age) {
        this.age.set(age);
    }

    public SimpleIntegerProperty ageProperty() {
        return age;
    }

    public String getStatus() {
        return status.get();
    }

    public void setStatus(String status) {
        this.status.set(status);
    }

    public SimpleStringProperty statusProperty() {
        return status;
    }
}
4.2 主界面代码
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.util.stream.Collectors;

public class TableViewExample extends Application {
    private ObservableList<Person> masterData = FXCollections.observableArrayList(
            new Person("Alice", 30, "Active"),
            new Person("Bob", 25, "Inactive"),
            new Person("Charlie", 35, "Active")
    );
    private ObservableList<Person> filteredData = FXCollections.observableArrayList(masterData);

    @Override
    public void start(Stage primaryStage) {
        // 创建 TableView 和列
        TableView<Person> tableView = new TableView<>();
        TableColumn<Person, String> nameColumn = new TableColumn<>("Name");
        nameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());

        TableColumn<Person, Integer> ageColumn = new TableColumn<>("Age");
        ageColumn.setCellValueFactory(cellData -> cellData.getValue().ageProperty().asObject());

        TableColumn<Person, String> statusColumn = new TableColumn<>("Status");
        statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty());

        tableView.getColumns().addAll(nameColumn, ageColumn, statusColumn);
        tableView.setItems(filteredData);

        // 搜索框
        TextField searchField = new TextField();
        searchField.setPromptText("Search...");
        searchField.textProperty().addListener((obs, oldText, newText) -> {
            filteredData.setAll(masterData.stream()
                    .filter(person -> person.getName().toLowerCase().contains(newText.toLowerCase())
                            || person.getStatus().toLowerCase().contains(newText.toLowerCase()))
                    .collect(Collectors.toList()));
        });

        // 添加按钮
        Button addButton = new Button("Add");
        addButton.setOnAction(e -> {
            masterData.add(new Person("New Person", 20, "Active"));
            filteredData.setAll(masterData);
        });

        // 删除按钮
        Button deleteButton = new Button("Delete");
        deleteButton.setOnAction(e -> {
            Person selectedPerson = tableView.getSelectionModel().getSelectedItem();
            if (selectedPerson != null) {
                masterData.remove(selectedPerson);
                filteredData.setAll(masterData);
            } else {
                showAlert(Alert.AlertType.WARNING, "No Selection", "Please select a row to delete.");
            }
        });

        // 修改按钮
        Button editButton = new Button("Edit");
        editButton.setOnAction(e -> {
            Person selectedPerson = tableView.getSelectionModel().getSelectedItem();
            if (selectedPerson != null) {
                // 弹出编辑窗口
                showEditDialog(primaryStage, selectedPerson);
            } else {
                showAlert(Alert.AlertType.WARNING, "No Selection", "Please select a row to edit.");
            }
        });

        // 布局
        HBox controls = new HBox(10, searchField, addButton, deleteButton, editButton);
        VBox root = new VBox(10, controls, tableView);

        Scene scene = new Scene(root, 600, 400);
        primaryStage.setTitle("JavaFX TableView Example");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    // 编辑对话框
    private void showEditDialog(Stage parentStage, Person selectedPerson) {
        // 新建一个编辑窗口
        Stage editDialog = new Stage();
        editDialog.initModality(Modality.WINDOW_MODAL);
        editDialog.initOwner(parentStage);
        editDialog.setTitle("Edit Person");

        // 创建输入框
        TextField nameField = new TextField(selectedPerson.getName());
        TextField statusField = new TextField(selectedPerson.getStatus());

        // 保存按钮
        Button saveButton = new Button("Save");
        saveButton.setOnAction(e -> {
            selectedPerson.setName(nameField.getText());
            selectedPerson.setStatus(statusField.getText());
            // 更新表格
            filteredData.setAll(masterData);
            editDialog.close();
        });

        // 布局
        VBox editLayout = new VBox(10, new Label("Name:"), nameField, new Label("Status:"), statusField, saveButton);
        Scene editScene = new Scene(editLayout, 300, 200);
        editDialog.setScene(editScene);
        editDialog.show();
    }

    // 显示警告框
    private void showAlert(Alert.AlertType alertType, String title, String message) {
        Alert alert = new Alert(alertType);
        alert.setTitle(title);
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

5. 样式自定义

使用 JavaFX CSS 文件可以进一步定制表格的样式。

样式示例
.table-view .column-header-background {
    -fx-background-color: #2c3e50;
}

.table-view .column-header .label {
    -fx-text-fill: white;
}

.table-row-cell:odd {
    -fx-background-color: #f4f4f4;
}

.table-row-cell:even {
    -fx-background-color: #ffffff;
}

在项目中添加 styles.css 并通过 scene.getStylesheets().add("styles.css"); 应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J老熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值