首页 > Java > java教程 > 正文

JavaFX TableView筛选与搜索结果动态获取教程

霞舞
发布: 2025-11-07 15:31:01
原创
555人浏览过

JavaFX TableView筛选与搜索结果动态获取教程

本教程详细讲解如何在javafx应用中实现tableview的数据筛选功能,并通过文本输入框和按钮交互,动态获取筛选后的数据。文章将涵盖filteredlist和sortedlist的使用、文本监听器实现实时筛选,以及在按钮点击事件中准确获取当前tableview中显示的数据项,并探讨如何将这些数据传递给其他fxml视图进行进一步处理。

在JavaFX应用程序中,TableView 是一个功能强大的组件,常用于展示大量结构化数据。当数据量较大时,提供搜索和筛选功能可以极大地提升用户体验。本教程将指导您如何结合 TextField 和 Button,实现对 TableView 数据的动态筛选,并在用户点击搜索按钮后,获取并处理筛选后的结果。

核心概念:JavaFX TableView的筛选机制

JavaFX提供了一套灵活的机制来管理和筛选 TableView 的数据。主要涉及到以下几个关键类:

  1. ObservableList: 存储 TableView 的原始数据。任何对该列表的修改都会自动反映在 TableView 上。
  2. FilteredList: 包装一个 ObservableList,并根据一个 Predicate 对象来过滤数据。当 Predicate 发生变化时,FilteredList 会自动更新其内容。
  3. SortedList: 包装一个 FilteredList (或任何 ObservableList),并根据 TableView 的排序规则来排序数据。它允许用户通过点击列头进行排序。

通过将 FilteredList 绑定到 TextField 的文本变化监听器上,我们可以实现实时搜索功能。

准备工作:FXML布局与控制器骨架

首先,我们需要一个包含 TableView、TextField 和 Button 的FXML布局文件。

立即学习Java免费学习笔记(深入)”;

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<GridPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.TableController">
    <columnConstraints>
        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
    </columnConstraints>
    <rowConstraints>
        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
    </rowConstraints>
    <HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" spacing="10.0">
        <TextField fx:id="mTextField" prefHeight="28.0" prefWidth="366.0" promptText="输入ID搜索" />
        <Button fx:id="searchBtn" mnemonicParsing="false" onAction="#handleSearch" prefHeight="26.0" prefWidth="166.0" text="搜索" />
    </HBox>
    <TableView fx:id="mTableView" prefHeight="451.0" prefWidth="929.0" GridPane.rowIndex="1">
        <columns>
            <TableColumn fx:id="idColumn" prefWidth="75.0" text="ID" />
            <TableColumn fx:id="nameColumn" prefWidth="75.0" text="Name" />
            <TableColumn fx:id="salColumn" prefWidth="75.0" text="Salary" />
        </columns>
    </TableView>
</GridPane>
登录后复制

接下来,是对应的控制器骨架和数据模型。

package com.example;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;

import java.net.URL;
import java.util.ResourceBundle;
import java.util.function.Predicate;

public class TableController implements Initializable {

    @FXML
    private TableView<Employee> mTableView;
    @FXML
    private TableColumn<Employee, Integer> idColumn;
    @FXML
    private TableColumn<Employee, String> nameColumn;
    @FXML
    private TableColumn<Employee, Double> salColumn; // 假设Salary是Double类型
    @FXML
    private TextField mTextField;
    @FXML
    private Button searchBtn;

    private ObservableList<Employee> mList = FXCollections.observableArrayList();
    private FilteredList<Employee> filteredList;
    private SortedList<Employee> sortedList;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        // 初始化列的单元格值工厂
        idColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        salColumn.setCellValueFactory(new PropertyValueFactory<>("salary"));

        // 模拟加载数据
        loadRecords();

        // 初始化FilteredList和SortedList
        filteredList = new FilteredList<>(mList, b -> true); // 初始显示所有数据
        sortedList = new SortedList<>(filteredList);
        sortedList.comparatorProperty().bind(mTableView.comparatorProperty()); // 绑定排序属性
        mTableView.setItems(sortedList); // 将排序列表设置给TableView

        // 添加TextField的文本变化监听器,实现实时筛选
        mTextField.textProperty().addListener((observable, oldValue, newValue) -> {
            filteredList.setPredicate(createSearchPredicate(newValue));
        });
    }

    /**
     * 模拟从数据库或其他源加载数据
     */
    private void loadRecords() {
        mList.add(new Employee(101, "Alice", 5000.0));
        mList.add(new Employee(102, "Bob", 6000.0));
        mList.add(new Employee(103, "Charlie", 7500.0));
        mList.add(new Employee(104, "David", 4500.0));
        mList.add(new Employee(201, "Eve", 8000.0));
        mList.add(new Employee(202, "Frank", 9000.0));
    }

    /**
     * 根据搜索关键字创建Predicate
     * @param searchText 搜索文本
     * @return Predicate<Employee>
     */
    private Predicate<Employee> createSearchPredicate(String searchText) {
        return employee -> {
            // 如果搜索文本为空,显示所有数据
            if (searchText == null || searchText.isEmpty() || searchText.isBlank()) {
                return true;
            }

            String lowerCaseSearchText = searchText.toLowerCase();

            // 检查员工ID是否包含搜索关键字
            if (String.valueOf(employee.getId()).toLowerCase().contains(lowerCaseSearchText)) {
                return true;
            }
            // 检查员工姓名是否包含搜索关键字
            if (employee.getName().toLowerCase().contains(lowerCaseSearchText)) {
                return true;
            }
            // 可以添加更多字段的检查,例如薪水
            // if (String.valueOf(employee.getSalary()).toLowerCase().contains(lowerCaseSearchText)) {
            //     return true;
            // }

            return false; // 不匹配
        };
    }

    @FXML
    public void handleSearch(ActionEvent event) {
        // 此方法将在下面详细实现
    }
}
登录后复制

Employee数据模型:

package com.example;

import javafx.beans.property.*;

public class Employee {
    private final IntegerProperty id;
    private final StringProperty name;
    private final DoubleProperty salary;

    public Employee(int id, String name, double salary) {
        this.id = new SimpleIntegerProperty(id);
        this.name = new SimpleStringProperty(name);
        this.salary = new SimpleDoubleProperty(salary);
    }

    public int getId() {
        return id.get();
    }

    public IntegerProperty idProperty() {
        return id;
    }

    public void setId(int id) {
        this.id.set(id);
    }

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

    public StringProperty nameProperty() {
        return name;
    }

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

    public double getSalary() {
        return salary.get();
    }

    public DoubleProperty salaryProperty() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary.set(salary);
    }
}
登录后复制

获取筛选后的数据:按钮点击事件处理

当用户在 TextField 中输入搜索词并点击“搜索”按钮时,我们通常希望获取当前 TableView 中显示(即已经过筛选和排序)的数据。

纳米搜索
纳米搜索

纳米搜索:360推出的新一代AI搜索引擎

纳米搜索 30
查看详情 纳米搜索

关键在于 mTableView.getItems() 方法。无论 TableView 绑定的是原始 ObservableList、FilteredList 还是 SortedList,mTableView.getItems() 总是返回当前 TableView 实际显示的数据列表。因此,如果您的 TableView 已经绑定了 SortedList(它又包装了 FilteredList),那么 getItems() 返回的就是经过筛选和排序后的数据。

在 handleSearch 方法中,您可以这样获取数据:

    @FXML
    public void handleSearch(ActionEvent event) {
        // 获取当前TableView中显示的所有数据项
        ObservableList<Employee> currentDisplayedEmployees = mTableView.getItems();

        if (currentDisplayedEmployees.isEmpty()) {
            System.out.println("没有找到匹配的员工。");
            // 可以显示一个提示信息给用户
            // Alert alert = new Alert(Alert.AlertType.INFORMATION, "没有找到匹配的员工!");
            // alert.showAndWait();
        } else {
            // 假设我们只关心第一个匹配项
            Employee firstResult = currentDisplayedEmployees.get(0);
            System.out.println("搜索结果的第一个员工ID: " + firstResult.getId() + ", 姓名: " + firstResult.getName());

            // 如果需要,您可以遍历所有结果
            // for (Employee emp : currentDisplayedEmployees) {
            //     System.out.println("匹配员工: " + emp.getName());
            // }

            // 进一步处理:例如,加载另一个FXML并传递这个员工对象
            // loadAnotherFxml(firstResult);
        }
    }
登录后复制

数据传递与多FXML场景

在实际应用中,您可能需要将筛选出的数据(例如 firstResult)传递给另一个FXML视图的控制器。这通常通过 FXMLLoader 来实现。

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;

// ... 在TableController中 ...

private void loadAnotherFxml(Employee employeeToPass) {
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/example/detailView.fxml"));
        Parent root = loader.load();

        // 获取目标控制器的实例
        DetailController detailController = loader.getController();
        // 调用目标控制器的方法来设置数据
        detailController.initData(employeeToPass);

        Stage stage = new Stage();
        stage.setScene(new Scene(root));
        stage.setTitle("员工详情");
        stage.show();

        // 如果需要关闭当前窗口
        // ((Stage) mTableView.getScene().getWindow()).close();

    } catch (IOException e) {
        e.printStackTrace();
        // 错误处理,例如显示一个警告框
        // Alert alert = new Alert(Alert.AlertType.ERROR, "无法加载详情视图:" + e.getMessage());
        // alert.showAndWait();
    }
}
登录后复制

对应的 DetailController 示例:

package com.example;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class DetailController {

    @FXML
    private Label idLabel;
    @FXML
    private Label nameLabel;
    @FXML
    private Label salaryLabel;

    public void initData(Employee employee) {
        if (employee != null) {
            idLabel.setText("ID: " + employee.getId());
            nameLabel.setText("姓名: " + employee.getName());
            salaryLabel.setText("薪水: " + employee.getSalary());
        }
    }
}
登录后复制

以及 detailView.fxml 示例:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox alignment="CENTER" spacing="10.0" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.DetailController">
    <Label fx:id="idLabel" text="ID:" />
    <Label fx:id="nameLabel" text="姓名:" />
    <Label fx:id="salaryLabel" text="薪水:" />
</VBox>
登录后复制

注意事项与最佳实践

  1. 处理空结果集: 在 handleSearch 方法中,务必检查 currentDisplayedEmployees 是否为空。如果为空,应向用户提供适当的反馈(例如,弹出一个提示框)。
  2. 处理多结果集: 如果筛选后有多个结果,您需要决定如何处理。
    • 选择第一个: 如示例所示,直接获取 get(0)。
    • 全部处理: 遍历整个 currentDisplayedEmployees 列表。
    • 用户选择: 如果希望用户从多个结果中手动选择,可以考虑在 TableView 中添加一个选择列,或者弹出一个新的 Dialog 让用户进行选择。
  3. 性能优化: 对于非常大的数据集(数万甚至数十万条记录),实时筛选可能会有性能问题。可以考虑:
    • 延迟搜索: 使用 Platform.runLater 或 Timeline 在用户停止输入一段时间后才执行筛选。
    • 后端搜索: 将搜索逻辑移到后端服务,只加载匹配的数据。
  4. 错误处理: 在加载新的FXML文件时,FXMLLoader.load() 可能会抛出 IOException。务必捕获并处理这些异常,向用户提供友好的错误信息。
  5. Predicate逻辑: createSearchPredicate 方法中的逻辑可以根据您的需求进行扩展。例如,可以支持多个字段的组合搜索,或者更复杂的匹配规则(如正则表达式)。

总结

通过本教程,您应该已经掌握了如何在JavaFX中实现 TableView 的动态筛选功能。核心在于利用 FilteredList 和 SortedList 来管理数据视图,并通过 TextField 的文本监听器实时更新筛选条件。在按钮点击事件中,mTableView.getItems() 方法是获取当前筛选后数据集合的关键。结合 FXMLLoader,您可以轻松地将这些数据传递到其他视图,构建更加复杂和交互性强的JavaFX应用程序。

以上就是JavaFX TableView筛选与搜索结果动态获取教程的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号