如何使用 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<E>
过滤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中使用模型类添加动态控件