Eclipse RCP: Comboboxes inside a JFace TableViewer
A few days ago I had to replace a TreeViewer with checkboxes with a TableViewer using dropdown comboboxes to allow the user editing values inside the table. It took me quite some time to find some useful documentation on how to manage to do that. The eclipse snippet page just deals with SWT whereas I wanted to use JFace. A tutorial is provided by eclipse as well, but unfortunately it is about 7 years old. In addition the eclipse API is far away from being detailed and helpful. Have a look at the JavaDoc of the class EditingSupport for instance. It is supposed to be one of the important classes to add editing support to your TableViewer and it's description simply says "EditingSupport is the abstract superclass of the support for cell editing."...
Searching around the web I finally found two helpful links: a "JFace Table" tutorial on vogella.de and a german blog post about the "The Mysterious TableViewer". After reading this blog post (and after I was done integrating my own TableViewer of course), I decided to write a very basic howto about this topic as well.The example code was written and tested with Eclipse 3.6 (Helios) as target platform.
The Table Viewer
There is nothing really special about the TableViewer. The more interesting part is adding the EditingSupport for a column which I will describe later. The TableViewer in my example has two columns, uses a very basic LabelProvider (see Listing for ExampleTableLabelProvider) and an ArrayContentProvider. It displays some static sample data and uses TableLayout to arrange the columns. It is important for EditingSupport to create the Table with the SWT.FULL_SELECTION flag.
I split the whole example up in three classes: the class displaying the table, the LabelProvider and the Data. The example data class is a plain Java bean with getters and setters. It also defines a enum class with three possible values. These values are going to be editable by the user later:
public class ExampleData {
public static enum Value {
value1, value2, value3;
}
private String label;
private Value value;
public ExampleData(String label, Value data) {
this.label = label;
this.value = data;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public Value getData() {
return value;
}
public void setData(Value data) {
this.value = data;
}
}The LabelProvider implements the interface ITableLableProvider in order to provide the table with different labels for each column. Note that it extends the class LabelProvider to cover most of the interface methods, so we can focus on the important methods of our TableLabelProvider. You can also display different icons in every table cell by implementing the methodgetColumnImage. If you want to display your labels in different colors (foreground or background) you can simply implement the IColorProvider interface in your LabelProvider in addition to ITableLabelProvider.
public final class ExampleTableLabelProvider extends LabelProvider implements ITableLabelProvider {
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
public String getColumnText(Object element, int columnIndex) {
ExampleData data = (ExampleData) element;
switch (columnIndex) {
case 0:
return data.getLabel();
case 1:
return data.getData().name();
default:
return "";
}
}
}The following snippet shows the creation of the TableViewer (and its underlying table) itself. It shows the ExampleData objects by using the ExampleTableLabelProvider for displaying the data in the cells. Note that parent is an SWT Composite which contains the TableViewer and which uses GridLayout.
TableLayout tableLayout = new TableLayout();
tableLayout.addColumnData(new ColumnWeightData(1));
tableLayout.addColumnData(new ColumnWeightData(1));
Table exampleTable = new Table(parent, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL);
exampleTable.setLinesVisible(true);
exampleTable.setHeaderVisible(true);
exampleTable.setLayout(tableLayout);
TableViewer exampleTableViewer = new TableViewer(exampleTable);
exampleTableViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
TableViewerColumn labelColumn = new TableViewerColumn(exampleTableViewer, SWT.NONE);
labelColumn.getColumn().setText("Label");
TableViewerColumn valueColumn = new TableViewerColumn(exampleTableViewer, SWT.NONE);
valueColumn.getColumn().setText("Value");
exampleTableViewer.setContentProvider(new ArrayContentProvider());
exampleTableViewer.setLabelProvider(new ExampleTableLabelProvider());
ExampleData[] input = new ExampleData[]{new ExampleData("Label 1", Value.value1),
new ExampleData("Label 2", Value.value1),
new ExampleData("Label 3", Value.value1)};
exampleTableViewer.setInput(input);The result should look similar to that:

Adding Editing Support
After the TableViewer is created and displays the data, it is time to add the editing support to be able to change the values by a dropdown menu. Therefore a subclass of EditorSupport is created which uses a ComboBoxViewerCellEditor to enable editing. The cell editor must be provided with a LabelProvider, a ContentProvider and input data, which makes it very similar to the creation of the TableViewer. In fact the CellEditor is not displayed until the user clicks into the designated cell. Then the LabelProvider of the CellEditor takes over to display the data's label from the TableViewer's LabelProvider. This is basically the reason why the CellEditor needs its own providers.
As you can see in the code snippet below, I pass the SWT.READONLY flag when creating the CellEditor. Otherwise the user would be able to insert custom text into the dropdown box, instead of just being able to choose from the predetermined values.
Beside creating and returning a proper CellEditor the EditingSupport class must provide information about the values to change and the current selected value. This can be achieved by implementing the abstract methods getValue(Object element)and setValue(Object element, Object value).
public final class ExampleEditingSupport extends EditingSupport {
private ComboBoxViewerCellEditor cellEditor = null;
private ExampleEditingSupport(ColumnViewer viewer) {
super(viewer);
cellEditor = new ComboBoxViewerCellEditor((Composite) getViewer().getControl(), SWT.READ_ONLY);
cellEditor.setLabelProvider(new LabelProvider());
cellEditor.setContenProvider(new ArrayContentProvider());
cellEditor.setInput(Value.values());
}
@Override
protected CellEditor getCellEditor(Object element) {
return cellEditor;
}
@Override
protected boolean canEdit(Object element) {
return true;
}
@Override
protected Object getValue(Object element) {
if (element instanceof ExampleData) {
ExampleData data = (ExampleData)element;
return data.getData();
}
return null;
}
@Override
protected void setValue(Object element, Object value) {
if (element instanceof ExampleData && value instanceof Value) {
ExampleData data = (ExampleData) element;
Value newValue = (Value) value;
/* only set new value if it differs from old one */
if (!data.getData().equals(newValue)) {
data.setData(newValue);
}
}
}
}After the ExampleEditingSupport class is implemented, it has to be added to the correct table column. Just append the following lines to the part where the TableViewer is created.
[...] EditingSupport exampleEditingSupport = new ExampleEditingSupport(valueColumn.getViewer()); valueColumn.setEditingSupport(exampleEditingSupport); [...]
Now a dropdown menu should appear inside the right table cell after clicking inside.

Event Handling
After the EditingSupport is integrated you might want to add some event handling to the table in order to react to user choices. I found three ways to add event handling to the combobox:
1. Add an ICellEditorListener to the CellEditor when creating the editor in the constructor of the ExampleEditingSupport class. This listener gets notified when a value is applied, changed or editing is canceled.
cellEditor.addListener(new ICellEditorListener() {
...
});2. Add an ColumnViewerEditorActivationListener to the ColumnViewerEditor of the TableViewer, which gets notified when the user interacts with the cell editor.
exampleTableViewer.getColumnViewerEditor().addEditorActivationListener(new ColumnViewerEditorActivationListener() {
...
}3. Add a custom listener to your EditingSupport class and fire an event when you set a new value within the setValue(Object element, Object value) method.
Categories
Sophora CMS - A New Take on Content Management
Sophora is optimized to meet the needs of modern companies that produce up-to-date multimedia content on a large scale and that require fast delivery of their content.
Toromiro
Toromiro is a professional tool for the administration and editing of Java Content Repositories (JCR). JCR is powering some of today’s most successful solutions for content management and digital asset management.