03 - Working With JFace Viewers

We have already seen SWT in action. It helps in rapid application development by providing ready made widgets like Tree, Table etc. However, there is a severe limitation in using these widgets directly. Let me explain it with an example. Consider the table example in SWT chapter. Following lines of code were used to populate Table with one row of data.

TableItem tableItem1 = new TableItem(myTable, SWT.NULL);
tableItem1.setText(new String[] {"A1", "A2"});

You can see that we have used String Literals "A1" and "A2" respectively while creating a row in table. If you think from object oriented perspective it is a severe limitation. In object oriented world we talk in terms of Objects. In order to build above table we will have to get Strings out of those objects and then supply it to Table to form every single row. Isn’t there a way in which we can simply map objects to tables so that table can itself use those objects and populate itself? This is where JFace viewers step in to provide OO wrappers around their associated SWT widgets. JFace provides two types of Viewers, Text Viewers and List Viewers. First we will discuss about list viewers.

List Viewers

JFace list viewers, such as TableViewer and TreeViewer, allow you to directly use your business objects (Employee, Customer, User, Business etc.). The trick is to provide adapters for things such as retrieving an item's name/label OR for retrieving an Tree parent's children (tree widget). So we will talk about these adapters first before moving onto implementing Table/Tree Viewers.

1. Label Providers

A label provider maps an element of the viewer's model to an optional image and optional text string used to display the element in the viewer's control.

The two most frequently used label providers are ILabelProvider and ITableLabelProvider In order to display elements name and label we can use getImage and getText methods provided by ILabelProvider Similarly in case of ITableLabelProvider, in order to display label image and label text for any column in a table we can use getColumnImage and getColumnText. We can use setLabelProvider() method to attach/associate provider with the viewer.

2. Content Providers

A content provider is another common adapter type used in list viewers. This provider is used to feed the actual content to the viewer. Viewer then uses its internal logic to display these input elements with its internal controls. The two most frequently used content providers are IStructuredContentProvider and ITreeContentProvider. These adapters provide convienient methods to retrive child elements for a given element. We can use setContentProvider() method to attach/associate provider with the viewer. A intial domain/business model of the application can be associated with the viewer with the help of setInput() method.

3. Viewer Sorters

A viewer sorter is a adapter which is called by viewer before the elements/contents are displayed to the user. We can use this provider to sort the elements which are provided by the content provider. We can use setSorter() method on the viewer to attach sorter.

4. Viewer Filters Providers

As the name suggests a viewer filter is used to filter out some of the elements from original list of elements provided by the content provider. For example: Original list of Employees consist of employees with two type of roles Admin, Non admin. We can use filters to display only admin role users. We can attach viewer filter by using the setFilter() method on the viwer itself.

Table Viewers

The TableViewer class acts as a OO wrapper around the Table widget. Table Viewer is capable of displaying data in rows and cloumns with the help of adapters like label provider and content provider. Table Viewer provides many useful APIs, Please refer to online Eclipse Platform API Specification Following example creates a table viewer.

 public static void main(String[] args) {
      Display exampleDisplay = new Display();
      Shell exampleShell = new Shell(exampleDisplay);

      exampleShell.setBounds(120, 120, 345, 220);
      exampleShell.setLayout(new FillLayout());

      final TableViewer myTableViewer = new TableViewer(
         exampleShell, SWT.SINGLE);

       final Table myTable = myTableViewer.getTable();

       String[] myColumns = new String[] {
         "Hello", "Bye"};

       for (int i = 0; i < columnNames.length; i++) {
         TableColumn tableColumn =
            new TableColumn(myTable);
         tableColumn.setText(myColumns[i]);
      }

      myTableViewer.setLabelProvider(
         new ExampleLabelProvider());

      myTableViewer.setContentProvider(
         new ArrayContentProvider());

     myTableViewer.setInput(Example.getInput());

     exampleShell.open();

     while (!exampleShell.isDisposed()) {
         if (!exampleDisplay.readAndDispatch()) exampleDisplay.sleep();
      }

     exampleDisplay.dispose();
   }

In Above listing we are creating table viewer Then we are creating two columns namely "Hello" and "Bye" The header of each column is set using setText() method. There after label provider and content providers are being attached with the viewer. Following listing shows how the label provider looks like

public class PersonTableLabelProvider
   extends LabelProvider
   implements ITableLabelProvider {
   public Image getColumnImage(
      Object element, int) {
       return null;
   }

   public String getColumnText(Object element, int index) {
      Example ex = (Example) element;
      switch (index) {
         case 0 :
            return ex.hello;
         case 1 :
            return ex.bye;
      }
   }
}

   public class Example{
    String hello;

    String bye;

    Example(String hello, String bye){
        this.hello = hello;
        this.bye=bye;
    }

   public static Example[] getInput(){
     return new Example[]{
         new Example("FirstHello","FirstBye"),new Example("SecondHello","SecondBye")
     };
    }
}   

 

Tree Viewers

The treeViewer class acts as a OO wrapper around the Tree widget. Tree Viewer is capable of displaying data in hierarchical manner with the help of adapters like label provider and content provider. Tree Viewer provides many useful APIs, Please refer to online Eclipse Platform API Specification

The following listing creates a tree viewer

public static void main(String[] args) {
      Display exampleDisplay = new Display();
      Shell exampleShell = new Shell(exampleDisplay);

       exampleShell.setBounds(120, 120, 220, 220);
       exampleShell.setLayout(new FillLayout());

      final TreeViewer myTreeViewer =
         new TreeViewer(exampleShell, SWT.SINGLE);

      myTreeViewer.setLabelProvider(
         new MyTreeLabelProvider());


       myTreeViewer.setContentProvider(
         new MyTreeContentProvider());

       myTreeViewer.setInput(Example1.getInput());

       exampleShell.open();

      while (!exampleShell.isDisposed()) {
         if (!exampleDisplay.readAndDispatch()) exampleDisplay.sleep();
      }
      exampleDisplay.dispose();
}

In above code listing we are creating the tree viewer. There after we are configuring label and content adapters. Following listing shows the rest of code:

public class MyTreeContentProvider
   extends ArrayContentProvider
   implements ITreeContentProvider {

   public Object[] getChildren(Object parent) {
      Example1 ex1 = (Example1) parent;
      return ex1.children;
   }

   public Object getParent(Object element) {
      Example1 ex1 = (Example1) element;
      return ex1.parent;
   }

    public boolean hasChildren(Object element) {
      Example1 ex1 = (Example1) element;
      return ex1.children.length > 0;
   }
}


public class MyTreeLabelProvider extends LabelProvider {
   public Image getImage(Object element) {
      return null;
   }
   public String getText(Object element) {
      Example1 ex1 = (Example1) element;
      return ex1.name;
   }
}

public class Example1{
    String name;

    Example1[] children = new Example1[0];

    Example1 parent = null;

    Example1(String name){
        this.name = name;
    }

    Example1(String name,Example1[] children){
        this.name = name;
        this.children = children;
        for (int i = 0; i < children.length; i++) {
                 children[i].parent = this;
      }
    }

    public static Example1[] getInput(){
     return new Example1[]{
         new Example1("First",new Example1[]
             {new Example1("Child1"), new Example1("Child2")}),
             new Example1("Second",new Example1[]{
                  new Example1("Child3"),new Example1("Child4")}
         )
     };
    }
}

 

Like us on Facebook