You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX MVC架构下多路径更新的ListView如何实现动态过滤?

核心问题说明

  1. Controller中创建的FilteredList是initialize方法内的局部变量,绑定的是从ListView items里复制出来的独立列表,和后续剪贴板新增的内容完全没有关联,自然无法生效。
  2. 剪贴板内容变更的回调线程不是JavaFX应用线程,直接修改UI会有线程安全问题,大概率会抛异常。
  3. 你直接操作ListView的items属性,而没有把ListView和FilteredList绑定,过滤规则自然不会作用到展示内容上。

具体修改步骤

1. Controller 代码修改

把数据源、FilteredList提为全局成员,绑定ListView到FilteredList,新增公共方法用来添加剪贴板内容:

package minimalsandbox;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.*;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import javafx.scene.control.TextField;
import java.net.URL;
import java.util.ResourceBundle;


public class Controller implements Initializable {

    @FXML
    private Button myButton01;

    @FXML
    public ListView<String> mylistviewvar;

    @FXML
    private ToggleButton myToggleBut;

    @FXML
    private AnchorPane myAnchorPane;

    @FXML
    private TextField searchFieldvar;

    // 全局数据源,所有新增内容都往这里加
    private final ObservableList<String> dataSource = FXCollections.observableArrayList();
    // 全局过滤列表
    private FilteredList<String> filteredData;

    // 给Main调用的新增剪贴板内容的方法
    public void addClipboardContent(String content) {
        dataSource.add(0, content);
    }

    @FXML
    void myButton01myEventClicked(MouseEvent event) {
        System.out.println("hi there !");

        // to put string INTO clipboard
        Clipboard clipboard = Clipboard.getSystemClipboard();
        ClipboardContent content = new ClipboardContent();
        content.putString("Some text");
        clipboard.setContent(content);
        // to copy from clipboard
        String fromclipboardstr = Clipboard.getSystemClipboard().getString();
        System.out.println(fromclipboardstr);
    }

    @FXML
    void myToggleButEventSB(MouseEvent event) {
        if (myToggleBut.isSelected()) {
            System.out.println("is ON");
            Stage stage = (Stage) myAnchorPane.getScene().getWindow();
            stage.setAlwaysOnTop(true);
        }else {
            System.out.println("is OFF");
            Stage stage = (Stage) myAnchorPane.getScene().getWindow();
            stage.setAlwaysOnTop(false);
        }
    }

    @FXML
    void myonKeyTyped(KeyEvent event) {
        System.out.println("input changed");
        // 这里不用加额外逻辑,textProperty的监听已经处理过滤了
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        // 绑定过滤列表到数据源
        filteredData = new FilteredList<>(dataSource, s -> true);
        // 把ListView的items设为过滤后的列表
        mylistviewvar.setItems(filteredData);

        // 搜索框文本变更监听,动态改过滤规则
        searchFieldvar.textProperty().addListener(obs->{
            String filter = searchFieldvar.getText();
            if(filter == null || filter.trim().isEmpty()) {
                filteredData.setPredicate(s -> true);
            }
            else {
                filteredData.setPredicate(s -> s.contains(filter));
            }
        });
    }
}

2. Main 代码修改

新增Platform.runLater包裹UI更新逻辑,调用Controller的公共方法添加内容,删掉没用的局部ObservableList创建:

package minimalsandbox;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.Clipboard;
import javafx.stage.Screen;
import javafx.stage.Stage;

public class Main extends Application  {

    @Override
    public void start(Stage primaryStage) throws Exception {

        FXMLLoader loader =new FXMLLoader();
        loader.setLocation(Main.class.getResource("/minimalsandbox/View.fxml"));
        Parent root = loader.load();
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);

        primaryStage.setX(200);
        primaryStage.setY(500);
        Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
        double x = bounds.getMinX() + (bounds.getWidth() - scene.getWidth()) * 0.2;
        double y = bounds.getMinY() + (bounds.getHeight() - scene.getHeight()) * 0.55;
        primaryStage.setX(x);
        primaryStage.setY(y);

        final Clipboard systemClipboard = Clipboard.getSystemClipboard();
        Controller controller = loader.getController();
        new com.sun.glass.ui.ClipboardAssistance(com.sun.glass.ui.Clipboard.SYSTEM) {
            @Override
            public void contentChanged() {
                System.out.print("System clipboard content changed: ");
                if ( systemClipboard.hasImage() ) {
                    System.out.println("image");
                } else if ( systemClipboard.hasString() ) {
                    System.out.println("string");
                    String fromclipboard = Clipboard.getSystemClipboard().getString();
                    // 必须包在Platform.runLater里,否则非FX线程改UI会报错
                    Platform.runLater(() -> {
                        controller.addClipboardContent(fromclipboard);
                    });
                } else if ( systemClipboard.hasFiles() ) {
                    System.out.println("files");
                }
            }
        };

        primaryStage.show();
        System.out.println("current thread: " + Thread.currentThread().getName());
    }

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

3. View.fxml 代码不需要修改,直接用原来的即可。


疑问解答

  1. 动态填充的列表怎么传入FilteredList:不需要手动传,只要FilteredList绑定的是同一个ObservableList数据源,你往数据源里新增/删除内容的时候,FilteredList会自动感知变化,触发过滤规则更新展示内容。
  2. 不需要在myonKeyTyped事件里写过滤逻辑,你原来用的textProperty().addListener更可靠,能覆盖所有文本变更场景,包括粘贴输入、中文输入法输入、右键剪切/删除等keyTyped捕获不到的情况。
  3. 不要直接操作ListView的items属性,所有数据变更都操作底层的数据源dataSource即可,视图层会自动同步。

内容的提问来源于stack exchange,提问作者progLearn00

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 13:06:04