JavaFx tableview sort действительно медленный, как улучшить скорость сортировки, как в java swing
Я работаю над приложением javaFx и создал табличное представление и имеет около 100 000 строк с 10 столбцами.
Я также создал ту же таблицу, используя java swing Jtable.
Теперь мне нужно, чтобы производительность сортировки была лучше в javaFx, если не лучше, чем у jtable java swing.
- как изменить пользовательский интерфейс в зависимости от выбора поля со списком
- Более эффективный способ обновления пользовательского интерфейса от службы, чем намерения?
- Обновление пользовательского интерфейса из разных streamов в JavaFX
- Анимировать обновление ProgressBar в Android
- Внедрение средства просмотра журналов с помощью WPF
Сейчас я использую sortorder (), которые сортируют данные, нажимая на заголовки столбцов и скорость сортировки в 20 раз медленнее, чем Jtable.
Кто-нибудь может помочь?
Спасибо
Редактировать:
Я использую пример 13.8 в этой ссылке http://docs.oracle.com/javafx/2/ui_controls/table-view.htm только что добавил несколько строк кода, чтобы просто добавить 100 000 строк, генерируя случайные данные.
- Возможно ли программирование графического интерфейса?
- Анимированная анимация Blackberry
- Как определить несколько действий JButton из другого classа
- Как подключить одну панель к другой
- Android ViewPager с нижними точками
- Как сделать canvas с Swing?
- Как отобразить более трех уровней расширяемого вида списка?
- Список нескольких вариантов с пользовательским представлением?
Это заняло некоторое время, но я думаю, что я понял это, по крайней мере, для этого примера.
В этом примере class Person не имеет каких-либо свойств (например, есть метод getFirstName (), но не метод firstNameProperty ()). Сортировка по столбцам должна получить доступ к значению в каждой ячейке в столбце через фабричное значение ячейки. Когда нет доступа к свойствам, фабрика значений ячейки будет вызывать getFirstName (), а затем завершает результат в новом ReadOnlyObjectWrapper при каждом вызове.
Если вы убедитесь, что class, представляющий данные строки, имеет соответствующие атрибуты свойств, то получение значения намного более эффективно, поскольку оно просто возвращает ссылку на существующий StringProperty.
Этот пример сортирует 100 000 строк примерно за секунду в моей системе (операционная система MacBookPro 8GB, четырехъядерный процессор). Вы можете повысить производительность, предоставляя явную фабрику значений ячеек, которая оборачивается необходимостью отражения при вычислении значения ячейки. Другими словами, замените
firstNameCol.setCellValueFactory( new PropertyValueFactory("firstName"));
с
firstNameCol.setCellValueFactory(new Callback, ObservableValue>() { @Override public ObservableValue call(CellDataFeatures cdf) { return cdf.getValue().firstNameProperty(); } });
Экономия производительности здесь не так драматична.
Вот полный пример:
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.Group; 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.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 void main(String[] args) { launch(args); } @Override public void start(Stage stage) { Scene scene = new Scene(new Group()); 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 table = new TableView (); table.setEditable(true); TableColumn firstNameCol = new TableColumn("First Name"); firstNameCol.setMinWidth(100); firstNameCol.setCellValueFactory( new PropertyValueFactory("firstName")); firstNameCol.setCellValueFactory(new Callback, ObservableValue>() { @Override public ObservableValue call(CellDataFeatures cdf) { return cdf.getValue().firstNameProperty(); } }); TableColumn lastNameCol = new TableColumn("Last Name"); lastNameCol.setMinWidth(100); lastNameCol.setCellValueFactory( new PropertyValueFactory("lastName")); TableColumn emailCol = new TableColumn("Email"); emailCol.setMinWidth(200); emailCol.setCellValueFactory( new PropertyValueFactory("email")); Random random = new Random(); for (int i = 0; i < 100000; i++) { table.getItems().add(new Person(randomString(random), randomString(random), randomString(random))); } table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol)); 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() { @Override public void handle(ActionEvent e) { table.getItems().add(new Person( addFirstName.getText(), addLastName.getText(), addEmail.getText())); 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, 0, 0, 10)); vbox.getChildren().addAll(label, table, hb); ((Group) scene.getRoot()).getChildren().addAll(vbox); stage.setScene(scene); stage.show(); } 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 { 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().compareTo(o.getFirstName()); } } }
ОБНОВЛЕНИЕ: Обратите внимание, что это исправлено в JavaFX 8.
Я не знаю, что случилось со скоростью сортировки в TableView, когда вы нажимаете на заголовок таблицы – он замедляется со 100 000 строк, как вы упомянули в своем вопросе.
Если вы просто предоставляете кнопку, которая сортирует базовую коллекцию, она сортируется во много раз быстрее, и таблица обновляется отлично (по крайней мере, в Java 8). Время сортировки столбца было значительно ниже секунды.
Button sortByEmail = new Button("Sort by Email"); sortByEmail.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { Collections.sort(table.getItems(), new Comparator() @Override public int compare(Person o1, Person o2) { return o1.getEmail().compareTo(o2.getEmail()); } }); } });
Или используя Java 8 lambdas:
Button sortByEmail = new Button("Sort by Email"); sortByEmail.setOnAction(event -> Collections.sort( table.getItems(), (o1, o2) -> o1.getEmail().compareTo(o2.getEmail()) ) );
Поэтому, если у вас много элементов в таблице, в столбце вызывается setSortable (false) и предоставляет кнопки для сортировки столбцов таблицы, если вам нужно.
Включение моего ноутбука в стену и увеличение максимальной памяти JVM также увеличило производительность сортировки для больших наборов данных (сокращая время сортировки, щелкнув заголовок столбца с образцом ниже от 20 секунд до 10 секунд).
Запрограммируйте запрос на повышение по сравнению с отслеживателем проблем JavaFX со следующим примером кода. Код генерирует 100 000 строк случайных данных, и вы можете проверить производительность стандартной сортировки столбцов, щелкнув заголовок столбца таблицы, чтобы отсортировать столбец таблицы и сравнить это с производительностью сортировки по Collections.sort
вызванной нажатием кнопок.
import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.Random; public class Test extends Application { private TableView table = new TableView (); private final ObservableList data = FXCollections.observableArrayList( new Person("Jacob", "Smith", "[email protected]"), new Person("Isabella", "Johnson", "[email protected]"), new Person("Ethan", "Williams", "[email protected]"), new Person("Emma", "Jones", "[email protected]"), new Person("Michael", "Brown", "[email protected]")); final HBox hb = new HBox(); public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) { Scene scene = new Scene(new Group()); stage.setTitle("Table View Sample"); stage.setWidth(550); stage.setHeight(550); final Label label = new Label("Address Book"); label.setFont(new Font("Arial", 20)); table.setEditable(true); TableColumn firstNameCol = new TableColumn("First Name"); firstNameCol.setMinWidth(100); firstNameCol.setCellValueFactory( new PropertyValueFactory("firstName")); TableColumn lastNameCol = new TableColumn("Last Name"); lastNameCol.setMinWidth(100); lastNameCol.setCellValueFactory( new PropertyValueFactory("lastName")); TableColumn emailCol = new TableColumn("Email"); emailCol.setMinWidth(200); emailCol.setCellValueFactory( new PropertyValueFactory("email")); Random random = new Random(); table.setItems(data); for (int i = 0; i < 100000; i++) { table.getItems().add(new Person(randomString(random), randomString(random), randomString(random))); } table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 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() { @Override public void handle(ActionEvent e) { data.add(new Person( addFirstName.getText(), addLastName.getText(), addEmail.getText())); addFirstName.clear(); addLastName.clear(); addEmail.clear(); } }); Button sortByFirstName = new Button("Sort by First Name"); sortByFirstName.setOnAction(new EventHandler () { @Override public void handle(ActionEvent event) { Collections.sort(table.getItems()); } }); Button sortByEmail = new Button("Sort by Email"); sortByEmail.setOnAction(new EventHandler () { @Override public void handle(ActionEvent event) { Collections.sort(table.getItems(), new Comparator() { @Override public int compare(Person o1, Person o2) { return o1.getEmail().compareTo(o2.getEmail()); } }); } }); hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton, sortByFirstName, sortByEmail); hb.setSpacing(3); final VBox vbox = new VBox(); vbox.setSpacing(5); vbox.setPadding(new Insets(10, 0, 0, 10)); vbox.getChildren().addAll(label, table, hb); ((Group) scene.getRoot()).getChildren().addAll(vbox); stage.setScene(scene); stage.show(); } 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 { private final SimpleStringProperty firstName; private final SimpleStringProperty lastName; private final SimpleStringProperty 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 String getLastName() { return lastName.get(); } public void setLastName(String fName) { lastName.set(fName); } public String getEmail() { return email.get(); } public void setEmail(String fName) { email.set(fName); } @Override public int compareTo(Person o) { return firstName.get().compareTo(o.getFirstName()); } } }