Best Practices - SWT Table, TableViewer, EditingSupport

jkteater picture jkteater · Sep 4, 2012 · Viewed 16.6k times · Source

I am adding a table to my main GUI. It does show up and has the data it is suppose to show. But I feel like I have a big mess of code and it is not structured correctly. I am looking for someone that uses SWT a lot to help me put the right pieces of code in the right places.

Class A - Main GUI with TableViewer

Class B - (ArrayList) Data for table / Class B1 - DataModel for ArrayList Structure

Class A - has method for creating TableViewer

  //////////////////////////////////////////////////////////////////////////
  //                         createTableViewer()                          //
  //////////////////////////////////////////////////////////////////////////
private TableViewer createTableViewer(Composite parent) {
    viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
    createColumns(parent, viewer);
    table = viewer.getTable();
    table.setHeaderVisible(true);
    table.setLinesVisible(true);

    // Layout the viewer
    GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
    viewer.setContentProvider(new ArrayContentProvider());
    *** Getting Array from Class B ***       
    viewer.setInput(AplotDataModel.getInstance().getArrayData());
    viewer.getControl().setLayoutData(gridData);
    return viewer;
}

Class A also has createColumns() method and a createTableViewerColumn() method.

 //////////////////////////////////////////////////////////////////////////
 //                         createColumns()                              //
 //////////////////////////////////////////////////////////////////////////
private void createColumns(final Composite parent, final TableViewer viewer) {
    String[] titles = { "ItemId", "RevId", "PRL", "Dataset Name", "EC Markup" };
    int[] bounds = { 150, 150, 100, 150, 100 };

    TableViewerColumn col = createTableViewerColumn(titles[0], bounds[0], 0);
    col.setLabelProvider(new ColumnLabelProvider() {
        @Override
        public String getText(Object element) {
            AplotDatasetData item = (AplotDatasetData) element;
            return item.getDataset().toString();
        }
    });

    col = createTableViewerColumn(titles[1], bounds[1], 1);
    col.setLabelProvider(new ColumnLabelProvider() {
        @Override
        public String getText(Object element) {
            AplotDatasetData item = (AplotDatasetData) element;
            return item.getRev().toString();
        }
    });

    col = createTableViewerColumn(titles[2], bounds[2], 2);
    col.setLabelProvider(new ColumnLabelProvider() {
        @Override
        public String getText(Object element) {
            AplotDatasetData item = (AplotDatasetData) element;
            return item.getPRLValue();
        }
    });

    col = createTableViewerColumn(titles[3], bounds[3], 3);
    col.setLabelProvider(new ColumnLabelProvider() {
        @Override
        public String getText(Object element) {
            AplotDatasetData item = (AplotDatasetData) element;
            return item.getDatasetName();
        }
    });

    col = createTableViewerColumn(titles[4], bounds[4], 4);
    col.setLabelProvider(new ColumnLabelProvider() {
        @Override
        public String getText(Object element) {
            AplotDatasetData item = (AplotDatasetData) element;
            return item.getECMarkupValue();
        }
    });
}

 //////////////////////////////////////////////////////////////////////////
 //                       createTableViewerColumn()                      //
 //////////////////////////////////////////////////////////////////////////
private TableViewerColumn createTableViewerColumn(String title, int bound, final int colNumber) {
    final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
    final TableColumn column = viewerColumn.getColumn();
    column.setText(title);
    column.setWidth(bound);
    column.setResizable(true);
    column.setMoveable(true);
    return viewerColumn;
}

Question 1: Is this the best practice to adding a table to my GUI class? Seems like a lot of code for the GUI class.

Question 2: Should the createColumns() method and the createTableViewerColumn() method be moved to Class B?

Question 3: My last column in the table is going to be a dropdown/combo box. So I am going to have to extend one class with EditingSupport. Should it be Class A or Class B?

Before I go any farther with this project I want to make sure I have it correctly structured.

Answer

Favonius picture Favonius · Sep 5, 2012

Answering this question is like answering which ice-cream flavor do you like :)

Q & A

Question 1: Is this the best practice to adding a table to my GUI class? Seems like a lot of code for the GUI class.

If the code is less than its not a bad idea. But if -

  1. The code is large (for me if its more than 100 lines).
  2. Overall System is going to be more than some thousand of lines of code.
  3. Someone else is going to maintain it
  4. If I need plug-and-play nature, for example today Table is sufficient but in future I may use Grid.
  5. If I am doing some custom drawing (doing some custom painting on windows paint event) or using custom controls, THEN

I normally prefer to sub-class the viewer/control. In this way I could maintain the separation between the bare-bone message pumping code, GUI controls and my data model.

Question 2: Should the createColumns() method and the createTableViewerColumn() method be moved to Class B?

No, You should not. As in your case the class B is your data model/supplier. The JFace programming model supports MVC architecture and if possible one should follow it. Suggested solution is to have a new class extending the TableViewer.

Question 3: My last column in the table is going to be a dropdown/combo box. So I am going to have to extend one class with EditingSupport. Should it be Class A or Class B?

I would suggest you to go for a new class and use that in the extended TableViewer. One benefit is that in case you are writing data back to some db then your viewer class remain db/persistence layer agnostic.

Code Sample

Below is a simple sample application. As you can see I can change my combo editor to text editor just by changing the OptionEditingSupport class. And also, the code looks clean and concise.

Main Class