如何使用 MVC 模型动态过滤 javafx 中的列表视图控件,同时以多种方式更新? [关闭]

Posted

技术标签:

【中文标题】如何使用 MVC 模型动态过滤 javafx 中的列表视图控件,同时以多种方式更新? [关闭]【英文标题】:How could I dynamically filter a listview control in javafx using the MVC model while is updated in more than one way? [closed] 【发布时间】:2022-01-09 15:19:13 【问题描述】:

我正在使用 3 个文件:View.fxml、Main 和 Controller。

我找到了一种方法,可以在更新剪贴板时(复制字符串时)使用存储在剪贴板中的字符串来更新列表视图控件。

我无法实现的是,我还希望在用户更新文本字段时更新/过滤相同的列表。我不确定如何设置可观察列表、谓词或在哪个文件、主文件或控制器文件中。

我添加我的代码:

主要



import Controller.Controller01;
import Model.Clip;
import Model.ClipboardListener;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.ObjectExpression;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.input.Clipboard;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.concurrent.Task;

import java.util.stream.IntStream;

public class Main extends Application  


    @Override
    public void start(Stage primaryStage) throws Exception 

        FXMLLoader loader =new FXMLLoader();
        loader.setLocation(Main.class.getResource("/View/View01.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);


// longrunning operation runs on different thread
        Thread thread = new Thread(new Runnable() 
            String oldString = "";
            @Override
            public void run() 

                System.out.println("pulse in run 1 ");
                System.out.println("crrent thread: " + Thread.currentThread().getName());


                Runnable updater = new Runnable() 


                    @Override
                    public void run() 
                        //updateview();

                       //    run   ends ---------------------------------------------------

                ;    //    updater   ends ---------------------------------------------------






            

        );   //  thread runnable ends -------------------------------------------------------
        // don't let thread prevent JVM shutdown
        thread.setDaemon(true);
        thread.start();





// --------------------------------------------------------------------------------------------------------------------
        //  in main, clipboard listener, I'm unsure how to update the listivew here if the textfield changes
// --------------------------------------------------------------------------------------------------------------------

        final Clipboard systemClipboard = Clipboard.getSystemClipboard();
        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");
                    //System.out.println(Clipboard.getSystemClipboard().getString());
                    System.out.println("current thread: " + Thread.currentThread().getName());


                   // controller.mylistviewvar.setItems(data);


                    Controller.Controller01 controller = loader.getController();           // works1
                    String fromclipboard = Clipboard.getSystemClipboard().getString();


                    ObservableList<String> items = FXCollections.observableArrayList();
                    

                    //controller.mylistviewvar.getItems().add(0,fromclipboard);                  // works1


                 else if ( systemClipboard.hasFiles() ) 
                    System.out.println("files");
                
            
        ;
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------


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




      // start stage ends --------------------------------------------

    

//  Mythread01   ends -----------------------------------




    public final Controller01 controller = new Controller01();

 // Main ends

控制器

package Controller;

import Model.Clip;
import Model.ClipboardListener;
import com.sun.tools.javac.Main;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.ToggleButton;
import javafx.scene.effect.DropShadow;
import javafx.scene.input.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.input.Clipboard;
import javafx.stage.Stage;
import javafx.scene.control.TextField;

import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

public class Controller01 implements Initializable 


    @FXML
    private Button myButton01;

    @FXML
    public ListView<String> mylistviewvar;

    public void setMylistviewvar(String listviewvar) 
        mylistviewvar.getItems().add(listviewvar);
    

    @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);


        //  ---------   alert dialogs
//        Alert alert = new Alert(Alert.AlertType.INFORMATION);
//        alert.setTitle("Information Dialog");
//        //alert.setHeaderText("Look, an Information Dialog");
//        alert.setContentText("I have a great message for you!");
//        alert.showAndWait();

//        Alert alert = new Alert(Alert.AlertType.INFORMATION);
//        alert.setTitle("Information Dialog");
//        alert.setHeaderText(null);
//        alert.setContentText("I have a great message for you!");
//        alert.showAndWait();




      // button click ends
    @FXML
    private ToggleButton myToggleBut;


// using this template methods in main can be accessed
//    @FXML protected void handleSubmitButtonRegister() throws IOException
//        //
//        //Here I want to invoke gotoRegister
//        FXMLExampleMVC.getInstance().gotoRegister();
//    

    @FXML
    private AnchorPane myAnchorPane;


    @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);
        
    


//    public void testingcopyaction(Scene scene)
//
//        ObservableList<Clip> list = FXCollections.observableArrayList();
//        scene.getAccelerators().put(copyCombination, () -> 
//            if (!list.isEmpty()) 
//                ClipboardContent content = new ClipboardContent();
//                content.putString(list.getSelectedItem().getClip());
//                // original:
//                // content.putString(table.getSelectionModel().getSelectedItem().getClip());
//                Clipboard.getSystemClipboard().setContent(content);
//            
//        );
//
//
//    
//
//    private static final KeyCodeCombination copyCombination = new KeyCodeCombination(KeyCode.C, KeyCombination.CONTROL_ANY);
//
//    private static final KeyCodeCombination pasteCombination = new KeyCodeCombination(KeyCode.V, KeyCodeCombination.CONTROL_ANY);


    // ------------------------- learned that copying from selected cell/item



//    public void updateview()
//        ObservableList<Clip> list = FXCollections.observableArrayList();
//        ListView<String> mylistviewvar = new ListView<>(list);
//        String fromclipboard = Clipboard.getSystemClipboard().getString();
//
//
//
//        mylistviewvar.getItems().add(fromclipboard);
//
//
//
//    


    @FXML
    private TextField searchFieldvar;

    public TextField getSearchFieldvar() 
        return searchFieldvar;
    

    public void setSearchFieldvar(TextField searchFieldvar) 
        this.searchFieldvar = searchFieldvar;
    

    @FXML
    void myonKeyTyped(KeyEvent event) 


     System.out.println("input changed");









//        ObservableList<String> list = FXCollections.observableArrayList(mylistviewvar.getItems());
//
//        FilteredList<String> filteredList = new FilteredList<String>(list);
//        filteredList.setPredicate((e) -> true);
//
//        // ListView<String> listView = new ListView<>(filteredList);
//
//
//
//        //TextField textField = new TextField();
//        searchFieldvar.textProperty().addListener((e) -> filteredList.setPredicate((v) -> (searchFieldvar.getText() == null || searchFieldvar.getText().length() == 0 || v.startsWith(searchFieldvar.getText()))));
//
//        mylistviewvar.setItems(filteredList);












//        FilteredList<String> filteredData = new FilteredList<>(mylistviewvar.getItems(), s -> true);
//
//        String filter = searchFieldvar.getText();
//
//      // System.out.println("changed");
//       if(filter == null || filter.length() == 0) 
//           filteredData.setPredicate(s -> true);
//       
//       else 
//           filteredData.setPredicate(s -> s.contains(filter));
//       

    








    public void applyClipboardPolling() 
        ObservableList<Clip> list = FXCollections.observableArrayList();
        ListView<Clip> mylistviewvar = new ListView<>(list);

        final Clipboard clipboard = Clipboard.getSystemClipboard();
        new com.sun.glass.ui.ClipboardAssistance(com.sun.glass.ui.Clipboard.SYSTEM) 
            @Override
            public void contentChanged() 
                // called every time system clipboard is changed
                // if the clipboard has a new String, add it to the TableView
                if (clipboard.hasString()) 

                    String toBeCopied = clipboard.getString();
                    // If the user hasn't selected anything in the table, we can safely add item
                    //
                    // If the user has selected something, and the selected clip differs from
                    // the String being copied, then we can add it.

                    // ObservableList<String> listview = FXCollections.observableArrayList("john","jane");
                    Clip clip = new Clip();
                    clip.setClip(clipboard.getString());
                    mylistviewvar.getItems().add(clip);


                    if (mylistviewvar.getSelectionModel().isEmpty() || !mylistviewvar.getSelectionModel().getSelectedItem().getClip().equals(toBeCopied)) 
                        Clip clip1 = new Clip();
                        clip1.setClip(clipboard.getString());
                        Clip lastCopied = (mylistviewvar.getItems().size() > 1) ? mylistviewvar.getItems().get(mylistviewvar.getItems().size() - 1) : null;
                        if (lastCopied != null && lastCopied.getClip().equals(toBeCopied)) 
                            // sometimes the contentChanged() method is called without the
                            // content actually having changed, don't add in this case
                            return;
                        
                        mylistviewvar.getItems().add(clip1);
                    
                
            
        ;
    




   @Override
   public void initialize(URL url, ResourceBundle resourceBundle) 

//       ClipboardListener listener = new ClipboardListener();
//       listener.setEntryListener(this);
//       listener.start();


      // FilteredList<String> filteredList = new FilteredList<String>(mylistviewvar.getItems());
      // filteredList.setPredicate((e) -> true);


       ObservableList<String> data = FXCollections.observableArrayList(mylistviewvar.getItems());

       FilteredList<String> filteredData = new FilteredList<>(data, s -> true);


       searchFieldvar.textProperty().addListener(obs->

           String filter = searchFieldvar.getText();
           if(filter == null || filter.length() == 0) 
               filteredData.setPredicate(s -> true);
           
           else 
               filteredData.setPredicate(s -> s.contains(filter));
           
       );


















     //  initializable ends -------------------------------




//    @Override
//    public void onCopy(String data) 
//        mylistviewvar.getItems().add(0,  data);
//    





 // Controller01 ends

View.fxml

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane fx:id="myAnchorPane" prefHeight="374.0" prefWidth="1188.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.Controller01">
   <children>
      <Button fx:id="myButton01" layoutX="42.0" layoutY="28.0" mnemonicParsing="false" onMouseClicked="#myButton01myEventClicked" text="Get clipboard type" />
      <ListView fx:id="mylistviewvar" layoutX="14.0" layoutY="133.0" prefHeight="229.0" prefWidth="561.0" />
      <TextField fx:id="searchFieldvar" layoutX="157.0" layoutY="89.0" onKeyTyped="#myonKeyTyped" prefHeight="37.0" prefWidth="297.0" />
      <TextArea layoutX="583.0" layoutY="133.0" prefHeight="229.0" prefWidth="591.0" />
      <ToggleButton fx:id="myToggleBut" layoutX="526.0" layoutY="16.0" mnemonicParsing="false" onMouseClicked="#myToggleButEventSB" prefHeight="25.0" prefWidth="98.0" text="On Top" />
   </children>
</AnchorPane>

【问题讨论】:

您能分享一下您的Clip 课程吗? 我还希望在用户更新文本字段时更新/过滤相同的列表。我认为不需要数百行代码来演示它。请发帖minimal reproducible example。 我投票结束这个问题,因为发布的代码很长。需要 MRE。 将其简化为minimal reproducible example - 没有人愿意涉足大量不相关的代码。还要保持专注,您似乎在这里遇到了几个问题。确保您正确格式化代码(不需要的大量垂直空格,以及如此多的注释代码 - 您可能更接近看起来的最小示例:)。并且:坚持 java 命名约定(包名应该小写) 您已经在使用动态工作的FilteredList,当底层可观察列表更新时更新其内容,所以我不确定您的问题是什么(除了观察之外,我没有阅读您的代码FilteredList 的用户)。举个简单的例子,你可以去掉 fxml 和控制器,以及所有与线程和剪贴板有关的东西,只需要一个简单的主应用程序,它使用可观察列表和过滤列表来演示问题。它甚至不需要有一个 UI,尽管一个简单的 UI 就可以了。 【参考方案1】:

以下是如何使用FilteredList&lt;E&gt; 过滤ListView 显示内容的示例:

List<String> names = Arrays.asList("John", "Winston", "Viggo Tarasov", "Cassian", "Bowery King", "Sofia");

// You can add items from other sources to this list
ObservableList<String> sourceList = FXCollections.observableArrayList(names);

// Create a FilteredList with your source list
FilteredList<String> filteredNames = new FilteredList<>(sourceList);

// Bind the predicate property of the filtered list to the text field.
// The following line tells the list to update the filtered items when the text field's text changes
filteredNames.predicateProperty().bind(Bindings.createObjectBinding(() -> name -> name.contains(searchField.getText()), searchField.textProperty()));

// Use the filtered list in the list view
namesListView.setItems(filteredNames);

【讨论】:

以上是关于如何使用 MVC 模型动态过滤 javafx 中的列表视图控件,同时以多种方式更新? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有循环或jquery的mvc中使用模型类添加动态控件

JavaFX项目结构

如何在请求过滤器中的 ViewResult 上设置视图模型?

如何从 JavaFX 中的另一个类动态创建舞台

MVC - Swing 与 JavaFX 的实现

如何将 SVG 中的 feGaussianBlur 转换为 JavaFX 中的 GaussianBlur 效果?