当前位置: 首页 > 知识库问答 >
问题:

javafx tableview活动排序很慢

尹欣怿
2023-03-14

我正在javafx tableview上工作,并创建了一个100,000行的表(三列一int二浮动)。

我有主动分拣功能。要插入新行,首先使用二进制搜索搜索索引,然后使用表插入索引。获取项目。添加(索引、元素);

但是每20毫秒增加一行,gui就有点没有响应。

我添加了table.setSseltionModel(null);它固定了我的GUI,所以它似乎是慢GUI背后的罪魁祸首。

但我还需要选择行的能力。。。。。

有人建议在这种情况下该怎么办吗。。。。

备注:(在添加行表之前。setSelectionModel(null);我试着运行jprofiler,结果显示大部分时间都花在了javafx上。场景控制TableCell 2美元。(一旦更改)

编辑:

我的用例

import java.util.ArrayList;  
import java.util.Collections;  
import java.util.Comparator;  
import java.util.List;  
import java.util.Random;  
import javafx.animation.Animation;  
import javafx.animation.KeyFrame;  
import javafx.animation.Timeline;  
import javafx.application.Application;  
import javafx.beans.binding.Bindings;  
import javafx.beans.property.SimpleStringProperty;  
import javafx.beans.property.StringProperty;  
import javafx.collections.FXCollections;  
import javafx.collections.ObservableList;  
import javafx.event.ActionEvent;  
import javafx.event.EventHandler;  
import javafx.geometry.HPos;  
import javafx.scene.Scene;  
import javafx.scene.control.Button;  
import javafx.scene.control.Label;  
import javafx.scene.control.SelectionMode;  
import javafx.scene.control.TableColumn;  
import javafx.scene.control.TableColumn.SortType;  
import javafx.scene.control.TableView;  
import javafx.scene.control.TextField;  
import javafx.scene.control.cell.PropertyValueFactory;  
import javafx.scene.layout.BorderPane;  
import javafx.scene.layout.ColumnConstraints;  
import javafx.scene.layout.GridPane;  
import javafx.stage.Stage;  
import javafx.util.Duration;  
public class TableInsertExample extends Application {  
  int count=0;  
    long s,e,mx=0,mn=1000000000;  
    float avg=0;  
  private static final Random RNG = new Random();  
  private Comparator<Person> tableOrderComparator ;  
  @SuppressWarnings("unchecked")  
@Override  
  public void start(Stage primaryStage) {  
    final BorderPane root = new BorderPane();  
    final TableView<Person> table = new TableView<Person>();  
    table.setItems(createData());  
    final TableColumn<Person, String> firstNameColumn = new TableColumn<Person,String>("First Name");  
    final TableColumn<Person, String> lastNameColumn = new TableColumn<Person,String>("Last Name");  
    firstNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));  
    lastNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));  
    table.getColumns().addAll(firstNameColumn, lastNameColumn);  

    tableOrderComparator = createTableOrderComparator(table);  

   //this line increase speed but then we can not even click on table as it will give someexception  
    table.setSelectionModel(null);  


    final GridPane addPersonPane = new GridPane();  
    final TextField firstNameTF = new TextField();  
    final TextField lastNameTF = new TextField();  
    final Button addButton = new Button("Add");  
    addPersonPane.addRow(0, new Label("First Name:"), firstNameTF);  
    addPersonPane.addRow(1, new Label("Last Name:"), lastNameTF);  
    addPersonPane.addRow(2, addButton);  
    final ColumnConstraints leftColConstraints = new ColumnConstraints();  
    leftColConstraints.setHalignment(HPos.RIGHT);  
    final ColumnConstraints rightColConstraints = new ColumnConstraints();  
    rightColConstraints.setHalignment(HPos.LEFT);  
    addPersonPane.getColumnConstraints().addAll(leftColConstraints, rightColConstraints);  

    addButton.setOnAction(new EventHandler<ActionEvent>() {  

      @Override  
      public void handle(ActionEvent event) {  
        final Person person = new Person(firstNameTF.getText(), lastNameTF.getText());  
        addPersonToTable(table, person);  
      }  
    });  
     table.getSortOrder().addAll(firstNameColumn);  
    Label countLabel = new Label();  
    countLabel.textProperty().bind(Bindings.format("Table has %s entries", Bindings.size(table.getItems())));  
    root.setTop(countLabel);  
    root.setCenter(table);  
    root.setBottom(addPersonPane);  
    primaryStage.setScene(new Scene(root, 400, 600));  
    primaryStage.show();     

    Timeline addRandomPeopleFrequently = new Timeline(new KeyFrame(Duration.millis(20), new EventHandler<ActionEvent>() {  
      @Override  
      public void handle(ActionEvent event) {  
        Person randomPerson = new Person(randomString(), randomString());  
        count++;  
        addPersonToTable(table, randomPerson);  
      }  
    }));  
    addRandomPeopleFrequently.setCycleCount(Animation.INDEFINITE);  
    addRandomPeopleFrequently.play();  
  }  
  private Comparator<Person> createTableOrderComparator(  
      final TableView<Person> table) {  
    return new Comparator<Person>() {  
      @Override  
      public int compare(Person person1, Person person2) {  
        for (TableColumn<Person, ?> col : table.getSortOrder()) {  
          Comparator colComp = col.getComparator();  
          if (colComp == null) {  
            colComp = TableColumn.DEFAULT_COMPARATOR;  
          }  
          final Object o1 = col.getCellData(person1);  
          final Object o2 = col.getCellData(person2);  
          int c = colComp.compare(o1, o2);  
          if (col.getSortType() == SortType.DESCENDING) {  
            c = -c ;  
          }  
          if (c != 0) {  
            return c;  
          }  
        }  
        return 0 ;  
      }  
    };  
  }  
  public static void main(String[] args) {  
    launch(args);  
  }  
  private ObservableList<Person> createData() {  
    List<Person> list = new ArrayList<Person>();  
    for (int i=0; i<100000; i++) {  
      list.add(new Person(randomString(), randomString()));  
    }  
    return FXCollections.observableList(list);  
  }  
  private String randomString() {  
    StringBuilder sb = new StringBuilder();  
    for (int i=0; i<8; i++) {  
      sb.append((char)(RNG.nextInt(26)+'a'));  
    }  
    return sb.toString();  
  }  
  private void addPersonToTable(final TableView<Person> table,  
       final Person person) {  
     int index ;  
     final ObservableList<TableColumn<Person, ?>> tableSortOrder = table.getSortOrder();  
     if (tableSortOrder.size()==0) {  
       index = table.getItems().size();  
     } else {  
       index = Collections.binarySearch(table.getItems(), person, tableOrderComparator);  
       if (index < 0) {  
         index = -index-1 ;  
       }  
     }  
     s=System.currentTimeMillis();  
     List<Person> leftList = table.getItems().subList(0, index);  
     List<Person> rightList = table.getItems().subList(index, table.getItems().size());  
     List<Person> newList = new ArrayList<Person>(table.getItems().size()+1);  
     newList.addAll(leftList);  
     newList.add(person);  
     newList.addAll(rightList);  
   /*  int selectedIndex = table.getSelectionModel().getSelectedIndex(); 
     if (index < selectedIndex) { 
       selectedIndex++; 
     }  */  
     table.getItems().setAll(newList);  
    // table.getSelectionModel().select(selectedIndex);  
     e= System.currentTimeMillis() - s;  
  avg+=e;  
  if(mx<e)  
  mx=e;  
  if(mn>e)  
  mn=e;  
  if(count==1000)  
  {  
  avg=avg/10000;  
  System.out.format("current System time is %f. Max is %d . Min is %d%n",avg,mx,mn);  
  count=0;  
  avg=0;  
  mx=0;  
  mn=100000000;  
  }  
   }  
  public static class Person {  
    private final StringProperty firstName ;  
    private final StringProperty lastName ;  
    Person(String firstName, String lastName) {  
      this.firstName = new SimpleStringProperty(this, "firstName", firstName);  
      this.lastName = new SimpleStringProperty(this, "lastName", lastName);  
    }  
    public String getFirstName() { return firstName.get(); }  
    public void setFirstName(String firstName) { this.firstName.set(firstName);}  
    public StringProperty firstNameProperty() { return firstName ; }  
    public String getLastName() { return lastName.get(); }  
    public void setLastName(String lastName) { this.lastName.set(lastName); }  
    public StringProperty lastNameProperty() { return lastName ; }     
    @Override public String toString() { return firstName.get() + " " + lastName.get() ; }  

  }  
}  

这条线在起点

//this line increase speed but then we can not even click on table as it will give someexception  
    table.setSelectionModel(null);

帮助我将插入速度提高到平均0.2毫秒(代码中包含计算平均值的代码)

但是它禁用了任何选择(因为这个原因,addPeople ToTable中的代码会被注释)

我希望能够选择一行,但与此代码的一些速度效率。(我用的是Jaloiler,它显示主要时间花在TableCell.on更改)

注意:这段代码是由James_D编写的,我只是对它做了一些修改(添加了line table.setSelectionModel(null);和addPersonToTable中的注释行)

共有1个答案

逑翰翮
2023-03-14

我无法复制你的问题。

在一个包含100000行的TableView中,向排序后的位置添加新行对我来说几乎是瞬间的事情。

我使用了James的一个修改版来回答您之前的问题:JavaFx tableview排序非常慢,如何像在JavaSwing中那样提高排序速度。

修改在按下添加按钮时执行以下算法:

  1. 如果没有输入新的人员详细信息,只会生成一些新的随机人员详细信息
  2. 对表项进行二进制搜索以查找插入索引
  3. 在适当的索引处插入项,选择新添加的行
  4. 滚动表格以显示它

如果使用Java 7,TableView scrollTo例程中存在一个错误,它会阻止表格在所有情况下滚动到正确的位置。

使用Java 8b93和Win7进行输出:

表端口性能测试。JAVA

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

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

我已经添加了有问题的用例

我不知道你为什么要求这种行为。

一些建议:

  1. 尝试Java8早期访问。Java8的性能有了很大的提高,无论是否使用选择模型,我都没有注意到时间上的差异。(但是请注意,在build 94中,Java 8对行高光的渲染在您的示例中运行时似乎出现了问题,因此您可能需要提交一个关于高光渲染问题的文件)

由于我不相信这个问题广泛有用,所以我不会再花时间了。

如果这真的是一个问题,我请求你去做(归档)。。。。我这样做是因为在基于swing的表中(我无法发布其代码),速度要快得多(平均为0.2毫秒)

我在8Java早期访问版本中看到的交替行闪烁是一个问题,我将尝试在一个更简单的程序和文件中复制JavaFX问题跟踪器。

我不认为这里有任何关于性能的问题。是的,选择模型在Java7中增加了一些(小)开销,但在Java8中,开销几乎无法察觉。对于操作,我在Java8的JavaFX中测量的0.2ms与在Swing中测量的相同。因此,在Java8的选择模型处理的平台实现中已经有了一些性能调整,我不认为需要任何进一步的调整。

你能给我一些关于过滤的建议吗

最好在新问题中提出新问题,而不是评论。

然而,看看Java8为此提供了什么
JavaFX for Java8中添加了一个FilteredList。还可以看看Panemu的TiwulFX,它包括表过滤功能(以及许多其他有用的功能),看看它是否适合您的应用程序

一般做法建议

不要太快地将行添加到表中,而是批量处理传入的行插入,并减少将它们添加到表中的频率(例如每四分之一秒)。用户不会在意表是否每秒更新四次而不是60次。

次要观察

如果您想对场景进行非常频繁的更新,而不是具有每20毫秒触发一次的KeyFrame和事件处理程序的时间轴,请使用每当系统接收到用于处理的脉冲(默认情况下,脉冲发生在定期每秒间隔60次;例如每16.666毫秒)。这将最终更顺利地处理东西,因为时间线的20毫秒关键帧可能会错过一个脉冲,并最终稍微不均匀(尽管眼睛可能不会察觉到不均匀)。

 类似资料:
  • 我有这些疑问: 和 对于LIST和GET方法。一个集合有零个或多个项目。我在Items中定义了与alloy\u to field的关系,在集合中有许多字段,这很好。 然后,当我查询集合并呈现JSON时,我想按属于Item的名为number的整数变量对项目进行排序。 我试过了,但不起作用: 我想按编号对集合中的项目列表进行排序。这就是@collections=Collection。all()返回,我

  • 我创建了一个TableView,其中包含一个复选框列(isSelected)和三个信息列(姓名、姓氏、职务)。我想根据用户信息禁用一些复选框。例如,如果用户名为“Peter”,则Peter旁边的复选框将被禁用。但我不能。以下是我的一些代码: 人JAVA 控制器。JAVA

  • 问题内容: 我正在寻找Java的良好排序列表。到处搜寻可以给我一些有关使用TreeSet / TreeMap的提示。但是这些组件缺少一件事:随机访问集合中的元素。例如,我想访问排序集中的第n个元素,但是使用TreeSet时,我必须遍历其他n-1个元素,然后才能到达那里。因为我的集合中最多有数千个元素,所以这很浪费。 基本上,我正在寻找与.NET中的排序列表类似的东西,能够快速添加元素,快速删除元素

  • 我使用尝试在活动之间切换。因为这是一辆马车(回来时有时会藏起来),所以我试着潜入其中。 并没有真正使活动移动到顶部,正如我从adb中看到的,活动顺序从未改变: 仅从以下位置更改“焦点状态”: 为此: 但如果我按home按钮四处玩,我可以看到launcher窗口能够“真正移动”到顶部: 由于隐藏/取消隐藏到后台以移动窗口是可能的,这让我想知道是否有可能通过编程方式将mySecondActivity置

  • 我正在研究javaFx应用程序,并创建了一个tableview,拥有大约10万+行和10列。 编辑: 在这个链接中,我使用的是示例13.8,http://docs.oracle.com/javafx/2/ui_controls/table-view.htm只添加了几行代码,通过生成随机数据,只添加了100,000行。

  • 问题内容: 我有一个〜8GB的大文本文件,我需要进行一些简单的过滤,然后对所有行进行排序。我使用的是28核计算机,具有SSD和128GB RAM。我努力了 方法1 方法2 令人惊讶的是,方法1仅需11.5分钟,而方法2仅需(0.75 + 1 <2)分钟。为什么通过管道传输时排序如此缓慢?它不是平行的吗? 编辑 而且并不重要,这个实验可以简单地通过使用(由于@Sergei Kurenkov)而重复进