我正在尝试使用多个选择框为我的 ListView 创建一个过滤函数,但我不知道如何做到这一点,因为我对 JavaFX 还很陌生。
我做了一些研究,听说需要使用过滤列表,但大多数在线示例仅围绕使用文本字段。
这是我的 Controller 类
@FXML
private ChoiceBox<String> genre;
@FXML
private ChoiceBox<String> branch;
@FXML
private ChoiceBox<String> status;
@FXML
private ChoiceBox<String> company;
@FXML
private ListView<Movie> listView;
private ObservableList<Movie> movieList = FXCollections.observableArrayList();
private FilteredList<Movie> filteredData = new FilteredList<>(movieList, s -> true);
public Controller() {
vehicleList.addAll(
new Movie("Horror" ,"IT", ,"Branch1", "Released", "Warner Bros"),
new Movie("Action","John Wick 3" ,"Branch2", "Coming Soon", "Summit Entertainment")
);
@Override
public void initialize(URL location, ResourceBundle resources) {
//I am planning to implement the filter here in the initialize method
listView.setItems(filteredData);
listView.setCellFactory(movieListView -> new MovieListViewCell());
}
这是 MovieListViewCell 类
@FXML
private Label genre;
@FXML
private Label status;
@FXML
private GridPane gridPane;
private FXMLLoader mLLoader;
@Override
protected void updateItem(Movie movie, boolean empty) {
super.updateItem(vehicle, empty);
if(empty || vehicle == null) {
setText(null);
setGraphic(null);
} else {
if (mLLoader == null) {
mLLoader = new FXMLLoader(getClass().getResource("/application/ListCell.fxml"));
mLLoader.setController(this);
try {
mLLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
genre.setText(String.valueOf(vehicle.getMovie_Genre()));
status.setText(String.valueOf(vehicle.getMovie_Status()));
setText(null);
setGraphic(gridPane);
}
}
这是我运行整个 UI 的主要方法
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/application/MainPage.fxml"));
Scene scene = new Scene(root,800,650);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
这是我的 FXML 主布局 MainPage.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import javafx.collections.FXCollections?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
<center>
<AnchorPane prefHeight="374.0" prefWidth="262.0" BorderPane.alignment="CENTER">
<children>
<ListView fx:id="listView" layoutX="106.0" layoutY="93.0" prefHeight="374.4" prefWidth="400.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</center>
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<left>
<VBox alignment="CENTER" prefHeight="368.0" prefWidth="149.0" BorderPane.alignment="CENTER">
<children>
<TextField fx:id="filterField" />
<ChoiceBox fx:id="type" prefWidth="150.0">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Horror" />
<String fx:value="Action" />
</FXCollections>
</items>
<VBox.margin>
<Insets bottom="20.0" left="10.0" right="10.0" />
</VBox.margin>
</ChoiceBox>
<ChoiceBox fx:id="branch" prefWidth="150.0">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="branch1" />
<String fx:value="branch2" />
<String fx:value="branch3" />
</FXCollections>
</items>
<VBox.margin>
<Insets bottom="20.0" left="10.0" right="10.0" />
</VBox.margin>
</ChoiceBox>
<ChoiceBox fx:id="company" prefWidth="150.0">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Warner Bros" />
<String fx:value="Summit Entertainment" />
</FXCollections>
</items>
<VBox.margin>
<Insets bottom="20.0" left="10.0" right="10.0" />
</VBox.margin>
</ChoiceBox>
<ChoiceBox fx:id="status" prefWidth="150.0">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Released" />
<String fx:value="Coming Soon" />
</FXCollections>
</items>
<VBox.margin>
<Insets left="10.0" right="10.0" />
</VBox.margin>
</ChoiceBox>
</children>
</VBox>
</left>
</BorderPane>
这是ListCell.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<GridPane fx:id="gridPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="206.0" prefWidth="534.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints>
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" maxWidth="350.0" minWidth="0.0" prefWidth="284.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="509.0" minWidth="0.0" prefWidth="56.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="543.0" minWidth="10.0" prefWidth="55.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="543.0" minWidth="10.0" prefWidth="119.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0">
<children>
<ImageView fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../../../../Desktop/Test.jpg" />
</image>
</ImageView>
</children>
</VBox>
<VBox alignment="CENTER" prefHeight="212.0" prefWidth="95.0" GridPane.columnIndex="1">
<children>
<Label text="Genre:" />
<Label text="Status:" />
</children>
</VBox>
<VBox alignment="CENTER" prefHeight="183.0" prefWidth="80.0" GridPane.columnIndex="2">
<children>
<Label fx:id="genre" text="Label" />
<Label fx:id="status" text="Label" />
</children>
</VBox>
<VBox alignment="CENTER" prefHeight="225.0" prefWidth="132.0" GridPane.columnIndex="3">
<children>
<Button mnemonicParsing="false" text="Button" />
</children>
</VBox>
</children>
</GridPane>
希望有人能给我任何解决方案。谢谢
最佳答案
使用 FilteredList
如果您想过滤内存中的项目,这是正确的方法。如果你看documentation ,你会看到FilteredList
有一个predicate
属性(property)。毫不奇怪,该属性拥有 Predicate
。 Predicate
接口(interface)是一个功能接口(interface)(这意味着它可以是 lambda 表达式或方法引用的目标),其抽象方法接受 T
类型的泛型参数并返回true
或false
基于任意逻辑。当您设置predicate
时FilteredList
的属性,它将使用 Predicate
确定源中的元素是否 ObservableList
应该可以通过 FilteredList
看到查看。随着项目从源中添加和删除 ObservableList
FilteredList
会自动更新。
不幸的是,如果您更新任何状态 Predicate
基于(例如,在 ChoiceBox
es 中选择了哪些选项),它不会自动重新应用 Predicate
源 ObservableList
的所有元素。换句话说,FilteredList
不会因为Predicate
而自动更新的内部状态发生了变化。这意味着每次更新过滤器状态时,您都需要创建一个新 Predicate
并设置predicate
FilteredList
的属性(property)。这是创建和使用绑定(bind)会有所帮助的地方。 (注意:虽然 Callable
是 java.util.concurrent
包的一部分,但这里没有发生并发。)
要创建绑定(bind),我们将使用 Bindings.createObjectBinding(Callable,Observable...)
。该方法接受 Callable
(另一个功能接口(interface))和一个 Observable
数组对象。 Observable
的数组被称为创建的 ObjectBinding
的依赖并且,当其中任何一个无效时,会导致 ObjectBinding
根据给定的 Callable
重新计算其值。换句话说,Callable
每次 Observable
之一时都会被调用s 无效。
FilteredList<Movie> filteredList = movieList.filtered(null); // a null Predicate means "always true"
// moved to own variable for clarity (usually inlined with the method call)
Observable[] dependencies = {genre.valueProperty(), branch.valueProperty(), status.valueProperty(), company.valueProperty()};
ObjectBinding<Predicate<Movie>> binding = Bindings.createObjectBinding(() -> {
Predicate<Movie> predicate = movie -> {
// test "movie" based on the values of your ChoiceBoxes
};
return predicate;
}, dependencies);
filteredList.predicateProperty().bind(binding);
如果您注意到,依赖项是 value
您的每个属性 ChoiceBox
es.属性(即 ReadOnlyProperty
和 Property
的实例)是 Observable
的实现当它们的值可能改变时,它们就会失效。这意味着每当用户更改他们的选择时,value
属性无效,并且 Predicate
FilteredList
的被改变了。当 Predicate
更改列表被“重新过滤”。
关于java - 在 JavaFX 中使用多个选择框来过滤 ListView ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56248446/