# JFace Data Binding



## overflow (6. Okt 2011)

Hi liebe Leute,

ich habe ein Problem, bei dem ich einfach nicht weiter komme.
Ich verwende einen TableViewer, den ich mit daten aus einem Modell füttere, was auch passt. Hinzufügen bzw. entfernen kann man auch ganz praktisch, soweit so gut.
Allerdings muss, um Änderungen an den Datensätzen an sich im Table sichtbar zu machen, ein LabelObserver eingesetzt werden, welcher diese Änderungen erfasst und weitergibt.

Allerdings hab ichs bisher nicht hingebracht, auch nur irgendeine Änderung zu erfassen, drum wende ich mich an euch, in der Hoffnung, ihr könnt mir hier etwas klarheit verschaffen.

Habe allen Code, der in diese Richtung ging wieder entfernt, damit es wenigstens ein wenig übersichtlicher wird. Stand unten ist eben eine Tabelle, welche mit Initialdaten gefüllt wird und wo man hinzufügen/entfernen kann. Es solln aber eben noch Modelländerungen angezeigt werden.

Zusatzinfo: Vorlage war zu gutem Teil das Tutorial von Lars Vogel

--- Klasse Person: ---


```
public class Person extends AbstractModelObject{

	private int ID;

	public enum Anrede {
		Herr, Frau
	};

	private Anrede Anrede;
	private String Vorname, Nachname, Adresse, Ort, Telefon, Email, Handy;
	private int Plz;
	private Date Gebdat;

	public Person() {
		this.ID = -1;
	}

	public Person(int _ID, Anrede _Anrede, String _Vorname, String _Nachname,
			String _Adresse, String _Ort, String _Telefon, String _Email,
			String _Handy, int _Plz, Date _Gebdat) {

		this.ID = _ID;
		this.Anrede = _Anrede;
		this.Vorname = _Vorname;
		this.Nachname = _Nachname;
		this.Adresse = _Adresse;
		this.Ort = _Ort;
		this.Plz = _Plz;
		this.Handy = _Handy;
		this.Telefon = _Telefon;
		this.Email = _Email;
		this.Gebdat = _Gebdat;
	}

	/* Methoden */

	public int getAlter() {
		Calendar GebTag = Calendar.getInstance();
		GebTag.setTime(this.Gebdat);
		Calendar today = Calendar.getInstance();
		int age = today.get(Calendar.YEAR) - GebTag.get(Calendar.YEAR);
		if (today.get(Calendar.DAY_OF_YEAR) < GebTag.get(Calendar.DAY_OF_YEAR))
			age--;
		return age;
	}
	
	public String toString() {
		if (this.Anrede != null)
			return this.Anrede.toString() + " " + this.Vorname + " " + this.Nachname;
		else
			return this.Vorname + " " + this.Nachname;
	}

	/* Getter und Setter */

	public int getID() {
		return this.ID;
	}

	public void setID(int iD) {
		firePropertyChange("ID", this.ID, this.ID = iD);
	}

	public Anrede getAnrede() {
		return this.Anrede;
	}

	public void setAnrede(Anrede anrede) {
		firePropertyChange("anrede", this.Anrede, this.Anrede = anrede);
	}

	public String getVorname() {
		return this.Vorname;
	}

	public void setVorname(String vorname) {
		firePropertyChange("vorname", this.Vorname,	this.Vorname = vorname);
	}

	public String getNachname() {
		return this.Nachname;
	}

	public void setNachname(String nachname) {
		firePropertyChange("nachname", this.Nachname, this.Nachname = nachname);
	}
	
	[...]
	
}
```


```
public abstract class AbstractModelObject {
	
   private final PropertyChangeSupport m_propertyChangeSupport = new PropertyChangeSupport(this);

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      m_propertyChangeSupport.addPropertyChangeListener(listener);
   }
   public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
      m_propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
   }
   public void removePropertyChangeListener(PropertyChangeListener listener) {
      m_propertyChangeSupport.removePropertyChangeListener(listener);
   }
   public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
      m_propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
   }
   public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
      m_propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
   }
}
```

--- Mitglied erweitert Person ---

```
public enum ModelProvider {
	INSTANCE;

	private List<Mitglied> Mitglieder;

	private ModelProvider() {
		Mitglieder = new ArrayList<Mitglied>();
		
		/* Datenbankzugriff um die user auszulesen */
		[...]
	}
		
	public List<Mitglied> getMitglieder() {
		return Mitglieder;
	}
	
	public void printAll() {
		for ( Mitglied m : Mitglieder )	{
		  System.out.println(m.getAnrede() + " " + m.getVorname() + " " + m.getNachname());
		}
	}
}
```

--- View mit Tabelle ---

```
private MitgliederComparator comparator;
	private TableViewer viewer;
	private WritableList input;

	// Icons
	private static final Image HAT_PARTNER = Activator.getImageDescriptor(
			"icons/partner.png").createImage();

	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));
	
		//createViewer(parent);
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
		createColumns(parent, viewer);
		final Table table = viewer.getTable();
		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		// 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);
		
		// Sortierer fürn Table
		comparator = new MitgliederComparator();
		viewer.setComparator(comparator);

		// Bindes
		input = new WritableList(ModelProvider.INSTANCE.getMitglieder(),
				Mitglied.class);
		//viewer.setInput(input);
		ViewerSupport.bind(
				viewer,
				input,
				BeanProperties.values(new String[] { "anrede", "vorname",
						"nachname", "geburtsdatum" }));
		
		
		// Testfunktionen - Löschen
		Button delete = new Button(parent, SWT.PUSH);
		delete.setText("Delete");
		delete.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (!viewer.getSelection().isEmpty()) {
					IStructuredSelection selection = (IStructuredSelection) viewer
							.getSelection();
					Mitglied m = (Mitglied) selection.getFirstElement();
					input.remove(m);
				}
			}
		});
		// Hinzufügen
		Button add = new Button(parent, SWT.PUSH);
		add.setText("Add");
		add.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				Mitglied m = new Mitglied();
				m.setVorname("Test1");
				m.setNachname("Test2");
				input.add(m);
			}
		});
		//Werte tauschen
		Button change = new Button(parent, SWT.PUSH);
		change.setText("Switch First / Lastname");
		change.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (!viewer.getSelection().isEmpty()) {
					IStructuredSelection selection = (IStructuredSelection) viewer
							.getSelection();
					Mitglied m = (Mitglied) selection.getFirstElement();
					System.out.println(m.getVorname() + " - " + m.getNachname());
					String temp = m.getNachname();
					m.setNachname(m.getVorname());
					m.setVorname(temp);
				}
			}
		});
		//Modell ausgeben
		Button print = new Button(parent, SWT.PUSH);
		print.setText("Print");
		print.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				ModelProvider.INSTANCE.printAll();
			}
		});

	}

	public TableViewer getViewer() {
		return viewer;
	}

	// This will create the columns for the table
	private void createColumns(final Composite parent, final TableViewer viewer) {
        
		// Anrede
		TableViewerColumn col = createTableViewerColumn("Anrede", 50, 0);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				if (m.getAnrede() == Anrede.Herr)
					return "Herr";
				else
					return "Frau";
			}
		});

		// Vorname
		col = createTableViewerColumn("Vorname", 100, 1);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				return m.getVorname();
			}
		});

		// Nachname
		col = createTableViewerColumn("Nachname", 100, 2);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				return m.getNachname();
			}
		});

		// GebTag
		col = createTableViewerColumn("Gebutsdatum", 75, 3);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				Format format = new SimpleDateFormat("dd.MM.yyyy");
				return format.format(m.getGebdat()).toString();
			}
		});

		// Partner
		col = createTableViewerColumn("Partner", 50, 4);
		col.setLabelProvider(new CenterImageLabelProvider() {

			@Override
			public Image getImage(Object element) {
				if (((Mitglied) element).hatPartner()) {
					return HAT_PARTNER;
				} else {
					return null;
				}
			}
		});

		// Adresse
		col = createTableViewerColumn("Adresse", 150, 5);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				return m.getAdresse();
			}
		});

		// PLZ
		col = createTableViewerColumn("PLZ", 50, 6);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				return String.valueOf(m.getPlz());
			}
		});

		// Ort
		col = createTableViewerColumn("Ort", 75, 7);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				return m.getOrt();
			}
		});

		// Telefon
		col = createTableViewerColumn("Telefon", 100, 8);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				return m.getTelefon();
			}
		});

		// Handy
		col = createTableViewerColumn("Handynummer", 100, 9);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				return m.getHandy();
			}
		});

		// Mail
		col = createTableViewerColumn("EMail", 125, 10);
		col.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element) {
				Mitglied m = (Mitglied) element;
				return m.getEmail();
			}
		});
	}

	private TableViewerColumn createTableViewerColumn(String title, int bound,
			final int colNumber) {
		final TableViewerColumn viewerColumn = new TableViewerColumn(viewer,
				SWT.NONE);
		final TableColumn column = viewerColumn.getColumn();
		column.setText(title);
		column.setWidth(bound);
		column.setResizable(true);
		column.setMoveable(true);
		column.addSelectionListener(getSelectionAdapter(column, colNumber));
		return viewerColumn;

	}

	private SelectionAdapter getSelectionAdapter(final TableColumn column,
			final int index) {
		SelectionAdapter selectionAdapter = new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				comparator.setColumn(index);
				int dir = comparator.getDirection();
				viewer.getTable().setSortDirection(dir);
				viewer.getTable().setSortColumn(column);
				viewer.refresh();
			}
		};
		return selectionAdapter;
	}

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

	/* *
	 * Erweiterter ImageLabelProvider, der die Labels zentriert
	 */

	private abstract class CenterImageLabelProvider extends
			OwnerDrawLabelProvider {

		protected void measure(Event event, Object element) {
		}

		protected void paint(Event event, Object element) {

			Image img = getImage(element);

			if (img != null) {
				Rectangle bounds = ((TableItem) event.item)
						.getBounds(event.index);
				Rectangle imgBounds = img.getBounds();
				bounds.width /= 2;
				bounds.width -= imgBounds.width / 2;
				bounds.height /= 2;
				bounds.height -= imgBounds.height / 2;

				int x = bounds.width > 0 ? bounds.x + bounds.width : bounds.x;
				int y = bounds.height > 0 ? bounds.y + bounds.height : bounds.y;

				event.gc.drawImage(img, x, y);
			}
		}

		protected abstract Image getImage(Object element);

	}
}
```


Vielen Dank fürs Lesen und ich hoffe, jemand kann mir helfen 
lg
M


----------



## Wildcard (6. Okt 2011)

Dein LabelProvider muss ein Listener auf dem Modell sein um einen refresh anstoßen zu können.
Mein Tipp, lass dir dein Modell mit EMF erzeugen. Das Modell wird dadurch besser, du sparst dir das ganze PropertyChange Zeug, das Databinding wird einfacher und mächtiger und die LabelProvider und ContentProvider bekommst du gratis dazu (die sich auch automatisch aktualisieren).

Dann musst du dir auch um Undo/Redo und Transaktionen keine Gedanken mehr machen, EMF kann das alles.


----------



## overflow (7. Okt 2011)

Hi Wildcard,

danke für den Tipp, hab eh schon mehrfach über EMF gelesen, nur wollte ich nicht in zu viele neue Bereiche zugleich vordringen. Werde es mir aber direkt mal ansehen. 
Hast du eventuell mal eine schöne Seite mit einem Tutorial/Anleitung oder dergleichen gefunden, welche du empfehlen kannst? Wenn nicht find ich sicher auch was 

Danke und lg
M


----------



## Wildcard (8. Okt 2011)

Das hier sollte für den Einstieg genügen. 
Eclipse Modeling Framework (EMF) - Tutorial
Wenn du Fragen hast wie man EMF Modelle in Tabellen und Bäumen verwendet, oder wie das Databinding funktioniert (alles sehr einfach), melde dich einfach nochmal.


----------



## overflow (9. Okt 2011)

Hi Wildcard,

Danke mal für die Seite, die hatte ich eh schon gefunden. Habs auch schon mal nachgebaut, das prob is nur: der gute Lars erklärt recht wenig, er gibt nur Anleitungen, was zu amchen ist... für was ich da jetzt ein Edit und einen Editor undw as weiss ich noch alles für Code generier weiss ich trotzdem ned 

Ich nehme an, ein schönen Tutorial, wo dann zb auch das Databinding an ein JFace control erklärt wird, gibtz ned, oder? Ich hätte zumindest nichts gefunden.

So, wies auf der einen Seite war, schien es mir auf jeden fall etwas zu kompliziert, zumal ich eben auch ned die Feinheiten gesehn hab (also eben DB, Validierungen, conversion, etc.)

Danke auf jeden Fall für dein bemühen,

lg


----------



## Wildcard (10. Okt 2011)

> Danke mal für die Seite, die hatte ich eh schon gefunden. Habs auch schon mal nachgebaut, das prob is nur: der gute Lars erklärt recht wenig, er gibt nur Anleitungen, was zu amchen ist... für was ich da jetzt ein Edit und einen Editor undw as weiss ich noch alles für Code generier weiss ich trotzdem ned


Der EMF Editor kann dir 4 Dinge generieren:
Model: Das Datenmodell
Edit: UI Gluecode zB für Content- und LabelProvider
Editor: ein funktionsfähiger CRUD Editor für Eclipse
Test: JUnit Test Stubs für dein Modell


> Ich nehme an, ein schönen Tutorial, wo dann zb auch das Databinding an ein JFace control erklärt wird, gibtz ned, oder? Ich hätte zumindest nichts gefunden.


Gibt es auch, müsste ich aber erst suchen. Das Databinding ist sehr einfach. Funktioniert wie normales JFace Databinding, nur das du dir das PropertyChange Zeug sparen kannst. Stattdessen verwendest du EMFProperties als einstiegspunkt, oder EMFEditProperties, wenn automatisch Undo/Redo unterstützt werden soll.



> So, wies auf der einen Seite war, schien es mir auf jeden fall etwas zu kompliziert, zumal ich eben auch ned die Feinheiten gesehn hab (also eben DB, Validierungen, conversion, etc.)


Glaub mir, es ist nicht kompliziert, nur am Anfang viel neues. DB, Validierung, conversion, was genau möchtest du wissen?


----------



## overflow (10. Okt 2011)

Hey Wildcard,

vielen Dank nochmal für deine Anmerkung! Ich hab mir jetzt noch ein paar Seiten rausgesucht, wo ich mich einlesen werde. Detailfragen stell ich dann eventuell später, muss mich erst vernünftig einarbeiten.
Danke auf jeden Fall für deine Hilfe 

lg


----------



## Gast2 (10. Okt 2011)

Wildcard hat gesagt.:


> Gibt es auch, müsste ich aber erst suchen. Das Databinding ist sehr einfach. Funktioniert wie normales JFace Databinding, nur das du dir das PropertyChange Zeug sparen kannst. Stattdessen verwendest du EMFProperties als einstiegspunkt, oder EMFEditProperties, wenn automatisch Undo/Redo unterstützt werden soll.



Es gibt doch auch schon ein JFace Databinding, dass das alles ohne das PropertyChange zeugs hinbekommt. 

5. JFace Data Binding with POJOs


----------



## Wildcard (10. Okt 2011)

SirWayne hat gesagt.:


> Es gibt doch auch schon ein JFace Databinding, dass das alles ohne das PropertyChange zeugs hinbekommt.
> 
> 5.*JFace Data Binding with POJOs



Das geht aber nur in eine Richtung, UI -> Model.


----------



## Gast2 (10. Okt 2011)

Wildcard hat gesagt.:


> Das geht aber nur in eine Richtung, UI -> Model.



Ah gut zu wissen, hab mit die API noch nicht angeschaut.


----------



## Gast2 (26. Okt 2011)

Wildcard hat gesagt.:


> Das geht aber nur in eine Richtung, UI -> Model.



Nochmal zu dem Thema das geht doch auch in beide Richtungen  =).


```
public class Person{

String firstname;

//getter setter
```
Beispiel

```
bindingContext.bindValue(SWTObservables.observeText(textField,
                           SWT.Modify), PojoObservables.observeValue(myPerson,
                           "firstName"), null,null);
```


----------



## Wildcard (26. Okt 2011)

JFace Data Binding - Tutorial


> If you only need to update the model from the UI you can use the class "PojoObservables". This this case you Java model objects do not need to implement "PropertyChangeSupport" and can be a POJO. Changes from the model will in this case not be reflected in the UI.


----------



## Gast2 (27. Okt 2011)

Wildcard hat gesagt.:


> JFace Data Binding - Tutorial



Ahhh hab grad gesehen dass irgendwo ein 
	
	
	
	





```
bindingContext.updateTargets();
```
 ausgeführt wurde, deshalb hat das geklappt.


----------

