我正在尝试创建一个带有侦听器的搜索栏,以执行实时搜索和过滤
javafx
中的数据。当我单击启动程序的执行按钮时,应该触发 dataSearch
方法。最初,我的搜索栏似乎工作正常,但问题是,当我从应用程序更新 Oracle 数据库时,TableView
停止被搜索栏中的输入关键字过滤。看来每次程序执行时,dataSearch
方法只调用一次,并且修改TableView
后,称为ObservableList
的generalList
并不会自动更新。
代码示例:
public class App extends Application {
private TableView<General> generalTableView;
private ObservableList<General> generalList;
private TextField searchBox;
private TextField addTextField;
@Override
public void start(Stage primaryStage) {
generalTableView = new TableView<>();
TableColumn<General, String> generalColumn = new TableColumn<>("Col");
generalColumn.setCellValueFactory(new PropertyValueFactory<>("col"));
generalTableView.getColumns().add(generalColumn);
Button loadDataButton = new Button("Load Data");
loadDataButton.setOnAction(event -> {
createGeneralTable();
loadGeneralData();
dataSearch();
});
searchBox = new TextField();
searchBox.setPromptText("Search");
addTextField = new TextField();
addTextField.setPromptText("Add Data");
Button addButton = new Button("Add");
addButton.setOnAction(event -> addData(addTextField.getText()));
HBox searchBoxContainer = new HBox(searchBox);
HBox addBoxContainer = new HBox(addTextField, addButton);
VBox root = new VBox(generalTableView, loadDataButton, searchBoxContainer, addBoxContainer);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
loadDataButton.fire(); // Trigger the button action when the program starts
}
public static void main(String[] args) {
launch(args);
}
static class General {
private ObjectProperty<String> col;
public General(String col) {
this.col = new SimpleObjectProperty<>(col);
}
public String getCol() {
return col.get();
}
public void setCol(String col) {
this.col.set(col);
}
public ObjectProperty<String> colProperty() {
return col;
}
}
static class OracleConnect {
public static Connection getConnection() {
Connection connection = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "system", "o4a75e");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
}
private void createGeneralTable() {
try {
Connection connection = OracleConnect.getConnection();
String createTableGeneral = "CREATE TABLE general (col VARCHAR2(50))";
PreparedStatement statement = connection.prepareStatement(createTableGeneral);
statement.execute();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void loadGeneralData() {
try {
Connection connection = OracleConnect.getConnection();
String query = "SELECT col FROM general";
PreparedStatement statement = connection.prepareStatement(query);
ResultSet resultSet = statement.executeQuery();
generalList = FXCollections.observableArrayList();
while (resultSet.next()) {
String col = resultSet.getString("col");
General general = new General(col);
generalList.add(general);
}
generalTableView.setItems(generalList);
resultSet.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void dataSearch() {
ObservableList<General> generalList = FXCollections.observableArrayList(generalTableView.getItems());
FilteredList<General> filteredData = new FilteredList<>(generalList, b -> true);
searchBox.textProperty().addListener((observable, oldValue, newValue) -> {
filteredData.setPredicate(general -> {
if (newValue.isEmpty() || newValue.isBlank() || newValue == null) {
return true;
}
String searchKeyword = newValue.toLowerCase();
if (general.getCol().toLowerCase().contains(searchKeyword)) {
return true;
} else {
return false;
}
});
});
SortedList<General> sortedData = new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(generalTableView.comparatorProperty());
generalTableView.setItems(sortedData);
}
private void addData(String data) {
try {
Connection connection = OracleConnect.getConnection();
String insertQuery ="INSERT INTO general (col) VALUES (?)";
PreparedStatement statement = connection.prepareStatement(insertQuery);
statement.setString(1, data);
statement.executeUpdate();
General general = new General(data);
generalList.add(general);
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
此答案用于过滤添加到支持
TableView
的内存列表中的数据,因此不包含数据库代码。
问题代码中的主要问题是您不必要地创建新的数据列表。相反,只需拥有一个数据列表并在任何地方使用它,将其包装在单个 FilteredList 和单个 SortedList 中,以对基础列表数据进行所需的转换。
强制不创建超出需要的对象和集合实例的一个好方法是将引用声明为 Final,这是示例代码中演示的技术。
Cat.java
创建记录来保存您的数据。
package com.example.cats;
record Cat(String name) {}
IronCatFistClan.java
创建一个模型来保存您的记录,并对它们进行排序和过滤。
您可以简单地称其为
Model
而不是 IronCatFistClan
。
package com.example.cats;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
class IronFistCatClan {
private final ObservableList<Cat> cats = FXCollections.observableArrayList(
new Cat("Grizabella"),
new Cat("Bombalurina"),
new Cat("Rum Tum Tugger")
);
private final FilteredList<Cat> filteredCats = new FilteredList<>(
cats
);
private final SortedList<Cat> sortedFilteredCats = new SortedList<>(
filteredCats
);
public ObservableList<Cat> getCats() {
return cats;
}
public SortedList<Cat> getSortedFilteredCats() {
return sortedFilteredCats;
}
public void setSearchText(String searchText) {
filteredCats.setPredicate(
cat ->
containsCaseInsensitive(
cat.name(),
searchText
)
);
}
private static boolean containsCaseInsensitive(String textToSearch, String searchText) {
if (searchText == null || searchText.isEmpty() || searchText.isBlank()) {
return true;
}
return textToSearch.toLowerCase().contains(
searchText.toLowerCase()
);
}
}
FilteredCatApp.java
创建一个与模型交互的 UI,显示数据的表格视图,并使用对数据设置过滤器的搜索功能和向数据添加新记录的添加功能。
package com.example.cats;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class FilteredCatApp extends Application {
@Override
public void start(Stage primaryStage) {
IronFistCatClan ironFistCatClan = new IronFistCatClan();
VBox root = new VBox(
10,
createTable(ironFistCatClan),
createSearchBox(ironFistCatClan),
createAddControls(ironFistCatClan)
);
root.setPadding(new Insets(10));
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private static HBox createAddControls(IronFistCatClan ironFistCatClan) {
TextField newCatName = new TextField();
newCatName.setPromptText("Name of a cat to add");
Button addButton = new Button("Add Cat");
addButton.setOnAction(event ->
ironFistCatClan.getCats().add(
new Cat(newCatName.getText())
)
);
return new HBox(10, newCatName, addButton);
}
private static TextField createSearchBox(IronFistCatClan ironFistCatClan) {
TextField searchBox = new TextField();
searchBox.setPromptText("Search");
searchBox.textProperty().addListener((observable, oldSearchText, newSearchText) ->
ironFistCatClan.setSearchText(newSearchText)
);
return searchBox;
}
private static TableView<Cat> createTable(IronFistCatClan ironFistCatClan) {
TableView<Cat> tableView = new TableView<>(
ironFistCatClan.getSortedFilteredCats()
);
ironFistCatClan.getSortedFilteredCats().comparatorProperty().bind(
tableView.comparatorProperty()
);
TableColumn<Cat, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(p ->
new SimpleStringProperty(p.getValue().name())
);
tableView.getColumns().add(nameColumn);
return tableView;
}
public static void main(String[] args) {
launch(args);
}
}