Java, Eclipse and Web programming Tutorials
Follow me on twitter About Lars Vogel

Eclipse JFace TableViewer - Tutorial

Clemens Muessener, Lars Vogel

Version 1.9

22.02.2010

Revision History
Revision 0.101.07.2007Clemens Muessener
Created Article
Revision 0.212.09.2007Lars Vogel
Revised Article
Revision 0.320.03.2008Hendrik Still
Added Editors, navigation via tab
Revision 0.412.10.2008Marcus Rieck
Added Sort Columns / Show Hide Columns and
Revision 0.521.03.2009Lars Vogel
Re-worked article, added explanation about the general concept of JFace
Revision 0.622.03.2009Lars Vogel
Correct usage of setInput() in View.java
Revision 0.723.03.2009Lars Vogel
Changed project and package name
Revision 0.824.03.2009Lars Vogel
Fixed the sorter coding
Revision 0.929.03.2009Lars Vogel
Added filter
Revision 1.030.03.2009Lars Vogel
Added StyledCellLabelProvider
Revision 1.120.04.2009Lars Vogel
Minor clean-up in PersonEditingSupport
Revision 1.220.05.2009Lars Vogel
Show / Hide using the menu on the table using Eclipse 3.5
Revision 1.327.07.2009Lars Vogel
Fixed StyledLabelProvider
Revision 1.405.08.2009Lars Vogel
Fixed sorter for Persons
Revision 1.502.09.2009Lars Vogel
removed hard-coded image location against Activator.getImageDescriptor()
Revision 1.608.09.2009Lars Vogel
Fixed incorrect import in LabelProvider
Revision 1.710.09.2009Lars Vogel
added TreeNodeContentProvider and LabelProvider explanation
Revision 1.816.12.2009Lars Vogel
LabelProvider is also template for ITableLabelProvider
Revision 1.922.02.2010Lars Vogel
Fixed typo

Eclipse JFace Table

This article explains the usage of Eclipse JFace TableViewer including label and contentprovider, filtering, sorting, and model / view interaction.

This article is based on Eclipse 3.5.


Table of Contents

1. Eclipse JFace viewers
1.1. Overview
1.2. Viewer, content and label provider
1.3. Viewer
1.4. Content provider
1.5. Label provider
2. Overview of the example
3. Create a project
4. Create the model
5. Content and LabelProvider
5.1. Build your ContentProvider
5.2. Build your LabelProvider
5.3. Use the providers
5.4. Run
6. Cell Editors
7. Sort Columns
8. Filter
9. Highlighting elements - StyledCellLabelProvider
10. Show/Hide Columns
11. Commands
11.1. Print the model content
11.2. Add and delete a person to and from the model
11.3. Copy data to the system clipboard
12. Thank you
13. Questions and Discussion
14. Download
15. Links and Literature
15.1. Source Code
15.2. JFace Resources
15.3. Other Resources

1. Eclipse JFace viewers

1.1. Overview

Eclipse JFace viewers allow to display a domain model in a list, tree or table without converting the domain model beforehand.

These viewers provider adaptors which are used to provide the model to the viewer (these are called content provider) and adaptors to define how the model data is displayed in the viewer (these are called label providers).

The Eclipse JFace viewer concept is very flexible as it allows to use the same content provider / label provider in different viewers without changing the underlying data structure.

JFace also allows assign label provider directly to columns instead of one label provider for the whole table.

1.2. Viewer, content and label provider

In working with JFace viewers it is important to understand the concept of viewers, label and content providers. The following provides an overview and lists some typical classes in these areas.

1.3. Viewer

The user interface is represented by the viewer, e.g. in our example the table viewer.

Viewer: Typical viewers are

  • org.eclipse.jface.viewers.ListViewer - Display a simple list

  • org.eclipse.jface.viewers.TreeViewer - Displays a tree

  • org.eclipse.jface.viewers.TableViewer - Displays a table

1.4. Content provider

Responsible for providing objects to the view. It can simply return objects as-is.

Typical content provider are

  • IStructuredContentProvider: Used for lists and tables

  • ITreeContentProvider: Used for trees, has addional methods to determine the children and the parents of elements

1.5. Label provider

Defines how objects are displayed, e.g. which part of the object is used to return the text which is displayed.

Label provider follow usually the template approach; you have an interface which describes and contact and a class which the programmer can use which delivers already reasonable implementations for the interface and the programmer can then choose to override only the relevant methods.

Typical label providers are

Table 1. Label providers

InterfaceTemplate classDescription
ILabelProviderLabelProviderUsed for lists and trees, displays per element a icons and / or a text element.
ITableLabelProviderLabelProviderUsed for tables, displays per element and column a icons and / or a text element

2. Overview of the example

In this tutorial we will build a Eclipse RCP application which will display a domain model in a JFace table. The domain modelrepresents the data of persons (first name, last name, gender and if he/she is married). Each person is displayed in one row in the table.

Different editors and label provider will be used for different data types. The article demonstrate how to sort based on different table columns and how to use filters to display only selected content of the viewer. We will then learn how to use StyledCellLabelProvider to influence the display of data in the table. The usage of commands and how to hide and sort table columns is demonstrated.

The application will also be able to change the first name and last name like a text editor, the gender by a drop down list and the married status by a checkbox. You can edit the objects on two ways: an inline editor in the table and within a editor.

Via the menu it will be possible to add new persons to the table and to remove persons from the table. You will also be able to show/hide columns.

The final application will look like this.

3. Create a project

Create a new RCP Project "de.vogella.jface.tableviewer" (see Create your first Eclipse RCP application for details). Use the "RCP application with a view" as a template.

4. Create the model

Create a package "de.vogella.jface.tableviewer.model".

Create the following class "Person". This class contains the first name, last name, gender and married status for a person and represents the data model for this example.

			
package de.vogella.jface.tableviewer.model;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class Person {
	private String firstName;
	private String lastName;
	private boolean married;
	private String gender;
	private Integer age;
	private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(
			this);

	public Person() {
	}

	public Person(String firstName, String lastName, String gender,
			boolean married) {
		super();
		this.firstName = firstName;
		this.lastName = lastName;
		this.gender = gender;
		this.married = married;
	}

	public void addPropertyChangeListener(String propertyName,
			PropertyChangeListener listener) {
		propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
	}

	public void removePropertyChangeListener(PropertyChangeListener listener) {
		propertyChangeSupport.removePropertyChangeListener(listener);
	}

	public String getFirstName() {
		return firstName;
	}

	public String getGender() {
		return gender;
	}

	public String getLastName() {
		return lastName;
	}

	public boolean isMarried() {
		return married;
	}

	public void setFirstName(String firstName) {
		propertyChangeSupport.firePropertyChange("firstName", this.firstName,
				this.firstName = firstName);
	}

	public void setGender(String gender) {
		propertyChangeSupport.firePropertyChange("gender", this.gender,
				this.gender = gender);
	}

	public void setLastName(String lastName) {
		propertyChangeSupport.firePropertyChange("lastName", this.lastName,
				this.lastName = lastName);
	}

	public void setMarried(boolean isMarried) {
		propertyChangeSupport.firePropertyChange("married", this.married,
				this.married = isMarried);
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		propertyChangeSupport.firePropertyChange("age", this.age,
				this.age = age);
	}

	@Override
	public String toString() {
		return firstName + " " + lastName;
	}

}
		

Tip

This class has also propertyChange support, which is not necessary for this example. Feel free to ignore this and implement your own POJO's with only the getter and setters.

Now create a class, called "ModelProvider". This class will be providing the collection of persons. This class is defined as a Singleton (see The Singleton Pattern for details).

			
package de.vogella.jface.tableviewer.model;

import java.util.ArrayList;
import java.util.List;

public class ModelProvider {

	private static ModelProvider content;
	private List<Person> persons;

	private ModelProvider() {
		persons = new ArrayList<Person>();
		// Image here some fancy database access to read the persons and to
		// put them into the model
		Person person;
		person = new Person("Rainer", "Zufall", "male", true);
		persons.add(person);
		person = new Person("Rainer", "Babbel", "male", true);
		persons.add(person);
		person = new Person("Marie", "Darms", "female", false);
		persons.add(person);
		person = new Person("Holger", "Adams", "male", true);
		persons.add(person);
		person = new Person("Juliane", "Adams", "female", true);
		persons.add(person);

	}

	public static synchronized ModelProvider getInstance() {
		if (content != null) {
			return content;
		}
		content = new ModelProvider();
		return content;
	}

	public List<Person> getPersons() {
		return persons;
	}

}

		

5. Content and LabelProvider

The application you have created already contains a pre-defined view. This is because we used the template "RCP application with a view". In this view a content provider and a label provider are given and assigned to a table viewer. Open now the class View.java and review and the method "createPartControl".

The following will replace these default providers with our own providers.

5.1. Build your ContentProvider

Create your own Content Provider. First create the package "de.vogella.jface.tableviewer.providers". Create the class "PersonContentProvider" which implement the Interface "org.eclipse.jface.viewers.IStructuredContentProvider". The class "PersonContentProvider" reads the data model and to return the data as an array.

Tip

It is important to note that within the content provider no assumption is made how and which data of the data model is displayed by the view. This is the responsibility of the label provider.

				
package de.vogella.jface.tableviewer.providers;

import java.util.List;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;

import de.vogella.jface.tableviewer.model.Person;

public class PersonContentProvider implements IStructuredContentProvider {

	@Override
	public Object[] getElements(Object inputElement) {
		@SuppressWarnings("unchecked")
		List<Person> persons = (List<Person>) inputElement;
		return persons.toArray();
	}

	@Override
	public void dispose() {
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
	}

}

			

The method getElements() will be called by the viewer. The viewer has method setInput(). This input will be provided to the contentProvider as the parameter in method getElements().

5.2. Build your LabelProvider

We will use icons for the married Status. If the folder "icons" does not exists in your project create it. Download the icons from the link provided at the end of this article and place the two icons in the folder icons.

Tip

You can also return null in the method getColumnImage() of the label provider in case you don't want to use the icons.

The class "View" already contains a Label Provider from the example. Currently the toString() method of the object Person is used in this label provider. We will replace this default label provider with our own label providers.

Create class "PersonLabelProvider" implementing the interface org.eclipse.jface.viewers.ITableLabelProvider.

				
package de.vogella.jface.tableviewer.providers;

import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.graphics.Image;
import de.vogella.jface.tableviewer.Activator;

import de.vogella.jface.tableviewer.model.Person;

public class PersonLabelProvider extends LabelProvider implements
		ITableLabelProvider {
	// We use icons
	// We use icons
	private static final Image CHECKED = Activator.getImageDescriptor(
			"icons/checked.gif").createImage();
	private static final Image UNCHECKED = Activator.getImageDescriptor(
					"icons/unchecked.gif").createImage();

	@Override
	public Image getColumnImage(Object element, int columnIndex) {
		// In case you don't like image just return null here
		if (columnIndex == 3) {
			if (((Person) element).isMarried()) {
				return CHECKED;
			} else {
				return UNCHECKED;
			}
		}
		return null;
	}

	@Override
	public String getColumnText(Object element, int columnIndex) {
		Person person = (Person) element;
		switch (columnIndex) {
		case 0:
			return person.getFirstName();
		case 1:
			return person.getLastName();
		case 2:
			return person.getGender();
		case 3:
			return String.valueOf(person.isMarried());
		default:
			throw new RuntimeException("Should not happen");
		}

	}

}

			

Important thing to note:

  • getColumnText: will return the value for a certain element, e.g. in our example row and column. May not be null.

  • getColumnImage: will return the image for a certain element and a certain column. May be null

5.3.  Use the providers

We have to change the class "View.java" to use our content and label providers. We will also delete the internal class ViewLabelProvider and ViewContentProvider which the tempate generated.

				
package de.vogella.jface.tableviewer;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.part.ViewPart;

import de.vogella.jface.tableviewer.model.ModelProvider;
import de.vogella.jface.tableviewer.providers.PersonContentProvider;
import de.vogella.jface.tableviewer.providers.PersonLabelProvider;

public class View extends ViewPart {
	public static final String ID = "de.vogella.jface.tableviewer.view";

	private TableViewer viewer;

	public void createPartControl(Composite parent) {
		createViewer(parent);
		// Get the content for the viewer, setInput will call getElements in the
		// contentProvider
		viewer.setInput(ModelProvider.getInstance().getPersons());
	}

	private void createViewer(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.FULL_SELECTION);
		createColumns(viewer);
		viewer.setContentProvider(new PersonContentProvider());
		viewer.setLabelProvider(new PersonLabelProvider());
	}

	// This will create the columns for the table
	private void createColumns(TableViewer viewer) {

		String[] titles = { "First name", "Last name", "Gender", "Married" };
		int[] bounds = { 100, 100, 100, 100 };

		for (int i = 0; i < titles.length; i++) {
			TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
			column.getColumn().setText(titles[i]);
			column.getColumn().setWidth(bounds[i]);
			column.getColumn().setResizable(true);
			column.getColumn().setMoveable(true);
		}
		Table table = viewer.getTable();
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}

			

The method createColumns create the table columns, headers, sets the size of the columns, makes the columns resizable and show the lines in the table.

5.4. Run

Run the example. The application should look like this.

6. Cell Editors

A cell editor defines how the user can edit certain cells of a table.

We will define the editors for our table. The "First name" and "Last name" column will be editable by a textfield. The "Gende"’ column will be editable by a drop down list and the "Married" column will be editable by a checkbox.

Create a new class with the name "PersonEditingSupport" in package de.vogella.jface.tableviewer.providers.

			
package de.vogella.jface.tableviewer.providers;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;

import de.vogella.jface.tableviewer.model.Person;

public class PersonEditingSupport extends EditingSupport {
	private CellEditor editor;
	private int column;

	public PersonEditingSupport(ColumnViewer viewer, int column) {
		super(viewer);

		String[] gender = new String[2];
		gender[0] = "male";
		gender[1] = "female";

		// Create the correct editor based on the column index
		switch (column) {
		case 2:
			editor = new ComboBoxCellEditor(((TableViewer) viewer).getTable(),
					gender);
			break;
		case 3:
			editor = new CheckboxCellEditor(null, SWT.CHECK | SWT.READ_ONLY);
			break;
		default:
			editor = new TextCellEditor(((TableViewer) viewer).getTable());
		}
		this.column = column;
	}

	@Override
	protected boolean canEdit(Object element) {
		return true;
	}

	@Override
	protected CellEditor getCellEditor(Object element) {
		return editor;
	}

	@Override
	protected Object getValue(Object element) {
		Person person = (Person) element;

		switch (this.column) {
		case 0:
			return person.getFirstName();
		case 1:
			return person.getLastName();
		case 2:
			if (person.getGender().equals("male")) {
				return 0;
			}
			return 1;
		case 3:
			return person.isMarried();
		default:
			break;
		}
		return null;
	}

	@Override
	protected void setValue(Object element, Object value) {
		Person pers = (Person) element;

		switch (this.column) {
		case 0:
			pers.setFirstName(String.valueOf(value));
			break;
		case 1:
			pers.setLastName(String.valueOf(value));
			break;
		case 2:
			if (((Integer) value) == 0) {
				pers.setGender("male");
			} else {
				pers.setGender("female");
			}
			break;
		case 3:
			pers.setMarried((Boolean) value);
			break;
		default:
			break;
		}

		getViewer().update(element, null);
	}

}

		

Explanation of the the main methods of "PersonEditingSupport":

  • ‘getCellEditor’ : In this method you return the celleditor you want to use (e.g. Texteditor). I work with a ‘switch-case-command’ to split my columns and give every column its own celleditor.

  • ‘setValue’: Receives the new value the user gives. You have to set the new value to the object which is given, too.

  • ‘getValue’: Receives the object which was changed and returns the value for the table. You have to return the new value of the object.

Now assign the editors to your columns. We do this in View.java in the method createColumns().

			
// This will create the columns for the table
	private void createColumns(TableViewer viewer) {

		String[] titles = { "First name", "Last name", "Gender", "Married" };
		int[] bounds = { 100, 100, 100, 100 };

		for (int i = 0; i < titles.length; i++) {
			TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
			column.getColumn().setText(titles[i]);
			column.getColumn().setWidth(bounds[i]);
			column.getColumn().setResizable(true);
			column.getColumn().setMoveable(true);
			// enable editing support
			column.setEditingSupport(new PersonEditingSupport(viewer, i));
		}
		Table table = viewer.getTable();
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
	}
		

Run now your application. You should now be able to modify the content of the JFace table.

7. Sort Columns

This chapter explains how to to sort the columns of the table ascending/descending.

Create a new Class "de.vogella.jface.tableviewer.sorter.TableSorter.java"

			
package de.vogella.jface.tableviewer.sorter;

import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;

import de.vogella.jface.tableviewer.model.Person;

public class TableSorter extends ViewerSorter {
	private int propertyIndex;
	// private static final int ASCENDING = 0;
	private static final int DESCENDING = 1;

	private int direction = DESCENDING;

	public TableSorter() {
		this.propertyIndex = 0;
		direction = DESCENDING;
	}

	public void setColumn(int column) {
		if (column == this.propertyIndex) {
			// Same column as last sort; toggle the direction
			direction = 1 - direction;
		} else {
			// New column; do an ascending sort
			this.propertyIndex = column;
			direction = DESCENDING;
		}
	}

	@Override
	public int compare(Viewer viewer, Object e1, Object e2) {
		Person p1 = (Person) e1;
		Person p2 = (Person) e2;
		int rc = 0;
		switch (propertyIndex) {
		case 0:
			rc = p1.getFirstName().compareTo(p2.getFirstName());
			break;
		case 1:
			rc = p1.getLastName().compareTo(p2.getLastName());
			break;
		case 2:
			rc = p1.getGender().compareTo(p2.getGender());
			break;
		case 3:
			if (p1.isMarried() == p2.isMarried()) {
				rc = 0;
			} else
				rc = (p1.isMarried() ? 1 : -1);
			break;
		default:
			rc = 0;
		}
		// If descending order, flip the direction
		if (direction == DESCENDING) {
			rc = -rc;
		}
		return rc;
	}
}
		

Add a listener to the view for setting the information which column should be sorted. Change View.java to the following-

			
package de.vogella.jface.tableviewer;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.part.ViewPart;

import de.vogella.jface.tableviewer.model.ModelProvider;
import de.vogella.jface.tableviewer.providers.PersonContentProvider;
import de.vogella.jface.tableviewer.providers.PersonEditingSupport;
import de.vogella.jface.tableviewer.providers.PersonLabelProvider;
import de.vogella.jface.tableviewer.sorter.TableSorter;

public class View extends ViewPart {
	public static final String ID = "de.vogella.jface.tableviewer.view";

	private TableViewer viewer;

	private TableSorter tableSorter;

	public void createPartControl(Composite parent) {
		createViewer(parent);
		// Get the content for the viewer, setInput will call getElements in the
		// contentProvider
		viewer.setInput(ModelProvider.getInstance().getPersons());
		// Make the selection available
		getSite().setSelectionProvider(viewer);
		// Set the sorter for the table
		tableSorter = new TableSorter();
		viewer.setSorter(tableSorter);

	}
	
	private void createViewer(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.FULL_SELECTION);
		createColumns(viewer);
		viewer.setContentProvider(new PersonContentProvider());
		viewer.setLabelProvider(new PersonLabelProvider());
	}

	public TableViewer getViewer() {
		return viewer;
	}

	// This will create the columns for the table
	private void createColumns(final TableViewer viewer) {
		Table table = viewer.getTable();
		String[] titles = { "First name", "Last name", "Gender", "Married" };
		int[] bounds = { 100, 100, 100, 100 };

		for (int i = 0; i < titles.length; i++) {
			final int index = i;
			final TableViewerColumn viewerColumn = new TableViewerColumn(
					viewer, SWT.NONE);
			final TableColumn column = viewerColumn.getColumn();
			column.setText(titles[i]);
			column.setWidth(bounds[i]);
			column.setResizable(true);
			column.setMoveable(true);
			// Setting the right sorter
			column.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					tableSorter.setColumn(index);
					int dir = viewer.getTable().getSortDirection();
					if (viewer.getTable().getSortColumn() == column) {
						dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
					} else {

						dir = SWT.DOWN;
					}
					viewer.getTable().setSortDirection(dir);
					viewer.getTable().setSortColumn(column);
					viewer.refresh();
				}
			});
			viewerColumn.setEditingSupport(new PersonEditingSupport(viewer, i));
		}
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}
		

Run the example, click on a column, there will appear a sort-direction signifier and your items are ordered ascending or descending.

8. Filter

Now we would like to add a filter to the table. The user should have a text field in which we can enter a first- or lastname. Only the names which applies to this filter should get displayed.

Adding a filter to a view is simple, you use method addFilter() on the viewer, which expects a ViewFilter as argument. Each ViewFilter is checked the input on the viewer is changed of whenever the viewer.refresh();

Create a new Class "de.vogella.jface.tableviewer.filter.PersonFilter.java"

			
package de.vogella.jface.tableviewer.filter;

import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;

import de.vogella.jface.tableviewer.model.Person;

public class PersonFilter extends ViewerFilter {

	private String searchString;

	public void setSearchText(String s) {
		// Search must be a substring of the existing value
		this.searchString = ".*" + s + ".*";
	}

	@Override
	public boolean select(Viewer viewer, Object parentElement, Object element) {
		if (searchString == null || searchString.length() == 0) {
			return true;
		}
		Person p = (Person) element;
		if (p.getFirstName().matches(searchString)) {
			return true;
		}
		if (p.getLastName().matches(searchString)) {
			return true;
		}

		return false;
	}
}

		

We will create a new text field in which the user can search. This text field will have a keyListener which updates the filter and the viewer. Change the View.java to the following .

			
package de.vogella.jface.tableviewer;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

import de.vogella.jface.tableviewer.filter.PersonFilter;
import de.vogella.jface.tableviewer.model.ModelProvider;
import de.vogella.jface.tableviewer.providers.PersonContentProvider;
import de.vogella.jface.tableviewer.providers.PersonEditingSupport;
import de.vogella.jface.tableviewer.providers.PersonLabelProvider;
import de.vogella.jface.tableviewer.sorter.TableSorter;

public class View extends ViewPart {
	public static final String ID = "de.vogella.jface.tableviewer.view";

	private TableViewer viewer;

	private TableSorter tableSorter;

	private PersonFilter filter;

	public void createPartControl(Composite parent) {
		GridLayout layout = new GridLayout(2, false);
		parent.setLayout(layout);
		Label searchLabel = new Label(parent, SWT.NONE);
		searchLabel.setText("Search: ");
		final Text searchText = new Text(parent, SWT.BORDER | SWT.SEARCH);
		searchText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
				| GridData.HORIZONTAL_ALIGN_FILL));
		searchText.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent ke) {
				filter.setSearchText(searchText.getText());
				viewer.refresh();
			}

		});
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
		createColumns(viewer);
		viewer.setContentProvider(new PersonContentProvider());
		viewer.setLabelProvider(new PersonLabelProvider());
		// Get the content for the viewer, setInput will call getElements in the
		// contentProvider
		viewer.setInput(ModelProvider.getInstance().getPersons());
		// Make the selection available
		getSite().setSelectionProvider(viewer);
		// Set the sorter for the table
		tableSorter = new TableSorter();
		viewer.setSorter(tableSorter);
		filter = new PersonFilter();
		viewer.addFilter(filter);

		// Layout the viewer
		GridData gridData = new GridData();
		gridData.verticalAlignment = GridData.FILL;
		gridData.horizontalSpan = 2;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = GridData.FILL;
		viewer.getControl().setLayoutData(gridData);
	}

	public TableViewer getViewer() {
		return viewer;
	}

	// This will create the columns for the table
	private void createColumns(final TableViewer viewer) {
		Table table = viewer.getTable();
		String[] titles = { "First name", "Last name", "Gender", "Married" };
		int[] bounds = { 100, 100, 100, 100 };

		for (int i = 0; i < titles.length; i++) {
			final int index = i;
			final TableViewerColumn viewerColumn = new TableViewerColumn(
					viewer, SWT.NONE);
			final TableColumn column = viewerColumn.getColumn();
			column.setText(titles[i]);
			column.setWidth(bounds[i]);
			column.setResizable(true);
			column.setMoveable(true);
			// Setting the right sorter
			column.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					tableSorter.setColumn(index);
					int dir = viewer.getTable().getSortDirection();
					if (viewer.getTable().getSortColumn() == column) {
						dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
					} else {

						dir = SWT.DOWN;
					}
					viewer.getTable().setSortDirection(dir);
					viewer.getTable().setSortColumn(column);
					viewer.refresh();
				}
			});
			viewerColumn.setEditingSupport(new PersonEditingSupport(viewer, i));
		}
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}
		

Run the example, filtering should work.

9. Highlighting elements - StyledCellLabelProvider

It is also possible to use a StyleCellLabelProvider to highlight the search result. StyleCellLabelProvider can do much more but we will look at the simple case.

First create the following helper class which will determine which occurrence of the search string is in the column.

			
package de.vogella.jface.tableviewer.util;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.widgets.Display;

public class SearchUtil {
	public static int[] getSearchTermOccurrences(String searchTerm,
			String content) {
		List<StyleRange> styleRange;
		List<Integer> ranges;
		Display disp = Display.getCurrent();
		StyleRange myStyleRange = new StyleRange(0, 0, null, disp
				.getSystemColor(SWT.COLOR_YELLOW));

		styleRange = new ArrayList<StyleRange>(); // reset the StyleRange-Array
		// for each new field
		ranges = new ArrayList<Integer>(); // reset the ranges-array
		// empty search term ==> return an empty StyleRange array
		if (searchTerm.equals("")) {
			return new int[] {};
		}

		// determine all occurrences of the searchText and write the beginning
		// and length of each occurrence into an array
		for (int i = 0; i < content.length(); i++) {
			if (i + searchTerm.length() <= content.length()
					&& content.substring(i, i + searchTerm.length())
							.equalsIgnoreCase(searchTerm)) {
				// ranges format: n->start of the range, n+1->length of the
				// range
				ranges.add(i);
				ranges.add(searchTerm.length());
			}
		}
		// convert the list into an int[] and make sure that overlapping
		// search term occurrences are are merged
		int[] intRanges = new int[ranges.size()];
		int arrayIndexCounter = 0;
		for (int listIndexCounter = 0; listIndexCounter < ranges.size(); listIndexCounter++) {
			if (listIndexCounter % 2 == 0) {
				if (searchTerm.length() > 1
						&& listIndexCounter != 0
						&& ranges.get(listIndexCounter - 2)
								+ ranges.get(listIndexCounter - 1) >= ranges
								.get(listIndexCounter)) {
					intRanges[arrayIndexCounter - 1] = 0
							- ranges.get(listIndexCounter - 2)
							+ ranges.get(listIndexCounter)
							+ ranges.get(++listIndexCounter);
				} else {
					intRanges[arrayIndexCounter++] = ranges
							.get(listIndexCounter);
				}
			} else {
				intRanges[arrayIndexCounter++] = ranges.get(listIndexCounter);
				styleRange.add(myStyleRange);
			}
		}
		// if there have been any overlappings we need to reduce the size of
		// the array to avoid conflicts in the setStyleRanges method
		int[] intRangesCorrectSize = new int[arrayIndexCounter];
		System.arraycopy(intRanges, 0, intRangesCorrectSize, 0,
				arrayIndexCounter);

		return intRangesCorrectSize;
	}
}

		

Change your PersonLabelProvider to the following.

			
package de.vogella.jface.tableviewer.providers;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import de.vogella.jface.tableviewer.Activator;

import de.vogella.jface.tableviewer.model.Person;
import de.vogella.jface.tableviewer.util.SearchUtil;

public class PersonLabelProvider extends StyledCellLabelProvider {
	// We use icons
	private static final Image CHECKED = Activator.getImageDescriptor(
			"icons/checked.gif").createImage();
	private static final Image UNCHECKED = Activator.getImageDescriptor(
					"icons/unchecked.gif").createImage();
	private String searchText;
	private Color systemColor;

	public PersonLabelProvider() {
		systemColor = Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW);
	}

	public void setSearchText(String searchText) {
		this.searchText = searchText;

	}

	@Override
	public void update(ViewerCell cell) {
		Person element = (Person) cell.getElement();
		int index = cell.getColumnIndex();
		String columnText = getColumnText(element, index);
		cell.setText(columnText);
		cell.setImage(getColumnImage(element, index));
		if (searchText != null && searchText.length() > 0) {
			int intRangesCorrectSize[] = SearchUtil.getSearchTermOccurrences(
					searchText, columnText);
			List<StyleRange> styleRange = new ArrayList<StyleRange>();
			for (int i = 0; i < intRangesCorrectSize.length / 2; i++) {
				StyleRange myStyleRange = new StyleRange(0, 0, null,
						systemColor);
				myStyleRange.start = intRangesCorrectSize[i];
				myStyleRange.length = intRangesCorrectSize[++i];
				styleRange.add(myStyleRange);
			}
			cell.setStyleRanges(styleRange.toArray(new StyleRange[styleRange
					.size()]));
		} else {
			cell.setStyleRanges(null);
		}
	
		super.update(cell);

	}

	private String getColumnText(Object element, int columnIndex) {
		Person person = (Person) element;
		switch (columnIndex) {
		case 0:
			return person.getFirstName();
		case 1:
			return person.getLastName();
		case 2:
			return person.getGender();
		case 3:
			return String.valueOf(person.isMarried());
		default:
			throw new RuntimeException("Should not happen");
		}
	}

	private Image getColumnImage(Object element, int columnIndex) {
		// In case you don't like image just return null here
		if (columnIndex == 3) {
			if (((Person) element).isMarried()) {
				return CHECKED;
			}
			return UNCHECKED;
		}
		return null;
	}

}

		

Make the following changes to the View. .

			
package de.vogella.jface.tableviewer;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

import de.vogella.jface.tableviewer.filter.PersonFilter;
import de.vogella.jface.tableviewer.model.ModelProvider;
import de.vogella.jface.tableviewer.providers.PersonContentProvider;
import de.vogella.jface.tableviewer.providers.PersonEditingSupport;
import de.vogella.jface.tableviewer.providers.PersonLabelProvider;
import de.vogella.jface.tableviewer.sorter.TableSorter;

public class View extends ViewPart {
	public static final String ID = "de.vogella.jface.tableviewer.view";

	private TableViewer viewer;

	private TableSorter tableSorter;

	private PersonFilter filter;

	private PersonLabelProvider labelProvider;

	public void createPartControl(Composite parent) {
		GridLayout layout = new GridLayout(2, false);
		parent.setLayout(layout);
		Label searchLabel = new Label(parent, SWT.NONE);
		searchLabel.setText("Search: ");
		final Text searchText = new Text(parent, SWT.BORDER | SWT.SEARCH);
		searchText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
				| GridData.HORIZONTAL_ALIGN_FILL));
		searchText.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent ke) {
				filter.setSearchText(searchText.getText());
				labelProvider.setSearchText(searchText.getText());
				viewer.refresh();
			}
		});
		
		createViewer(parent);
		
		
		// Get the content for the viewer, setInput will call getElements in the
		// contentProvider
		viewer.setInput(ModelProvider.getInstance().getPersons());
		// Make the selection available
		getSite().setSelectionProvider(viewer);
		// Set the sorter for the table
		tableSorter = new TableSorter();
		viewer.setSorter(tableSorter);
		filter = new PersonFilter();
		viewer.addFilter(filter);

		// Layout the viewer
		GridData gridData = new GridData();
		gridData.verticalAlignment = GridData.FILL;
		gridData.horizontalSpan = 2;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = GridData.FILL;
		viewer.getControl().setLayoutData(gridData);
	}
	private void createViewer(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
		createColumns(viewer);
		viewer.setContentProvider(new PersonContentProvider());
		labelProvider = new PersonLabelProvider();
		viewer.setLabelProvider(labelProvider);
	}

	public TableViewer getViewer() {
		return viewer;
	}

	// This will create the columns for the table
	private void createColumns(final TableViewer viewer) {
		Table table = viewer.getTable();
		String[] titles = { "First name", "Last name", "Gender", "Married" };
		int[] bounds = { 100, 100, 100, 100 };

		for (int i = 0; i < titles.length; i++) {
			final int index = i;
			final TableViewerColumn viewerColumn = new TableViewerColumn(
					viewer, SWT.NONE);
			final TableColumn column = viewerColumn.getColumn();
			column.setText(titles[i]);
			column.setWidth(bounds[i]);
			column.setResizable(true);
			column.setMoveable(true);
			// Setting the right sorter
			column.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					tableSorter.setColumn(index);
					int dir = viewer.getTable().getSortDirection();
					if (viewer.getTable().getSortColumn() == column) {
						dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
					} else {

						dir = SWT.DOWN;
					}
					viewer.getTable().setSortDirection(dir);
					viewer.getTable().setSortColumn(column);
					viewer.refresh();
				}
			});
			viewerColumn.setEditingSupport(new PersonEditingSupport(viewer, i));
		}
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}
		

Run the example, if you search now the selected content should get highlighted should work.

10. Show/Hide Columns

This chapter shows how to implement a menu on the table which allows to show and hide columns of the table. Please note that Eclipse 3.5 introduced the possibility to add menus to columns headers.

Tip

This example is based on SWT Snippet 311

Change your coding in View.java to the following.

			
package de.vogella.jface.tableviewer;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

import de.vogella.jface.tableviewer.filter.PersonFilter;
import de.vogella.jface.tableviewer.model.ModelProvider;
import de.vogella.jface.tableviewer.providers.PersonContentProvider;
import de.vogella.jface.tableviewer.providers.PersonEditingSupport;
import de.vogella.jface.tableviewer.providers.PersonLabelProvider;
import de.vogella.jface.tableviewer.sorter.TableSorter;

public class View extends ViewPart {
	public static final String ID = "de.vogella.jface.tableviewer.view";

	private TableViewer viewer;

	private TableSorter tableSorter;

	private PersonFilter filter;

	private PersonLabelProvider labelProvider;

	public void createPartControl(Composite parent) {
		GridLayout layout = new GridLayout(2, false);
		parent.setLayout(layout);
		Label searchLabel = new Label(parent, SWT.NONE);
		searchLabel.setText("Search: ");
		final Text searchText = new Text(parent, SWT.BORDER | SWT.SEARCH);
		searchText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
				| GridData.HORIZONTAL_ALIGN_FILL));
		searchText.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent ke) {
				filter.setSearchText(searchText.getText());
				labelProvider.setSearchText(searchText.getText());
				viewer.refresh();
			}
		});
		createViewer(parent);
	}

	private void createViewer(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);

		createColumns(parent, viewer);
		viewer.setContentProvider(new PersonContentProvider());
		labelProvider = new PersonLabelProvider();
		viewer.setLabelProvider(labelProvider);
		// Get the content for the viewer, setInput will call getElements in the
		// contentProvider
		viewer.setInput(ModelProvider.getInstance().getPersons());
		// Make the selection available
		getSite().setSelectionProvider(viewer);
		// Set the sorter for the table
		tableSorter = new TableSorter();
		viewer.setSorter(tableSorter);
		filter = new PersonFilter();
		viewer.addFilter(filter);

		// Layout the viewer
		GridData gridData = new GridData();
		gridData.verticalAlignment = GridData.FILL;
		gridData.horizontalSpan = 2;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = GridData.FILL;
		viewer.getControl().setLayoutData(gridData);
	}

	public TableViewer getViewer() {
		return viewer;
	}

	// This will create the columns for the table
	private void createColumns(final Composite parent, final TableViewer viewer) {
		final Menu headerMenu = new Menu(parent);
		String[] titles = { "First name", "Last name", "Gender", "Married" };
		int[] bounds = { 100, 100, 100, 100 };

		for (int i = 0; i < titles.length; i++) {
			final int index = i;
			final TableViewerColumn viewerColumn = new TableViewerColumn(
					viewer, SWT.NONE);
			final TableColumn column = viewerColumn.getColumn();
			column.setText(titles[i]);
			column.setWidth(bounds[i]);
			column.setResizable(true);
			createMenuItem(headerMenu, column); // Create the menu item for this
												// column
			column.setMoveable(true);

			// Setting the right sorter
			column.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					tableSorter.setColumn(index);
					int dir = viewer.getTable().getSortDirection();
					if (viewer.getTable().getSortColumn() == column) {
						dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
					} else {

						dir = SWT.DOWN;
					}
					viewer.getTable().setSortDirection(dir);
					viewer.getTable().setSortColumn(column);
					viewer.refresh();
				}
			});
			viewerColumn.setEditingSupport(new PersonEditingSupport(viewer, i));
		}
		final Table table = viewer.getTable();
		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		table.addListener(SWT.MenuDetect, new Listener() {
			public void handleEvent(Event event) {
				table.setMenu(headerMenu);
			}
		});

	}

	private void createMenuItem(Menu parent, final TableColumn column) {
		final MenuItem itemName = new MenuItem(parent, SWT.CHECK);
		itemName.setText(column.getText());
		itemName.setSelection(column.getResizable());
		itemName.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				if (itemName.getSelection()) {
					column.setWidth(150);
					column.setResizable(true);
				} else {
					column.setWidth(0);
					column.setResizable(false);
				}
			}
		});

	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}
		

If you run your application you are able to hide and show columns using the right mouse click on your table.

11. Commands

The following will demonstrate the usage of commands. Feel free to skip with chapter.

11.1. Print the model content

This chapter add the functionality to print the content of the domain model to the console. This way it is possible to verify that the changes on the JFace table are updating the model.

Create the command "de.vogella.jface.tableviewer.commands.Print" with the default handler "de.vogella.jface.tableviewer.commands.Print" (see Defining commands for details).

Implement the following coding:

				
package de.vogella.jface.tableviewer.commands;

import java.util.List;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;

import de.vogella.jface.tableviewer.model.ModelProvider;
import de.vogella.jface.tableviewer.model.Person;

public class Print extends AbstractHandler {
	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		List<Person> personList = ModelProvider.getInstance().getPersons();
		for (Person p : personList) {
			System.out.println(p);
		}
		return null;
	}
}

			

Add your command to the menu.(see Defining commands for details).

After finishing this you will be able to print the current state of your domain model to the console via the menu. Validate that the changes you are doing in the UI are reflected the model.

11.2. Add and delete a person to and from the model

This chapter shows how to add and delete Persons to and from the table.

You have to make the selection of the viewer available and will also provide an access method to the viewer of the view.

				
	public void createPartControl(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.FULL_SELECTION);
		createColumns(viewer);
		viewer.setContentProvider(new PersonContentProvider());
		viewer.setLabelProvider(new PersonLabelProvider());
		// Get the content for the viewer, setInput will call getElements in the
		// contentProvider
		viewer.setInput(ModelProvider.getInstance().getPersons());
		// Make the selection available
		getSite().setSelectionProvider(viewer);

	}

	public TableViewer getViewer() {
		return viewer;
	}

			

Create the command "de.vogella.jface.tableviewer.commands.AddPerson" with the default handler "de.vogella.jface.tableviewer.commands.AddPerson". Add the command to your menu. Again see Defining commands for details.

Create a dialog to maintain the data for the additional person. Create package "de.vogella.jface.tableviewer.dialogs" and the following class "AddPersonDialog".

				
package de.vogella.jface.tableviewer.dialogs;

import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import de.vogella.jface.tableviewer.model.Person;

public class AddPersonDialog extends TitleAreaDialog {

	private Text text1;
	private Text text2;
	private Person person;
	private Button button1;
	private Combo combo1;

	public Person getPerson() {
		return person;
	}

	public AddPersonDialog(Shell parentShell) {
		super(parentShell);
	}

	@Override
	protected Control createContents(Composite parent) {
		Control contents = super.createContents(parent);
		setTitle("Add a new Person");
		setMessage("Please enter the data of the new person",
				IMessageProvider.INFORMATION);
		return contents;
	}

	@Override
	protected Control createDialogArea(Composite parent) {
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		parent.setLayout(layout);
		Label label1 = new Label(parent, SWT.NONE);
		label1.setText("First Name");
		text1 = new Text(parent, SWT.BORDER);
		Label label2 = new Label(parent, SWT.NONE);
		label2.setText("Last Name");
		text2 = new Text(parent, SWT.BORDER);
		Label label3 = new Label(parent, SWT.NONE);
		label3.setText("Gender");
		GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
		gd.horizontalSpan = 2;
		combo1 = new Combo(parent, SWT.READ_ONLY);
		combo1.add("male");
		combo1.add("female");
		button1 = new Button(parent, SWT.CHECK);
		button1.setText("Is married?");
		button1.setLayoutData(gd);
		return parent;

	}

	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		((GridLayout) parent.getLayout()).numColumns++;

		Button button = new Button(parent, SWT.PUSH);
		button.setText("OK");
		button.setFont(JFaceResources.getDialogFont());
		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (text1.getText().length() != 0
						&& text2.getText().length() != 0
						&& combo1.getItem(combo1.getSelectionIndex()).length() != 0) {
					person = new Person(text1.getText(), text2.getText(),
							combo1.getItem(combo1.getSelectionIndex()), button1
									.getSelection());
					close();

				} else {
					setErrorMessage("Please enter all data");
				}
			}
		});
	}
}

			

Implement the following code for the class "de.vogella.jface.tableviewer.commands.AddPerson":

				
package de.vogella.jface.tableviewer.commands;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;

import de.vogella.jface.tableviewer.View;
import de.vogella.jface.tableviewer.dialogs.AddPersonDialog;
import de.vogella.jface.tableviewer.model.ModelProvider;

public class AddPerson extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
		ModelProvider persons = ModelProvider.getInstance();
		AddPersonDialog dialog = new AddPersonDialog(window.getShell());
		dialog.open();
		if (dialog.getPerson() != null) {
			persons.getPersons().add(dialog.getPerson());
			// Updating the display in the view
			IWorkbenchPage page = window.getActivePage();
			View view = (View) page.findView(View.ID);
			view.getViewer().refresh();
		}
		return null;
	}
}
			

When you finished this successful you are able to add new persons in your application.

We will implement that a person can be deleted from the list after someone selected a person in the table, e.g. via a double click.

Create the command "de.vogella.jface.tableviewer.commands.DeletePerson" with the default handler "de.vogella.jface.tableviewer.commands.DeletePerson". Add the command to your menu.

Implement class "de.vogella.jface.tableviewer.commands.DeletePerson".

				
package de.vogella.jface.tableviewer.commands;

import java.util.Iterator;
import java.util.List;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;

import de.vogella.jface.tableviewer.View;
import de.vogella.jface.tableviewer.model.ModelProvider;
import de.vogella.jface.tableviewer.model.Person;

public class DeletePerson extends AbstractHandler {
	@SuppressWarnings("unchecked")
	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
		IWorkbenchPage page = window.getActivePage();
		View view = (View) page.findView(View.ID);
		ISelection selection = view.getSite().getSelectionProvider()
				.getSelection();

		if (selection != null && selection instanceof IStructuredSelection) {
			List<Person> persons = ModelProvider.getInstance().getPersons();
			IStructuredSelection sel = (IStructuredSelection) selection;

			for (Iterator<Person> iterator = sel.iterator(); iterator.hasNext();) {
				Person person = iterator.next();
				persons.remove(person);
			}
			view.getViewer().refresh();
		}
		return null;
	}
}

			

Please try to delete entries of the table by selection entries and executing "Delete Action".

11.3. Copy data to the system clipboard

This chapter shows how to copy the table data to the system clipboard via a command.

Create the command "de.vogella.jface.tableviewer.commands.CopyPersonClipboard" with the default handler "de.vogella.jface.tableviewer.commands.CopyPersonClipboard". Add the command to the menu.

				
package de.vogella.jface.tableviewer.commands;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

import de.vogella.jface.tableviewer.View;
import de.vogella.jface.tableviewer.model.Person;

public class CopyPersonClipboard extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {

		IWorkbenchWindow window = PlatformUI.getWorkbench()
				.getActiveWorkbenchWindow();
		IWorkbenchPage page = window.getActivePage();
		IViewPart view = page.findView(View.ID);
		Clipboard cb = new Clipboard(Display.getDefault());
		ISelection selection = view.getSite().getSelectionProvider()
				.getSelection();
		List<Person> personList = new ArrayList<Person>();
		if (selection != null && selection instanceof IStructuredSelection) {
			IStructuredSelection sel = (IStructuredSelection) selection;
			for (Iterator<Person> iterator = sel.iterator(); iterator.hasNext();) {
				Person person = iterator.next();
				personList.add(person);
			}
		}
		StringBuilder sb = new StringBuilder();
		for (Person person : personList) {
			sb.append(personToString(person));
		}
		TextTransfer textTransfer = TextTransfer.getInstance();
		cb.setContents(new Object[] { sb.toString() },
				new Transfer[] { textTransfer });

		return null;
	}

	private String personToString(Person person) {
		return person.getFirstName() + "\t" + person.getLastName() + "\t"
				+ person.getGender() + "\t" + person.isMarried()
				+ System.getProperty("line.separator");
	}

}

			

Run your application, select a few persons, run your command and paste the result in a text editor, e.g. notepad.

12. Thank you

Thank you for practicing with this tutorial.

Please note that I maintain this website in my private time. If you like the information I'm providing please help me by donating.

13. Questions and Discussion

For questions and discussion around this article please use the www.vogella.de Google Group. Also if you note an error in this article please post the error and if possible the correction to the Group.

I believe the following is a very good guideline for asking questions in general and also for the Google group How To Ask Questions The Smart Way.

14. Download

http://www.vogella.de/articles/EclipseJFaceTable/download/checkedpics.zip The checkbox pictures for the JFace Labelprovider

15. Links and Literature

15.1. Source Code

http://www.vogella.de/code/codeeclipse.html Source Code of Examples

15.2. JFace Resources

http://www.eclipse.org/articles/Article-Table-viewer/table_viewer.html Building and delivering a table editor with SWT/JFace

http://wiki.eclipse.org/index.php/JFaceSnippets JFace snippets, e.g. small code examples