在SWT/JFace RCP应用程序中填充大表。

时间:2023-01-20 17:40:23

How would you go about displaying huge amount of rows in SWT table? Huge is something above 20K rows, 20 columns. Don't ask me why I need to show that much data, it's not the point. The point is how to make it work as fast as possible so that end user won't get bored waiting. Each row displays an instance of some object, columns are its properties (some). I thought to use JFace content/label provider pattern, but afraid it will be even slower than hitting the table directly with the data. This is how it goes:

如何在SWT表中显示大量的行?巨大是超过20K行,20列。不要问我为什么要展示这么多数据,这不是重点。关键是如何使它尽可能快地工作,以便最终用户不会感到等待的无聊。每一行显示一个对象的实例,列是它的属性(有些)。我想使用JFace内容/标签提供程序模式,但恐怕它比直接使用数据访问表还要慢。事情是这样的:

    Display.getDefault().asyncExec(new Runnable() {
       public void run() {
           List<MyObject> objects = model.getViewData();
           for(MyObject object: objects){
           TableItem item = new TableItem(table, SWT.NULL);
           item.setImage(0, img1);
           item.setBackground(color1);
               item.setText(0, object.getProperty0());
               item.setText(1, object.getProperty1());
               item.setText(2, object.getProperty2());
               ..... 
            }
       });

Drawing 20k records on my computer takes about 20 sec. The biggest performance problem I've seen in Windows are caused by incredible amount of native windowing messages sent by SWT when new table item created and populated with text. I've found great workaround for this - hide table before populating, and then show it when done. Just calling table.setVisible(false) before the loop and table.setVisible(true) after the loop does wonders - the speed goes up six-seven times!

在我的电脑上绘制20k的记录大约需要20秒。我在Windows中看到的最大的性能问题是当新表项创建并使用文本填充时,SWT发送的大量本地窗口消息导致的。我为这个隐藏表找到了很好的解决方案——填充之前,然后在填充后显示它。只需要在循环之前调用table.setVisible(false)和table.setVisible(true)循环之后——速度提升六到七倍!

I'd like to speed it up even more. What would you suggest ? Also, I wonder how this trick hiding the widget would work on non-windows implementations of SWT (aka Linux) ?

我想进一步加快速度。你有什么建议?另外,我想知道这个隐藏小部件的技巧在SWT(即Linux)的非windows实现上是如何工作的?

3 个解决方案

#1


19  

SWT can do that for you. When you use the SWT.VIRTUAL style flag, items are only created when scrolled into view. Here's how to do it:

SWT可以帮你。当你使用SWT。虚拟样式标志,只有在滚动到视图时才创建项目。这是如何做到的:

  1. Create the table with style SWT.VIRTUAL
  2. 创建具有SWT.VIRTUAL样式的表
  3. Set the row count using Table#setItemCount()
  4. 使用表#setItemCount()设置行计数
  5. Add a SWT.SetData Listener that fills the TableItems on demand.
  6. 添加一个SWT。SetData侦听器,按需填充表项。

Here's a code snippet:

这里有一个代码片段:

public static void main( String[] args ) {
    Display display = new Display();
    Shell shell = new Shell( display );
    shell.setLayout( new FillLayout() );
    final Table table = new Table( shell, SWT.VIRTUAL );
    table.setItemCount( 10000 );
    table.addListener( SWT.SetData, new Listener() {
        public void handleEvent( Event event ) {
            TableItem item = (TableItem)event.item;
            item.setText( "Item " + table.indexOf( item ) );
        }
    } );
    shell.setSize( 300, 500 );
    shell.open();
    while( !shell.isDisposed() ) {
        if( !display.readAndDispatch() ) {
            display.sleep();
        }
    }
    display.dispose();
}

#2


2  

You want to do lazy-loading on the table display. Basically, you keep all these objects offscreen in memory, then create only a handful of actual GUI table rows. As the user scrolls you re-render these rows with the objects at that scroll location.

您希望对表显示执行延迟加载。基本上,您将所有这些对象都保留在内存中,然后只创建少量实际的GUI表行。当用户滚动时,您将使用该滚动位置的对象重新呈现这些行。

See this article (EDIT: oops I meant this article) for a JFace example.

有关JFace示例,请参阅本文(编辑:糟糕,我指的是本文)。

#3


2  

1 - use the setText(String[]) instead of setText(int, String) one call instead of several.

1 -使用setText(String[])代替setText(int, String)一个调用,而不是几个。

2 - use myTable.setRedraw(false) before and myTable.setRedraw(true) after the process to stop all redrawing opérations during loading data.

2 -在加载数据时,使用myTable.setRedraw(false)和myTable.setRedraw(true)来停止所有重绘操作。

it's simpler and can improve performance !!

它更简单,可以提高性能!

good luck.

祝你好运。

on my side using this I load 2500 lines of 20 column in less than 300ms..... on a standard today PC.

在我这边,我在不到300毫秒的时间里,装载了2500条20列的线……在今天的标准PC上。

#1


19  

SWT can do that for you. When you use the SWT.VIRTUAL style flag, items are only created when scrolled into view. Here's how to do it:

SWT可以帮你。当你使用SWT。虚拟样式标志,只有在滚动到视图时才创建项目。这是如何做到的:

  1. Create the table with style SWT.VIRTUAL
  2. 创建具有SWT.VIRTUAL样式的表
  3. Set the row count using Table#setItemCount()
  4. 使用表#setItemCount()设置行计数
  5. Add a SWT.SetData Listener that fills the TableItems on demand.
  6. 添加一个SWT。SetData侦听器,按需填充表项。

Here's a code snippet:

这里有一个代码片段:

public static void main( String[] args ) {
    Display display = new Display();
    Shell shell = new Shell( display );
    shell.setLayout( new FillLayout() );
    final Table table = new Table( shell, SWT.VIRTUAL );
    table.setItemCount( 10000 );
    table.addListener( SWT.SetData, new Listener() {
        public void handleEvent( Event event ) {
            TableItem item = (TableItem)event.item;
            item.setText( "Item " + table.indexOf( item ) );
        }
    } );
    shell.setSize( 300, 500 );
    shell.open();
    while( !shell.isDisposed() ) {
        if( !display.readAndDispatch() ) {
            display.sleep();
        }
    }
    display.dispose();
}

#2


2  

You want to do lazy-loading on the table display. Basically, you keep all these objects offscreen in memory, then create only a handful of actual GUI table rows. As the user scrolls you re-render these rows with the objects at that scroll location.

您希望对表显示执行延迟加载。基本上,您将所有这些对象都保留在内存中,然后只创建少量实际的GUI表行。当用户滚动时,您将使用该滚动位置的对象重新呈现这些行。

See this article (EDIT: oops I meant this article) for a JFace example.

有关JFace示例,请参阅本文(编辑:糟糕,我指的是本文)。

#3


2  

1 - use the setText(String[]) instead of setText(int, String) one call instead of several.

1 -使用setText(String[])代替setText(int, String)一个调用,而不是几个。

2 - use myTable.setRedraw(false) before and myTable.setRedraw(true) after the process to stop all redrawing opérations during loading data.

2 -在加载数据时,使用myTable.setRedraw(false)和myTable.setRedraw(true)来停止所有重绘操作。

it's simpler and can improve performance !!

它更简单,可以提高性能!

good luck.

祝你好运。

on my side using this I load 2500 lines of 20 column in less than 300ms..... on a standard today PC.

在我这边,我在不到300毫秒的时间里,装载了2500条20列的线……在今天的标准PC上。