JFace TableViewer性能改善 -- 使用VirtualTable

时间:2023-01-18 12:42:30

前一篇提到了SWT中的table的通过使用virtual table性能得到很大的改善,那么如果既存的工程中使用的是TableViewer来创建的表,也能改成virtual table吗?

答案是肯定的,而且改起来超级简单,只需要在创建TableViewer的时候,加一个SWT.VIRTUAL属性即可~~

 

直接上示例代码:

package swt.table;

import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableColumn;

/**
 * A simple TableViewer to demonstrate the usage of a standard content provider
 * with a virtual table
 * 
 */
public class VirtualTableViewer {
    private static int tableItems = 30000;
    // ContentProvider
    private class MyContentProvider implements IStructuredContentProvider {
        private MyModel[] elements;

        public Object[] getElements(Object inputElement) {
            return elements;
        }

        public void dispose() {

        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            this.elements = (MyModel[]) newInput;
        }
    }

    // LabelProvider
    private class MyLabelProvider implements ITableLabelProvider {

        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        public String getColumnText(Object element, int columnIndex) {
            if (element instanceof MyModel) {
                MyModel model = (MyModel) element;
                if (columnIndex == 0) {
                    return String.valueOf(model.getCounter());
                } else {
                    return model.getName();
                }
            }
            return null;
        }

        public void addListener(ILabelProviderListener listener) {

        }

        public void dispose() {

        }

        public boolean isLabelProperty(Object element, String property) {
            return false;
        }

        public void removeListener(ILabelProviderListener listener) {

        }

    }

    // model
    public class MyModel {
        public int counter;
        public String name;

        public MyModel(int counter) {
            this.counter = counter;
            this.name = "model" + counter;
        }

        public int getCounter() {
            return counter;
        }

        public String getName() {
            return name;
        }

        public String toString() {
            return "Item " + this.counter;
        }
    }

    public VirtualTableViewer(Shell shell) {
        // ※ SWT.VIRTUAL
        TableViewer tableViewer = new TableViewer(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);

        // set table title
        TableColumn column = new TableColumn(tableViewer.getTable(), SWT.NULL);
        column.setText("Column1");
        column.pack();
        TableColumn column2 = new TableColumn(tableViewer.getTable(), SWT.NULL);
        column2.setText("Column2");
        column2.pack();

        tableViewer.setLabelProvider(new MyLabelProvider());
        tableViewer.setContentProvider(new MyContentProvider());
        tableViewer.setUseHashlookup(true);
        MyModel[] model = createModel();
        tableViewer.setInput(model);

        tableViewer.getTable().setLinesVisible(true);
        tableViewer.getTable().setHeaderVisible(true);
        tableViewer.getTable().setBounds(10, 10, 280, 350);
    }
    
    

    private MyModel[] createModel() {
        MyModel[] elements = new MyModel[tableItems];

        for (int i = 0; i < tableItems; i++) {
            elements[i] = new MyModel(i);
        }

        return elements;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("Virtual TableViewer Demo");

        new VirtualTableViewer(shell);
        shell.pack();
        shell.open();
        
        long end = System.currentTimeMillis();
        System.out.println("All cost:" + (end - start));

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }

        display.dispose();
    }
}

注意到了?

TableViewer tableViewer = new TableViewer(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);

仅仅是比平常创建TableViewer多一个SWT.VIRTUAL属性而已~~

 

不过虚表都有一个问题,在setInput之后,再调用setText来设置某个单元格的时候,单元格所在的行的其他单元格的数据就会被清空掉,

就是说把VirtualTableViewer方法代码改成下面这个样子(其他代码不动):

public VirtualTableViewer(Shell shell) {
        // SWT.VIRTUAL
        TableViewer tableViewer = new TableViewer(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);

        // set table title
        TableColumn column = new TableColumn(tableViewer.getTable(), SWT.NULL);
        column.setText("Column1");
        column.pack();
        TableColumn column2 = new TableColumn(tableViewer.getTable(), SWT.NULL);
        column2.setText("Column2");
        column2.pack();

        tableViewer.setLabelProvider(new MyLabelProvider());
        tableViewer.setContentProvider(new MyContentProvider());
        tableViewer.setUseHashlookup(true);
        MyModel[] model = createModel();
        tableViewer.setInput(model);

        tableViewer.getTable().setLinesVisible(true);
        tableViewer.getTable().setHeaderVisible(true);
        tableViewer.getTable().setBounds(10, 10, 280, 350);
        
        // 加了下面这一行改变单元格的值,整行其他单元格的值都没了。
        // 去掉SWT.VIRTUAL属性,则不会出现这个问题
        tableViewer.getTable().getItem(0).setText("test");
    }