Java 如何在谓词中对FilteredList结果进行优先级排序?
我的应用程序包含一个Java 如何在谓词中对FilteredList结果进行优先级排序?,java,javafx,predicate,Java,Javafx,Predicate,我的应用程序包含一个文本字段和一个列表视图。TextField允许用户输入搜索词,在键入时过滤列表视图的内容 过滤过程将匹配列表视图中每个数据项中的多个字段,如果其中任何字段匹配,则返回结果 然而,我想做的是,让这些结果将匹配某个特定字段的项目优先于其他字段 例如,在下面的MCVE中,我有两项:计算机和纸张。计算机项有一个关键字表示“纸张”,因此搜索“纸张”应返回计算机 但是,由于我还有一个名为Paper的项目,搜索应该返回列表顶部的Paper。不过,在MCVE中,结果仍按字母顺序排列: 问题
文本字段
和一个列表视图
。TextField
允许用户输入搜索词,在键入时过滤列表视图的内容
过滤过程将匹配列表视图
中每个数据项
中的多个字段,如果其中任何字段匹配,则返回结果
然而,我想做的是,让这些结果将匹配某个特定字段的项目优先于其他字段
例如,在下面的MCVE中,我有两项:计算机
和纸张
。计算机
项有一个关键字
表示“纸张”,因此搜索“纸张”应返回计算机
但是,由于我还有一个名为Paper
的项目,搜索应该返回列表顶部的Paper
。不过,在MCVE中,结果仍按字母顺序排列:
问题:我将如何确保与数据项的任何匹配。上面列出了与数据项的匹配项。关键字
编辑:在搜索字段中输入“pap”也应在顶部返回“Paper”,然后是剩余的匹配项,因为部分搜索词部分匹配数据项
名称
MCVE
DataItem.java:
import java.util.List;
public class DataItem {
// Instance properties
private final IntegerProperty id = new SimpleIntegerProperty();
private final StringProperty name = new SimpleStringProperty();
private final StringProperty description = new SimpleStringProperty();
// List of search keywords
private final ObjectProperty<List<String>> keywords = new SimpleObjectProperty<>();
public DataItem(int id, String name, String description, List<String> keywords) {
this.id.set(id);
this.name.set(name);
this.description.set(description);
this.keywords.set(keywords);
}
/**
* Creates a space-separated String of all the keywords; used for filtering later
*/
public String getKeywordsString() {
StringBuilder sb = new StringBuilder();
for (String keyword : keywords.get()) {
sb.append(keyword).append(" ");
}
return sb.toString();
}
public int getId() {
return id.get();
}
public IntegerProperty idProperty() {
return id;
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public String getDescription() {
return description.get();
}
public StringProperty descriptionProperty() {
return description;
}
public List<String> getKeywords() {
return keywords.get();
}
public ObjectProperty<List<String>> keywordsProperty() {
return keywords;
}
@Override
public String toString() {
return name.get();
}
}
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Main extends Application {
// TextField used for filtering the ListView
TextField txtSearch = new TextField();
// ListView to hold our DataItems
ListView<DataItem> dataItemListView = new ListView<>();
// The ObservableList of DataItems
ObservableList<DataItem> dataItems;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// Add the search field and ListView to the layout
root.getChildren().addAll(txtSearch, dataItemListView);
// Build the dataItems List
dataItems = FXCollections.observableArrayList(buildDataItems());
// Add the filter logic
addSearchFilter();
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
/**
* Adds the functionality to filter the list dynamically as search terms are entered
*/
private void addSearchFilter() {
// Wrap the dataItems list in a filtered list, initially showing all items, alphabetically
FilteredList<DataItem> filteredList = new FilteredList<>(
dataItems.sorted(Comparator.comparing(DataItem::getName)));
// Add the predicate to filter the list whenever the search field changes
txtSearch.textProperty().addListener((observable, oldValue, newValue) ->
filteredList.setPredicate(dataItem -> {
// Clear any selection already present
dataItemListView.getSelectionModel().clearSelection();
// If the search field is empty, show all DataItems
if (newValue == null || newValue.isEmpty()) {
return true;
}
// Compare the DataItem's name and keywords with the search query (ignoring case)
String query = newValue.toLowerCase();
if (dataItem.getName().toLowerCase().contains(query)) {
// DataItem's name contains the search query
return true;
} else {
// Otherwise check if any of the search terms match those in the DataItem's keywords
// We split the query by space so we can match DataItems with multiple keywords
String[] searchTerms = query.split(" ");
boolean match = false;
for (String searchTerm : searchTerms) {
match = dataItem.getKeywordsString().toLowerCase().contains(searchTerm);
}
return match;
}
}));
// Wrap the filtered list in a SortedList
SortedList<DataItem> sortedList = new SortedList<>(filteredList);
// Update the ListView
dataItemListView.setItems(sortedList);
}
/**
* Generates a list of sample products
*/
private List<DataItem> buildDataItems() {
List<DataItem> dataItems = new ArrayList<>();
dataItems.add(new DataItem(
1, "School Supplies", "Learn things.",
Arrays.asList("pens", "pencils", "paper", "eraser")));
dataItems.add(new DataItem(
2, "Computer", "Do some things",
Arrays.asList("paper", "cpu", "keyboard", "monitor")));
dataItems.add(new DataItem(
3, "Keyboard", "Type things",
Arrays.asList("keys", "numpad", "input")));
dataItems.add(new DataItem(
4, "Printer", "Print things.",
Arrays.asList("paper", "ink", "computer")));
dataItems.add(new DataItem(
5, "Paper", "Report things.",
Arrays.asList("write", "printer", "notebook")));
return dataItems;
}
}
import java.util.List;
公共类数据项{
//实例属性
private final IntegerProperty id=新的SimpleIntegerProperty();
私有最终StringProperty名称=新SimpleStringProperty();
private final StringProperty description=新SimpleStringProperty();
//搜索关键字列表
private final ObjectProperty关键字=新的SimpleObjectProperty();
公共数据项(int-id、字符串名称、字符串描述、列表关键字){
此.id.set(id);
this.name.set(name);
此.description.set(description);
this.keywords.set(关键字);
}
/**
*创建以空格分隔的所有关键字字符串;用于以后的筛选
*/
公共字符串getKeywordsString(){
StringBuilder sb=新的StringBuilder();
for(字符串关键字:keywords.get()){
sb.append(关键字)。append(“”);
}
使某人返回字符串();
}
公共int getId(){
返回id.get();
}
公共整数属性idProperty(){
返回id;
}
公共字符串getName(){
返回name.get();
}
公共字符串属性nameProperty(){
返回名称;
}
公共字符串getDescription(){
返回description.get();
}
public StringProperty descriptionProperty(){
返回说明;
}
公共列表getKeywords(){
返回关键字.get();
}
public ObjectProperty关键字property(){
返回关键字;
}
@凌驾
公共字符串toString(){
返回name.get();
}
}
Main.java:
import java.util.List;
public class DataItem {
// Instance properties
private final IntegerProperty id = new SimpleIntegerProperty();
private final StringProperty name = new SimpleStringProperty();
private final StringProperty description = new SimpleStringProperty();
// List of search keywords
private final ObjectProperty<List<String>> keywords = new SimpleObjectProperty<>();
public DataItem(int id, String name, String description, List<String> keywords) {
this.id.set(id);
this.name.set(name);
this.description.set(description);
this.keywords.set(keywords);
}
/**
* Creates a space-separated String of all the keywords; used for filtering later
*/
public String getKeywordsString() {
StringBuilder sb = new StringBuilder();
for (String keyword : keywords.get()) {
sb.append(keyword).append(" ");
}
return sb.toString();
}
public int getId() {
return id.get();
}
public IntegerProperty idProperty() {
return id;
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public String getDescription() {
return description.get();
}
public StringProperty descriptionProperty() {
return description;
}
public List<String> getKeywords() {
return keywords.get();
}
public ObjectProperty<List<String>> keywordsProperty() {
return keywords;
}
@Override
public String toString() {
return name.get();
}
}
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Main extends Application {
// TextField used for filtering the ListView
TextField txtSearch = new TextField();
// ListView to hold our DataItems
ListView<DataItem> dataItemListView = new ListView<>();
// The ObservableList of DataItems
ObservableList<DataItem> dataItems;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// Add the search field and ListView to the layout
root.getChildren().addAll(txtSearch, dataItemListView);
// Build the dataItems List
dataItems = FXCollections.observableArrayList(buildDataItems());
// Add the filter logic
addSearchFilter();
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
/**
* Adds the functionality to filter the list dynamically as search terms are entered
*/
private void addSearchFilter() {
// Wrap the dataItems list in a filtered list, initially showing all items, alphabetically
FilteredList<DataItem> filteredList = new FilteredList<>(
dataItems.sorted(Comparator.comparing(DataItem::getName)));
// Add the predicate to filter the list whenever the search field changes
txtSearch.textProperty().addListener((observable, oldValue, newValue) ->
filteredList.setPredicate(dataItem -> {
// Clear any selection already present
dataItemListView.getSelectionModel().clearSelection();
// If the search field is empty, show all DataItems
if (newValue == null || newValue.isEmpty()) {
return true;
}
// Compare the DataItem's name and keywords with the search query (ignoring case)
String query = newValue.toLowerCase();
if (dataItem.getName().toLowerCase().contains(query)) {
// DataItem's name contains the search query
return true;
} else {
// Otherwise check if any of the search terms match those in the DataItem's keywords
// We split the query by space so we can match DataItems with multiple keywords
String[] searchTerms = query.split(" ");
boolean match = false;
for (String searchTerm : searchTerms) {
match = dataItem.getKeywordsString().toLowerCase().contains(searchTerm);
}
return match;
}
}));
// Wrap the filtered list in a SortedList
SortedList<DataItem> sortedList = new SortedList<>(filteredList);
// Update the ListView
dataItemListView.setItems(sortedList);
}
/**
* Generates a list of sample products
*/
private List<DataItem> buildDataItems() {
List<DataItem> dataItems = new ArrayList<>();
dataItems.add(new DataItem(
1, "School Supplies", "Learn things.",
Arrays.asList("pens", "pencils", "paper", "eraser")));
dataItems.add(new DataItem(
2, "Computer", "Do some things",
Arrays.asList("paper", "cpu", "keyboard", "monitor")));
dataItems.add(new DataItem(
3, "Keyboard", "Type things",
Arrays.asList("keys", "numpad", "input")));
dataItems.add(new DataItem(
4, "Printer", "Print things.",
Arrays.asList("paper", "ink", "computer")));
dataItems.add(new DataItem(
5, "Paper", "Report things.",
Arrays.asList("write", "printer", "notebook")));
return dataItems;
}
}
导入javafx.application.application;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.collections.transformation.FilteredList;
导入javafx.collections.transformation.SortedList;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.ListView;
导入javafx.scene.control.TextField;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.Comparator;
导入java.util.List;
公共类主扩展应用程序{
//用于筛选ListView的TextField
TextField txtSearch=新建TextField();
//ListView保存我们的数据项
ListView dataItemListView=新建ListView();
//数据项的可观察列表
可观察列表数据项;
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
//简单接口
VBox根=新的VBox(10);
根部设置对齐(位置中心);
根。设置填充(新插图(10));
//将搜索字段和列表视图添加到布局中
root.getChildren().addAll(txtSearch,dataItemListView);
//构建数据项列表
dataItems=FXCollections.observableArrayList(buildDataItems());
//添加过滤器逻辑
addSearchFilter();
//上台
primaryStage.setScene(新场景(根));
初级阶段。设置标题(“样本”);
primaryStage.show();
}
/**
*添加在输入搜索词时动态筛选列表的功能
*/
私有void addSearchFilter(){
//将dataItems列表包装在筛选列表中,最初按字母顺序显示所有项目
FilteredList FilteredList=新的FilteredList(
dataItems.sorted(Comparator.comparing(DataItem::getName));
//添加谓词以在搜索字段更改时过滤列表
txtSearch.textProperty().addListener((可观察、旧值、新值)->
setPredicate(数据项->{
//清除所有已存在的选项
dataItemListView.getSelectionModel().clearSelection();
//如果搜索字段为空,则显示所有数据项
if(newValue==null | | newValue.isEmpty()){
返回true;
}
//将数据项的名称和关键字与搜索查询进行比较(忽略大小写)
字符串查询=newValue.toLowerCase();
if(dataItem.getName().toLowerCase().contains(查询)){
//DataItem的名称包含搜索查询
返回true;
}否则{
private void addSearchFilter() {
FilteredList<DataItem> filteredList = new FilteredList<>(dataItems);
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> filteredList.setPredicate(dataItem -> {
dataItemListView.getSelectionModel().clearSelection();
if (newValue == null || newValue.isEmpty()) {
return true;
}
String query = newValue.toLowerCase();
if (dataItem.getName().toLowerCase().contains(query)) {
return true;
} else {
String[] searchTerms = query.split(" ");
boolean match = false;
for (String searchTerm : searchTerms) {
match = dataItem.getKeywordsString().toLowerCase().contains(searchTerm);
}
return match;
}
}));
SortedList<DataItem> sortedList = new SortedList<>(filteredList);
Comparator<DataItem> byName = new Comparator<DataItem>() {
@Override
public int compare(DataItem o1, DataItem o2) {
String searchKey = txtSearch.getText().toLowerCase();
int item1Score = findScore(o1.getName().toLowerCase(), searchKey);
int item2Score = findScore(o2.getName().toLowerCase(), searchKey);
if (item1Score > item2Score) {
return -1;
}
if (item2Score > item1Score) {
return 1;
}
return 0;
}
private int findScore(String itemName, String searchKey) {
int sum = 0;
if (itemName.startsWith(searchKey)) {
sum += 2;
}
if (itemName.contains(searchKey)) {
sum += 1;
}
return sum;
}
};
sortedList.setComparator(byName);
dataItemListView.setItems(sortedList);
}