2013-07-30 63 views
10

Tôi đã chơi xung quanh với lớp FilteredList mà họ đã thêm lại vào JDK8 và nó cảm thấy nhanh hơn rất nhiều - dường như cho hiệu suất gần hơn với GlazedLists. Tuy nhiên bảng phân loại cột dường như không hoạt động ở tất cả khi tôi sử dụng một FilteredList thay vì một ObservableList.JavaFX Tableview với FilteredList (JDK 8) không sắp xếp theo cột

Không có ngoại lệ/stacktrace trong bảng điều khiển.

Dưới đây là các thành viên dụ của tôi trong bộ điều khiển của tôi:

private ObservableList<Film> masterData = FXCollections.observableArrayList(); 
    private FilteredList<Film> filteredData; 

điều khiển của tôi init:

@FXML 
void initialize() { 
    ... 
    filmTable.setItems(filteredData); 
    ... 
} 

vị thi công:

public FilmBrowserController() { 

    ... 
    masterData.addAll(filmRepository.findAllSortedByTitle()); 
    filteredData = new FilteredList<>(masterData); 
    filteredData.setPredicate(film -> true); 
} 

Tôi đã được lọc danh sách bằng cách chỉ cần đặt một vị ngữ mới khi một bộ lọc TextField được thay đổi:

filteredData.setPredicate(film -> 
    film.getTitle().toLowerCase().contains(filterField.getText().toLowerCase())); 

Tôi vẫn còn khá xanh với JavaFX - tôi có thiếu thứ gì đó khá cơ bản hay đây có phải là lỗi không? Tôi đang sử dụng JDK 8 tải xuống tại đây: https://jdk8.java.net/download.html Xây dựng b100.

Không thể có bảng có thể lọc nhưng được sắp xếp theo cột cùng một lúc?

chỉnh sửa:

Modified khác mẫu bảng JavaFX tôi tìm thấy trên stackoverflow, tôi đã thêm dòng này (74):

table.setItems(table.getItems().filtered(p -> p.getFirstName().startsWith("a"))); 

Nguồn đầy đủ:

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.*; 
import javafx.scene.control.TableColumn.CellDataFeatures; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.HBox; 
import javafx.scene.layout.StackPane; 
import javafx.scene.layout.VBox; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

import java.util.Arrays; 
import java.util.Collections; 
import java.util.Date; 
import java.util.Random; 

public class TableSortPerformanceTest extends Application { 

    public static final int INIT_LIST_SIZE = 100_000; 

    @Override 
    public void start(Stage stage) { 
     Scene scene = new Scene(new StackPane()); 
     stage.setTitle("Table View Sample"); 
     stage.setWidth(550); 
     stage.setHeight(550); 

     final Label label = new Label("Address Book"); 
     label.setFont(new Font("Arial", 20)); 

     final TableView<Person> table = new TableView<Person>(); 
     table.setEditable(true); 

     TableColumn<Person, String> firstNameCol = new TableColumn<Person, String>("First Name"); 
     firstNameCol.setMinWidth(100); 
     firstNameCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("firstName")); 
     firstNameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person,String>, ObservableValue<String>>() { 
      @Override 
      public ObservableValue<String> call(CellDataFeatures<Person, String> cdf) { 
       return cdf.getValue().firstNameProperty(); 
      } 
     }); 

     TableColumn<Person, String> lastNameCol = new TableColumn<Person, String>("Last Name"); 
     lastNameCol.setMinWidth(100); 
     lastNameCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("lastName")); 



     TableColumn<Person, String> emailCol = new TableColumn<Person, String>("Email"); 
     emailCol.setMinWidth(200); 
     emailCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("email")); 



     final Random random = new Random(); 
     for (int i = 0; i < INIT_LIST_SIZE; i++) { 
      table.getItems().add(new Person(randomString(random), randomString(random), randomString(random))); 
     } 
     table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol)); 

     table.setItems(table.getItems().filtered(p -> p.getFirstName().startsWith("a"))); 

     long start = new Date().getTime(); 
//  Collections.sort(table.getItems()); 
     long end = new Date().getTime(); 
     System.out.println("Took: " + (end - start)); 


     final TextField addFirstName = new TextField(); 
     addFirstName.setPromptText("First Name"); 
     addFirstName.setMaxWidth(firstNameCol.getPrefWidth()); 
     final TextField addLastName = new TextField(); 
     addLastName.setMaxWidth(lastNameCol.getPrefWidth()); 
     addLastName.setPromptText("Last Name"); 
     final TextField addEmail = new TextField(); 
     addEmail.setMaxWidth(emailCol.getPrefWidth()); 
     addEmail.setPromptText("Email"); 

     final Button addButton = new Button("Add"); 
     addButton.setOnAction(new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent e) { 
       String firstName = isEmpty(addFirstName.getText()) ? randomString(random) : addFirstName.getText(); 
       String lastName = isEmpty(addLastName.getText()) ? randomString(random) : addLastName.getText(); 
       String email  = isEmpty(addEmail.getText())  ? randomString(random) : addEmail.getText(); 
       Person person = new Person(firstName, lastName, email); 
       int idx = Collections.binarySearch(table.getItems(), person); 
       if (idx < 0) { 
        idx = -idx - 1; 
       } 
       table.getItems().add(idx, person); 
       table.getSelectionModel().select(idx); 
       table.scrollTo(idx); 

       addFirstName.clear(); 
       addLastName.clear(); 
       addEmail.clear(); 
      } 
     }); 

     final HBox hb = new HBox(3); 
     hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton); 

     final VBox vbox = new VBox(); 
     vbox.setSpacing(5); 
     vbox.setPadding(new Insets(10)); 
     vbox.getChildren().addAll(label, table, hb); 

     ((StackPane) scene.getRoot()).getChildren().addAll(vbox); 

     stage.setScene(scene); 
     stage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

    private boolean isEmpty(String string) { 
     return (string == null || string.isEmpty()); 
    } 

    private String randomString(Random random) { 
     char[] chars = new char[20]; 
     for (int i = 0; i < 20; i++) { 
      int nextInt = random.nextInt(26); 
      nextInt += random.nextBoolean() ? 65 : 97; 
      chars[i] = (char) nextInt; 
     } 
     return new String(chars); 
    } 

    public static class Person implements Comparable<Person> { 

     private final StringProperty firstName; 
     private final StringProperty lastName; 
     private final StringProperty email; 

     private Person(String fName, String lName, String email) { 
      this.firstName = new SimpleStringProperty(fName); 
      this.lastName = new SimpleStringProperty(lName); 
      this.email = new SimpleStringProperty(email); 
     } 

     public String getFirstName() { 
      return firstName.get(); 
     } 

     public void setFirstName(String fName) { 
      firstName.set(fName); 
     } 

     public StringProperty firstNameProperty() { 
      return firstName ; 
     } 

     public String getLastName() { 
      return lastName.get(); 
     } 

     public void setLastName(String fName) { 
      lastName.set(fName); 
     } 

     public StringProperty lastNameProperty() { 
      return lastName ; 
     } 

     public String getEmail() { 
      return email.get(); 
     } 

     public void setEmail(String fName) { 
      email.set(fName); 
     } 

     public StringProperty emailProperty() { 
      return email ; 
     } 

     @Override 
     public int compareTo(Person o) { 
      return firstName.get().compareToIgnoreCase(o.getFirstName()); 
     } 
    } 
} 

bây giờ tôi đã tạo một vé cho số này https://javafx-jira.kenai.com/browse/RT-32091

Trả lời

8

Hóa ra điều này chưa được hỗ trợ được chuyển (https://javafx-jira.kenai.com/browse/RT-32091) - nhưng phải ở trong tương lai xây dựng:

Martin Sladecek:

FilteredList là unmodifiable, vì vậy nó không thể được sắp xếp. Bạn cần phải bọc nó trong SortedList cho mục đích này. Hướng dẫn ngắn tại đây: http://fxexperience.com/2013/08/returning-a-tableview-back-to-an-unsorted-state-in-javafx-8-0/

Tôi đang thay đổi điều này thành tinh chỉnh vì tôi đang nghĩ đến việc làm cho phương thức FXCollections.sort() trở thành nhận thức của TransformationList, do đó việc sắp xếp một FilteredList sẽ là có thể. Vì TableView đang sử dụng phương thức này, nên nó sẽ hoạt động ngay lập tức sau khi điều này sẽ được thực hiện.

Thêm mã ví dụ:

package com.test; 

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.collections.transformation.FilteredList; 
import javafx.collections.transformation.SortedList; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.*; 
import javafx.scene.control.TableColumn.CellDataFeatures; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.HBox; 
import javafx.scene.layout.StackPane; 
import javafx.scene.layout.VBox; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

import java.util.*; 

public class TableFilterTest extends Application { 

    public static final int INIT_LIST_SIZE = 100_000; 

    @Override 
    public void start(Stage stage) { 
     Scene scene = new Scene(new StackPane()); 
     stage.setTitle("Table View Sample"); 
     stage.setWidth(550); 
     stage.setHeight(550); 

     final Label label = new Label("Address Book"); 
     label.setFont(new Font("Arial", 20)); 

     final TableView<Person> table = new TableView<Person>(); 
     table.setEditable(true); 

     TableColumn<Person, String> firstNameCol = new TableColumn<Person, String>("First Name"); 
     firstNameCol.setMinWidth(100); 
     firstNameCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("firstName")); 

     firstNameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person,String>, ObservableValue<String>>() { 
      @Override 
      public ObservableValue<String> call(CellDataFeatures<Person, String> cdf) { 
       return cdf.getValue().firstNameProperty(); 
      } 
     }); 

     TableColumn<Person, String> lastNameCol = new TableColumn<Person, String>("Last Name"); 
     lastNameCol.setMinWidth(100); 
     lastNameCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("lastName")); 

     TableColumn<Person, String> emailCol = new TableColumn<Person, String>("Email"); 
     emailCol.setMinWidth(200); 
     emailCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("email")); 


     final Random random = new Random(); 

     List<Person> personList = new ArrayList<>(); 
     for (int i = 0; i < INIT_LIST_SIZE; i++) { 
      personList.add(new Person(randomString(random), randomString(random), randomString(random))); 
     } 

     ObservableList<Person> personLists = FXCollections.observableList(personList); 
     table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol)); 


     final FilteredList<Person> filteredList = personLists.filtered(p -> p.getFirstName().startsWith("a")); 


     SortedList<Person> personSortedList = new SortedList<>(filteredList); 

     table.setItems(personSortedList); 
     personSortedList.comparatorProperty().bind(table.comparatorProperty()); 

     long start = new Date().getTime(); 
     long end = new Date().getTime(); 
     System.out.println("Took: " + (end - start)); 

     final TextField addFirstName = new TextField(); 
     addFirstName.setPromptText("First Name"); 
     addFirstName.setMaxWidth(firstNameCol.getPrefWidth()); 
     final TextField addLastName = new TextField(); 
     addLastName.setMaxWidth(lastNameCol.getPrefWidth()); 
     addLastName.setPromptText("Last Name"); 
     final TextField addEmail = new TextField(); 
     addEmail.setMaxWidth(emailCol.getPrefWidth()); 
     addEmail.setPromptText("Email"); 

     final TextField filterText = new TextField(); 
     filterText.setMaxWidth(emailCol.getPrefWidth()); 
     filterText.setPromptText("Filter"); 
     filterText.textProperty().addListener((observable, oldValue, newValue) -> 
       filteredList.setPredicate(p -> p.getFirstName().startsWith(filterText.getText())) 
     ); 

     final Button addButton = new Button("Add"); 
     addButton.setOnAction(new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent e) { 
       String firstName = isEmpty(addFirstName.getText()) ? randomString(random) : addFirstName.getText(); 
       String lastName = isEmpty(addLastName.getText()) ? randomString(random) : addLastName.getText(); 
       String email  = isEmpty(addEmail.getText())  ? randomString(random) : addEmail.getText(); 
       Person person = new Person(firstName, lastName, email); 
       int idx = Collections.binarySearch(table.getItems(), person); 
       if (idx < 0) { 
        idx = -idx - 1; 
       } 
       table.getItems().add(idx, person); 
       table.getSelectionModel().select(idx); 
       table.scrollTo(idx); 

       addFirstName.clear(); 
       addLastName.clear(); 
       addEmail.clear(); 
      } 
     }); 

     final HBox hb = new HBox(3); 



     hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton, filterText); 

     final VBox vbox = new VBox(); 
     vbox.setSpacing(5); 
     vbox.setPadding(new Insets(10)); 
     vbox.getChildren().addAll(label, table, hb); 

     ((StackPane) scene.getRoot()).getChildren().addAll(vbox); 

     stage.setScene(scene); 
     stage.show(); 

    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

    private boolean isEmpty(String string) { 
     return (string == null || string.isEmpty()); 
    } 

    private String randomString(Random random) { 
     char[] chars = new char[20]; 
     for (int i = 0; i < 20; i++) { 
      int nextInt = random.nextInt(26); 
      nextInt += random.nextBoolean() ? 65 : 97; 
      chars[i] = (char) nextInt; 
     } 
     return new String(chars); 
    } 

    public static class Person implements Comparable<Person> { 

     private final StringProperty firstName; 
     private final StringProperty lastName; 
     private final StringProperty email; 

     private Person(String fName, String lName, String email) { 
      this.firstName = new SimpleStringProperty(fName); 
      this.lastName = new SimpleStringProperty(lName); 
      this.email = new SimpleStringProperty(email); 
     } 

     public String getFirstName() { 
      return firstName.get(); 
     } 

     public void setFirstName(String fName) { 
      firstName.set(fName); 
     } 

     public StringProperty firstNameProperty() { 
      return firstName ; 
     } 

     public String getLastName() { 
      return lastName.get(); 
     } 

     public void setLastName(String fName) { 
      lastName.set(fName); 
     } 

     public StringProperty lastNameProperty() { 
      return lastName ; 
     } 

     public String getEmail() { 
      return email.get(); 
     } 

     public void setEmail(String fName) { 
      email.set(fName); 
     } 

     public StringProperty emailProperty() { 
      return email ; 
     } 

     @Override 
     public int compareTo(Person o) { 
      return firstName.get().compareToIgnoreCase(o.getFirstName()); 
     } 
    } 
} 
3

Để loại một TableView tableView qua các tiêu đề cột, làm điều này:

ObservableList<Film> masterData = // ... Some observable list 
FilteredList<Film> filteredData = new FilteredList(masterData); 
SortedList<Film> sortableData = new SortedList<>(filteredData); 
tableView.setItems(sortableData); 
sortableData.comparatorProperty().bind(tableView.comparatorProperty()); 

Để lọc các nội dung của TableView, chỉ đơn giản là:

filteredData.setPredicate(x -> x.getTitle().contains("The Walki")); 

Để lọc sống nội dung dựa trên một TextField textField:

textField.textProperty().addListener((observa,old,neo)-> 
    filteredData.setPredicate(x -> x.getTitle().contains(neo)) 
);