JavaFx tableview 排序真的很慢 如何像在 java swing 中一样提高排序速度 [英] JavaFx tableview sort is really slow how to improve sort speed as in java swing

查看:31
本文介绍了JavaFx tableview 排序真的很慢 如何像在 java swing 中一样提高排序速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发 javaFx 应用程序并创建了一个 tableview,并且有大约 100,000 多行和 10 列.

I am working on javaFx application and have created a tableview and have around 100,000+ rows with 10 columns.

我也使用 java swing Jtable 创建了相同的表.

I have also created same table using java swing Jtable.

现在我需要在 javaFx 中的排序性能更好,如果不是比 java swing 的 jtable 更好.

Now I need sorting performance to be better in javaFx if not better than some what near to java swing's jtable.

现在我正在使用 sortorder(),它通过单击列标题对数据进行排序,并且排序速度比 Jtable 慢 20 倍.

Right Now I am using sortorder() which sort data by clicking on column headers and sort speed is 20 times slower than Jtable.

有人可以帮忙吗?

谢谢

我在此链接中使用示例 13.8 http://docs.oracle.com/javafx/2/ui_controls/table-view.htm只需添加几行代码,即可通过生成随机数据添加 100,000 行.

I am using example 13.8 in this link http://docs.oracle.com/javafx/2/ui_controls/table-view.htm just has added few line of code to just add 100,000 rows by generating random data.

推荐答案

花了一段时间,但我想我已经弄清楚了,至少对于这个例子.

It took a while, but I think I have figured this out, at least for this example.

在这个例子中,Person 类没有任何属性访问器(即有一个 getFirstName() 方法,但没有 firstNameProperty() 方法).按列排序必须通过单元格值工厂访问列中每个单元格中的值.当没有属性访问器时,单元格值工厂将调用 getFirstName(),然后在每次调用时将结果包装在一个新的 ReadOnlyObjectWrapper 中.

In this example, the Person class doesn't have any property accessors (i.e. there's a getFirstName() method, but no firstNameProperty() method). Sorting by columns has to access the value in each cell in the column via the cell value factory. When there's no property accessor, the cell value factory is going to call getFirstName() and then wrap the result in a new ReadOnlyObjectWrapper on each invocation.

如果您确保表示行数据的类具有适当的属性访问器,那么检索值的效率会更高,因为它只返回对现有 StringProperty 的引用.

If you make sure the class representing the row data has the appropriate property accessors, then retrieving the value is much more efficient, as it merely returns a reference to the existing StringProperty.

本示例在我的系统(MacBookPro 8GB RAM,四核)上大约一秒内对 100,000 行进行排序.您可以通过提供显式单元格值工厂来进一步提高性能,从而避免计算单元格值时进行反射的需要.换句话说,替换

This example sorts 100,000 rows in approximately a second on my system (MacBookPro 8GB RAM, quad core). You can improve performance more by providing an explicit cell value factory, which gets around the need for reflection in computing the cell value. In other words, replace

    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();
      }
    });

这里的性能节省没有那么显着.

The performance saving here is not as dramatic.

完整示例如下:

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<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"));


        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<ActionEvent>() {
            @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<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().compareTo(o.getFirstName());
    }
  }
} 

更新:请注意,这是在 JavaFX 8 中修复的.

UPDATE: Note this is fixed in JavaFX 8.

这篇关于JavaFx tableview 排序真的很慢 如何像在 java swing 中一样提高排序速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆