语境
我已经实现了一个 NatTable (v1.1.0.201405012245) - 请考虑这个简化的例子:
package testproject;
import java.util.ArrayList;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration;
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.config.EditableRule;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.data.IColumnAccessor;
import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditBindings;
import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditConfiguration;
import org.eclipse.nebula.widgets.nattable.edit.editor.TextCellEditor;
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.layer.LabelStack;
import org.eclipse.nebula.widgets.nattable.layer.cell.IConfigLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.selection.config.DefaultSelectionStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
public class ViewPart1 extends ViewPart
{
@Override
public void createPartControl(final Composite parent)
{
final ArrayList<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
final IColumnAccessor<String> columnAccessor = new IColumnAccessor<String>()
{
@Override
public void setDataValue(final String rowObject, final int columnIndex, final Object newValue)
{
if (!(newValue instanceof String) || ((String) newValue).contains("x"))
{
MessageDialog.openError(getSite().getShell(), "Error", "Invalid Input");
return;
}
list.set(list.indexOf(rowObject), (String) newValue);
}
@Override
public Object getDataValue(final String rowObject, final int columnIndex)
{
return rowObject;
}
@Override
public int getColumnCount()
{
return 1;
}
};
final IDataProvider dataProvider = new ListDataProvider<>(list, columnAccessor);
final DataLayer dataLayer = new DataLayer(dataProvider);
final SelectionLayer selectionLayer = new SelectionLayer(dataLayer);
final ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);
final NatTable table = new NatTable(parent, viewportLayer, false);
GridDataFactory.fillDefaults().grab(true, true).applyTo(table);
viewportLayer.addConfiguration(new DefaultEditConfiguration());
viewportLayer.addConfiguration(new DefaultEditBindings());
viewportLayer.setRegionName(GridRegion.BODY);
viewportLayer.setConfigLabelAccumulator(new IConfigLabelAccumulator()
{
@Override
public void accumulateConfigLabels(final LabelStack configLabels, final int columnPosition, final int rowPosition)
{
configLabels.addLabel("myLabel");
}
});
table.setConfigRegistry(new ConfigRegistry());
table.addConfiguration(new DefaultNatTableStyleConfiguration());
table.addConfiguration(new DefaultSelectionStyleConfiguration());
table.addConfiguration(new AbstractRegistryConfiguration()
{
@Override
public void configureRegistry(final IConfigRegistry registry)
{
registry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new TextCellEditor(true), DisplayMode.NORMAL, "myLabel");
registry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, EditableRule.ALWAYS_EDITABLE, DisplayMode.NORMAL, "myLabel");
}
});
table.configure();
}
@Override
public void setFocus()
{
}
}
当然,这不是真正的代码,但我的问题也可以用这段代码来演示。
重要的是,在我的实际项目中,当用户修改一个值时,我需要更新一个模型(包括复杂的依赖树),如果失败(例如在数值计算中,更改会导致除以零) ,我需要显示一个错误(并恢复到以前的值)。
为了显示我的核心问题,在此处显示的代码中,我检查了一个简单的条件IColumnAccessor#setDataValue
(输入包含“x”)并相应地显示错误。
问题
我的实际问题是,如果您在 TextCellEditor 中输入一个 x,则会弹出两次错误对话框(按顺序 - 这意味着只要我为第一个单击“确定”,就会显示第二个)。
分析
我的分析表明,原因是 setDataValue 被调用了两次:
因为按下了 ENTER 键 - Stacktrace
TextCellEditor(AbstractCellEditor).commit(SelectionLayer$MoveDirectionEnum, boolean) line: 331
TextCellEditor(AbstractCellEditor).commit(SelectionLayer$MoveDirectionEnum) line: 326
TextCellEditor$1.keyPressed(KeyEvent) line: 246
因为 TextCellEditor 失去焦点 - Stacktrace
TextCellEditor(AbstractCellEditor).commit(SelectionLayer$MoveDirectionEnum, boolean, boolean) line: 341
TextCellEditor(AbstractCellEditor).commit(SelectionLayer$MoveDirectionEnum, boolean) line: 331
AbstractCellEditor$InlineFocusListener.focusLost(FocusEvent) line: 462
所以,我的主要问题是:我怎样才能防止(或至少检测)第二个事件?