Reputation: 1658
I have this example of Java table which generates values every second.
Short example:
MainApp.java
public class MainApp extends Application
{
private TableView<Employee> table;
private TextField txtField;
private ObservableList<Employee> data;
MyService myService;
@Override
public void start(Stage stage) throws Exception
{
Label lbl = new Label("Enter text below to filter: ");
initFilter();
initTable();
myService = new MyService();
myService.setDelay(new Duration(300));
myService.setPeriod(new Duration(1000));
myService.start();
VBox container = new VBox();
container.getChildren().addAll(lbl, txtField, table);
StackPane root = new StackPane();
root.getChildren().add(container);
Scene scene = new Scene(root, 500, 400);
stage.setScene(scene);
stage.show();
}
class MyService extends ScheduledService<Void>
{
@Override
protected Task<Void> createTask()
{
return new Task<Void>()
{
@Override
protected Void call() throws Exception
{
data = getTableData();
table.setItems(FXCollections.observableArrayList(data));
return null;
}
};
}
}
public static void main(String[] args)
{
launch(args);
}
private void initTable()
{
table = new TableView<>();
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
TableColumn<Employee, String> empIdCol = new TableColumn<>("Employee ID");
empIdCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Employee, String>, ObservableValue<String>>()
{
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Employee, String> p)
{
return p.getValue().empIdProperty();
}
});
TableColumn<Employee, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Employee, String>, ObservableValue<String>>()
{
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Employee, String> p)
{
return p.getValue().nameProperty();
}
});
TableColumn<Employee, Number> ageCol = new TableColumn<>("Age");
ageCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Employee, Number>, ObservableValue<Number>>()
{
@Override
public ObservableValue<Number> call(TableColumn.CellDataFeatures<Employee, Number> p)
{
return p.getValue().ageProperty();
}
});
TableColumn<Employee, String> cityCol = new TableColumn<>("City");
cityCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Employee, String>, ObservableValue<String>>()
{
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Employee, String> p)
{
return p.getValue().cityProperty();
}
});
table.getColumns().setAll(empIdCol, nameCol, ageCol, cityCol);
}
private void initFilter()
{
txtField = new TextField();
txtField.setPromptText("Filter");
txtField.textProperty().addListener(new InvalidationListener()
{
@Override
public void invalidated(Observable o)
{
if (txtField.textProperty().get().isEmpty())
{
table.setItems(data);
return;
}
ObservableList<Employee> tableItems = FXCollections.observableArrayList();
ObservableList<TableColumn<Employee, ?>> cols = table.getColumns();
for (int i = 0; i < data.size(); i++)
{
for (int j = 0; j < cols.size(); j++)
{
TableColumn col = cols.get(j);
String cellValue = col.getCellData(data.get(i)).toString();
cellValue = cellValue.toLowerCase();
if (cellValue.contains(txtField.textProperty().get().toLowerCase()))
{
tableItems.add(data.get(i));
break;
}
}
}
table.setItems(tableItems);
}
});
}
private ObservableList<Employee> getTableData()
{
ObservableList<Employee> list = FXCollections.observableArrayList();
String[] name =
{
"Sriram", "Pete", "Eric", "Dawson", "John"
};
String[] city =
{
"New York", "Chicago", "Little Rock", "Los Angeles", "Oakland"
};
for (int i = 0; i < 5; i++)
{
Employee emp = new Employee();
emp.setName(name[i]);
emp.setAge((int) (Math.random() * 100));
emp.setCity(city[i]);
emp.setEmpId(String.valueOf(i + 1000));
list.add(emp);
}
return list;
}
}
Employee.java
public class Employee {
private SimpleStringProperty name = new SimpleStringProperty();
private SimpleIntegerProperty age = new SimpleIntegerProperty();
private SimpleStringProperty city = new SimpleStringProperty();
private SimpleStringProperty empId = new SimpleStringProperty();
public SimpleStringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getName() {
return name.get();
}
public SimpleIntegerProperty ageProperty() {
return age;
}
public void setAge(Integer age) {
this.age.set(age);
}
p
ublic Integer getAge() {
return age.get();
}
public SimpleStringProperty cityProperty() {
return city;
}
public String getCity() {
return city.get();
}
public void setCity(String city) {
this.city.set(city);
}
public SimpleStringProperty empIdProperty() {
return empId;
}
public void setEmpId(String empId) {
this.empId.set(empId);
}
public String getEmpId() {
return empId.get();
}
}
I noticed that the filter that I use to filter the content is applied only for the current Service run. For next run the filter is not applied.
Upvotes: 0
Views: 741
Reputation: 209245
Use a FilteredList
to manage the filtering. Instead of updating the list directly, replace the contents of its source list from the service. When the text in the text field changes, just update the predicate for the filtered list.
As an aside, your code updates the TableView
from a background thread, which violates the threading rules of JavaFX. This is fixed in the example below.
SSCCE:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class FilteredTableViewExample extends Application {
private TableView<Employee> table;
private TextField txtField;
private FilteredList<Employee> tableData;
private ObservableList<Employee> data;
MyService myService;
@Override
public void start(Stage stage) throws Exception {
Label lbl = new Label("Enter text below to filter: ");
initFilter();
initTable();
myService = new MyService();
myService.setDelay(new Duration(300));
myService.setPeriod(new Duration(1000));
myService.start();
VBox container = new VBox();
container.getChildren().addAll(lbl, txtField, table);
StackPane root = new StackPane();
root.getChildren().add(container);
Scene scene = new Scene(root, 500, 400);
stage.setScene(scene);
stage.show();
}
class MyService extends ScheduledService<List<Employee>> {
@Override
protected Task<List<Employee>> createTask() {
Task<List<Employee>> task = new Task<List<Employee>>() {
@Override
protected List<Employee> call() throws Exception {
return getTableData();
}
};
task.setOnSucceeded(e -> data.setAll(task.getValue()));
return task ;
}
}
public static void main(String[] args) {
launch(args);
}
private void initTable() {
table = new TableView<>();
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
TableColumn<Employee, String> empIdCol = new TableColumn<>("Employee ID");
empIdCol.setCellValueFactory(p -> p.getValue().empIdProperty());
TableColumn<Employee, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(p -> p.getValue().nameProperty());
TableColumn<Employee, Number> ageCol = new TableColumn<>("Age");
ageCol.setCellValueFactory(p -> p.getValue().ageProperty());
TableColumn<Employee, String> cityCol = new TableColumn<>("City");
cityCol.setCellValueFactory(p -> p.getValue().cityProperty());
table.getColumns().setAll(empIdCol, nameCol, ageCol, cityCol);
data = FXCollections.observableArrayList();
tableData = new FilteredList<>(data);
table.setItems(tableData);
}
private void initFilter() {
txtField = new TextField();
txtField.setPromptText("Filter");
txtField.textProperty().addListener((obs, oldText, newText) -> {
if (txtField.textProperty().get().isEmpty()) {
tableData.setPredicate(employee -> true);
return;
}
tableData.setPredicate(employee -> {
String text = newText.toLowerCase();
for (TableColumn<Employee, ?> col : table.getColumns()) {
String cellValue = col.getCellData(employee).toString();
cellValue = cellValue.toLowerCase();
if (cellValue.contains(text)) {
return true;
}
}
return false;
});
});
}
private List<Employee> getTableData() {
List<Employee> list = new ArrayList<>();
String[] name = { "Sriram", "Pete", "Eric", "Dawson", "John" };
String[] city = { "New York", "Chicago", "Little Rock", "Los Angeles", "Oakland" };
for (int i = 0; i < 5; i++) {
Employee emp = new Employee();
emp.setName(name[i]);
emp.setAge((int) (Math.random() * 100));
emp.setCity(city[i]);
emp.setEmpId(String.valueOf(i + 1000));
list.add(emp);
}
return list;
}
public static class Employee {
private SimpleStringProperty name = new SimpleStringProperty();
private SimpleIntegerProperty age = new SimpleIntegerProperty();
private SimpleStringProperty city = new SimpleStringProperty();
private SimpleStringProperty empId = new SimpleStringProperty();
public SimpleStringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getName() {
return name.get();
}
public SimpleIntegerProperty ageProperty() {
return age;
}
public void setAge(Integer age) {
this.age.set(age);
}
public Integer getAge() {
return age.get();
}
public SimpleStringProperty cityProperty() {
return city;
}
public String getCity() {
return city.get();
}
public void setCity(String city) {
this.city.set(city);
}
public SimpleStringProperty empIdProperty() {
return empId;
}
public void setEmpId(String empId) {
this.empId.set(empId);
}
public String getEmpId() {
return empId.get();
}
}
}
Upvotes: 1