2010-07-29 11 views
5

Uso el marco org.eclipse.core.databinding para vincular algunos campos Text en una aplicación SWT. Añado una estrategia de actualización para validar los datos y para establecer el valor en el modelo sólo cuando el usuario haga clic en el botón de guardar:¿Databind y valida un TableViewer?

UpdateValueStrategy toModel = new UpdateValueStrategy(UpdateValueStrategy.POLICY_CONVERT); 
    if (validator != null) { 
     toModel.setAfterGetValidator(validator); 
    } 

    UpdateValueStrategy fromModel = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE); 

    binding = bindingContext.bindValue(SWTObservables.observeText(this, SWT.Modify), 
        BeansObservables.observeValue(pVO, propertyName), toModel, fromModel); 

Esta pieza de código funciona muy bien.

Pero, ¿cómo puedo hacer lo mismo en un TableViewer?

quiero que funcione de manera que cuando agrego algo en la IHM, el modelo permanecer sin cambios hasta que llamo getBindingContext().updateModels();

Respuesta

6

No es necesario utilizar el marco de enlace de datos JFace en TableViewer. La manipulación de los datos estructurados es más simple que los controles SWT, como TableViewer, ListViewer y TreeViewer. Puede utilizar los visor de la misma manera:

  • crear espectador
  • proveedor de contenido de conjunto
  • conjunto proveedor de etiqueta (sugerido)
  • filtro de serie (opcional)
  • conjunto clasificador (opcional)

Después de crear el visor, solo invoque viewer.setInput(data) para poner todo a su alcance.

Hay una lista de modelo:

TableViewer tableViewer = new TableViewer(parent); 

Table table = tableViewer.getTable(); 
table.setHeaderVisible(true);  
table.setLinesVisible(true);` 

for (int i = 0; i < COLUMN_NAMES.length; i++) { 
    TableColumn tableColumn = new TableColumn(table, SWT.LEFT); 
    tableColumn.setText(COLUMN_NAMES[i]); 
    tableColumn.setWidth(COLUMN_WIDTHS[i]); 
} 

tableViewer.setContentProvider(new ModelContentProvider()); 
tableViewer.setLabelProvider(new ModelLabelProvider()); 
tableViewer.setInput(models); 

La magia sucede en el proveedor de contenidos:

class ModelContentProvider implements IStructuredContentProvider { 

    @SuppressWarnings("unchecked") 
    @Override 
    public Object[] getElements(Object inputElement) { 
     // The inputElement comes from view.setInput() 
     if (inputElement instanceof List) { 
      List models = (List) inputElement; 
      return models.toArray(); 
     } 
     return new Object[0]; 
    } 

/* ... other methods */ 

} 

Cada modelo se convertirá en un TableItem y el modelo en el TableItem(item.getData()).

Sin embargo, una tabla compuesta por muchas columnas, se necesita el LabelProvider para ayudarle a la cartografía de la propiedad de modelo a la TableItem:

class ModelLabelProvider extends LabelProvider implements 
     ITableLabelProvider { 

    @Override 
    public Image getColumnImage(Object element, int columnIndex) { 
     // no image to show 
     return null; 
    } 

    @Override 
    public String getColumnText(Object element, int columnIndex) { 
     // each element comes from the ContentProvider.getElements(Object) 
     if (!(element instanceof Model)) { 
      return ""; 
     } 
     Model model = (Model) element; 
     switch (columnIndex) { 
     case 0: 
      return model.getFoo(); 
     case 1: 
      return model.getBar(); 
     default: 
      break; 
     } 
     return ""; 
    } 
} 

La propagación de modelos para el espectador es fácil. Si va a propagar el visor al modelo enlazado, usar el CellEditor también es simple. Para utilizar CellEditor, es necesario establecer las propiedades de la columna, editores celulares y modificador de la célula a TableViewer:

tableViewer.setColumnProperties(COLUMNS_PROPERTIES); 
tableViewer.setCellEditors(new CellEditor[] { 
     new TextCellEditor(table), new TextCellEditor(table) }); 
tableViewer.setCellModifier(new ModelCellModifier(tableViewer)); 

El CellModifier le gusta esto:

class ModelCellModifier implements ICellModifier { 
    TableViewer viewer; 

    public ModelCellModifier(TableViewer viewer) { 
     this.viewer = viewer; 
    } 

    @Override 
    public boolean canModify(Object element, String property) { 
     // property is defined by viewer.setColumnProperties() 
     // allow the FOO column can be modified. 
     return "foo_prop".equals(property); 
    } 

    @Override 
    public Object getValue(Object element, String property) { 
     if ("foo_prop".equals(property)) { 
      return ((Model) element).getFoo(); 
     } 
     if ("bar_prop".equals(property)) { 
      return ((Model) element).getBar(); 
     } 
     return ""; 
    } 

    @Override 
    public void modify(Object element, String property, Object value) { 
     if ("foo_prop".equals(property)) { 
      TableItem item = (TableItem) element; 
      ((Model) item.getData()).setFoo("" + value); 

      // refresh the viewer to show the changes to our user. 
      viewer.refresh(); 
     } 
    } 
} 

Todo es sencillo pero hay muchos pasos para hacer todo juntos.

+1

Hay un código completo: http://pastie.org/1089932 – qrtt1

+0

Muchas gracias por este código. ¡Realmente útil! – flumins

+8

... pero ¿por qué querría renunciar a la databinding y volver a escribir un montón de código repetitivo? – vwegert

2

Uso ViewerSupport:

TableViewer tableViewer = ... 
IObservableList tableElements = ... 
IValueProperty[] columnProperties = ... 
ViewerSupport.bind(tableViewer, tableElements, columnProperties); 
+0

Esto parece una buena solución. ¿Pero hay alguna forma de usar validadores y convertidores con un visor de tabla con esto? – Lii

0

Estoy de acuerdo con qualidafial.

Snippet017TableViewerWithDerivedColumns del jface.databinding snippets es un ejemplo completo de esto.

+0

El fragmento no parece estar disponible más. Aquí hay una alternativa: http://wiki.eclipse.org/JFace_Data_Binding/Snippets#Viewers – paul

Cuestiones relacionadas