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:
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!
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 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:
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();
}
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.
See this article (EDIT: oops I meant this article) for a JFace example.
1 - use the setText(String[]) instead of setText(int, String) one call instead of several.
2 - use myTable.setRedraw(false) before and myTable.setRedraw(true) after the process to stop all redrawing opérations during loading data.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With