Nebula NatTable - Editing Tutorial. This tutorial explains the edit mechanisms in NatTable. After this tutorial you should be able to configure the edit behavior in NatTable. This tutorial is based on Nebula NatTable 2.0.
1. Exercise: Add simple editing support to a NatTable
1.1. Target
In this exercise editing support will be provided for a simple first name and last name table.
1.2. Creating a part with a NatTable
Add another part called Simple Edit to the application model.
In an SimpleEditor
class a simple table with first name and last name is created.
For the sake of practicing you could try to create such an NatTable
on your own, by using the PersonService
, a ReflectiveColumnPropertyAccessor
, a ListDataProvider
, a header data provider, e.g., a PersonHeaderDataProvider
, and the DefaultGridLayer
.
Now for simple text editing purposes only a EditConfigAttributes.CELL_EDITABLE_RULE
config attribute has to be registered to the IConfigRegistry
.
natTable.addConfiguration(new AbstractRegistryConfiguration() {
@Override
public void configureRegistry(IConfigRegistry configRegistry) {
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE,
IEditableRule.ALWAYS_EDITABLE);
}
});
The complete implementation of the SimpleEditor
would look like this:
package com.vogella.nattable.parts.edit;
import java.util.List;
import javax.annotation.PostConstruct;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration;
import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.IEditableRule;
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
import org.eclipse.nebula.widgets.nattable.data.ReflectiveColumnPropertyAccessor;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultGridLayer;
import org.eclipse.swt.widgets.Composite;
import com.vogella.model.person.Person;
import com.vogella.model.person.PersonService;
import com.vogella.nattable.data.PersonHeaderDataProvider;
public class SimpleEditor {
@PostConstruct
public void postConstruct(Composite parent, PersonService personService) {
List<Person> persons = personService.getPersons(10);
ReflectiveColumnPropertyAccessor<Person> columnPropertyAccessor = new ReflectiveColumnPropertyAccessor<>(
"firstName", "lastName");
ListDataProvider<Person> dataProvider = new ListDataProvider<>(persons, columnPropertyAccessor);
PersonHeaderDataProvider headerDataProvider = new PersonHeaderDataProvider();
DefaultGridLayer gridLayer = new DefaultGridLayer(dataProvider, headerDataProvider);
NatTable natTable = new NatTable(parent, gridLayer, false);
natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
natTable.addConfiguration(new AbstractRegistryConfiguration() {
@Override
public void configureRegistry(IConfigRegistry configRegistry) {
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE,
IEditableRule.ALWAYS_EDITABLE);
}
});
natTable.configure();
}
}
2. Exercise: Add more advanced editing support to a NatTable
2.1. Target
In this exercise editing support will be provided for a table, which contains different data than only strings. So different cell editors have to be applied for different columns.
2.2. Creating a part with a NatTable
Add another part called Advanced Edit to the application model.
In an AdvancedEditor
class a default Person
table with first name, last name, gender, married, and birthday is created.
You can reuse the code from the SimpleEditor
of a former exercise.
For the SimpleEditor
an anonymous inner class of an AbstractRegistryConfiguration
was used to apply basic editing capabilities.
Now that the configuration becomes more complex it is better to encapsulate it in another class:
package com.vogella.nattable.parts.edit;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Locale;
import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration;
import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.IEditableRule;
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultBooleanDisplayConverter;
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDateDisplayConverter;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
import org.eclipse.nebula.widgets.nattable.edit.editor.CheckBoxCellEditor;
import org.eclipse.nebula.widgets.nattable.edit.editor.ComboBoxCellEditor;
import org.eclipse.nebula.widgets.nattable.edit.editor.DateCellEditor;
import org.eclipse.nebula.widgets.nattable.edit.editor.TextCellEditor;
import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.painter.cell.CheckBoxPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.ComboBoxPainter;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import com.vogella.model.person.Person.Gender;
public class EditConfiguration extends AbstractRegistryConfiguration {
@Override
public void configureRegistry(IConfigRegistry configRegistry) {
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE);
registerEditors(configRegistry);
}
private void registerEditors(IConfigRegistry configRegistry) {
registerLastNameEditor(configRegistry, 1);
registerGenderEditor(configRegistry, 2);
registerMarriedEditor(configRegistry, 3);
registerBirthdayEditor(configRegistry, 4);
}
private void registerLastNameEditor(IConfigRegistry configRegistry, int columnIndex) {
// register a TextCellEditor for column two that commits on key up/down
// moves the selection after commit by enter
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new TextCellEditor(true, true),
DisplayMode.NORMAL, ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
// configure to open the adjacent editor after commit
configRegistry.registerConfigAttribute(EditConfigAttributes.OPEN_ADJACENT_EDITOR, Boolean.TRUE,
DisplayMode.EDIT, ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
}
private void registerGenderEditor(IConfigRegistry configRegistry, int columnIndex) {
ComboBoxCellEditor comboBoxCellEditor = new ComboBoxCellEditor(Arrays.asList(Gender.FEMALE, Gender.MALE));
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, comboBoxCellEditor, DisplayMode.EDIT,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new ComboBoxPainter(),
DisplayMode.NORMAL, ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
}
private void registerMarriedEditor(IConfigRegistry configRegistry, int columnIndex) {
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new CheckBoxCellEditor(),
DisplayMode.EDIT, ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
// The CheckBoxCellEditor can also be visualized like a check button
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new CheckBoxPainter(),
DisplayMode.NORMAL, ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
// using a CheckBoxCellEditor also needs a Boolean conversion to work
// correctly
configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER,
new DefaultBooleanDisplayConverter(), DisplayMode.NORMAL,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
}
private void registerBirthdayEditor(IConfigRegistry configRegistry, int columnIndex) {
DateCellEditor dateCellEditor = new DateCellEditor();
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, dateCellEditor, DisplayMode.EDIT,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
String pattern = ((SimpleDateFormat) formatter).toPattern();
// using a DateCellEditor also needs a Date conversion to work correctly
configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER,
new DefaultDateDisplayConverter(pattern), DisplayMode.NORMAL,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex);
}
}
In the EditConfiguration
class different cell editors are applied and configured for the different columns.
In the AdvancedEditor
implementation this EditConfiguration
has to be added to the NatTable configuration.
natTable.addConfiguration(new EditConfiguration());
And since the columns in the EditConfiguration
class are references by labels like this ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + columnIndex
a ColumnLabelAccumulator has to be applied to the body data layer.
DefaultGridLayer gridLayer = new DefaultGridLayer(dataProvider, headerDataProvider);
ColumnLabelAccumulator columnLabelAccumulator = new ColumnLabelAccumulator(dataProvider);
((DataLayer) gridLayer.getBodyDataLayer()).setConfigLabelAccumulator(columnLabelAccumulator);
So the final AdvancedEditor
class should look similar to this:
package com.vogella.nattable.parts.edit;
import java.util.List;
import javax.annotation.PostConstruct;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultGridLayer;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnLabelAccumulator;
import org.eclipse.swt.widgets.Composite;
import com.vogella.model.person.Person;
import com.vogella.model.person.PersonService;
import com.vogella.nattable.data.PersonDataProvider;
import com.vogella.nattable.data.PersonHeaderDataProvider;
public class AdvancedEditor {
@PostConstruct
public void postConstruct(Composite parent, PersonService personService) {
List<Person> persons = personService.getPersons(10);
PersonDataProvider dataProvider = new PersonDataProvider(persons);
PersonHeaderDataProvider headerDataProvider = new PersonHeaderDataProvider();
DefaultGridLayer gridLayer = new DefaultGridLayer(dataProvider, headerDataProvider);
// Apply a ColumnLabelAccumulator to address the columns in the
// EditConfiguration class
ColumnLabelAccumulator columnLabelAccumulator = new ColumnLabelAccumulator(dataProvider);
((DataLayer) gridLayer.getBodyDataLayer()).setConfigLabelAccumulator(columnLabelAccumulator);
NatTable natTable = new NatTable(parent, gridLayer, false);
natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
// add the EditConfiguration to enable editing support
natTable.addConfiguration(new EditConfiguration());
natTable.configure();
}
}
Appendix A: Copyright, License and Source code
Copyright © 2012-2018 vogella GmbH. Free use of the software examples is granted under the terms of the Eclipse Public License 2.0. This tutorial is published under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Germany license.