In diesem Artikel (Tutorial) soll ein einfaches Databinding Beispiel gezeigt und erläutert werden. Die Aufgabe besteht darin den Wert einer Eclipse RCP GUI (SWT) in einem vorgefertigten Datenmodel automatisiert abzulegen und bei Änderungen am Model von dort automatisiert in der GUI wieder darzustellen.
Der Code kann ausprobiert werden, indem eine leere Eclipse Applikation basierend auf dem Template "RCP Application with a View" erstellt wird. Es wird die View Klasse modifiziert und es werden zwei weitere Klassen angelegt.
Rot markierte Codeteile werden benötigt, um das Textfeld und das entsprechende Attribut im Model miteinander zu verbinden.
Grün markierte Codeteile werden für das Databinding nicht zwangsläufig benötigt. Die Codezeilen werden benötigt um auf Änderungen im Model zu reagieren. In der Praxis ist dies oft eine Anforderung und daher für unser Minimalbeispiel notwendig.
Das Model besteht aus einer einzigen Klasse
Person
mit dem Attribut vorname
. Dies vereinfacht das Beispiel und macht die Funktionsweise deutlicher.Folgende Plugins sollten im plugin.xml unter Dependencies eingetragen werden:
- org.eclipse.core.databinding
- org.eclipse.core.databinding.beans
- org.eclipse.jface.databinding
- org.eclipse.core.databinding.property
Abbildung 1 |
Abbildung 2 |
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Person {
private String vorname;
private PropertyChangeSupport propertyChangeSupport;
public Person() {
propertyChangeSupport = new PropertyChangeSupport(this);
}
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
public String getVorname() {
return vorname;
}
public void setVorname(String vorname) {
propertyChangeSupport.firePropertyChange("vorname",
this.vorname, this.vorname = vorname );
}
@Override
public String toString() {
return vorname;
}
}
Die Klasse Person
besitzt zwei Klassenattribute: vorname
und propertyChangeSupport
. Das Attribut vorname
enthält den später in der GUI angezeigten Vornamen. Das Attribut propertyChangeSupport
vom Typ PropertyChangeSupport und sorgt dafür, dass Änderungen an den Attributen an das Framework propagiert werden.
Mit Hilfe der Klasse
PersonPropertyListener
wird in der Methode propertyChange
auf die Änderungen im Setter setVorname
reagiert, indem der Alte und der Neue Wert ausgegeben werden. Beim Aufruf des Setters wird ein Event erstellt auf das alle registrierten PropertyChangeListener
zugreifen können. In unserem Beispiel implementiert die Klasse PersonPropertyListener
das Interface PropertyChangeListener
.
Der PropertyChangeListener sieht wie folg aus:
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class PersonPropertyListener implements
PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println("Vorname wurde von "
+ evt.getOldValue() + " in " + evt.getNewValue()
+ " geändert.");
}
}
Wenn ein PropertyChangeEvent auftirtt, gibt der Listener den alten und den neuen Wert über die Standardausgabe aus. Dies geschieht bei jedem Aufruf der Setter Methode
setVorname
. Als nächstes betrachten wir die View Klasse. Der Inhalt der
createPartControl
Methode wird ersetzt und die Klasse wird um zwei weitere Methoden erweitert.
public static final String ID = "databinding.view";
private Person person;
private Text vorname;
@Override
public void createPartControl(Composite parent) {
person = new Person();
PersonPropertyListener personListener = new PersonPropertyListener();
person.addPropertyChangeListener("vorname", personListener);
person.setVorname("Testname");
GridLayout layout = new GridLayout(2, false);
layout.marginRight = 5;
parent.setLayout(layout);
vorname = createLabelFieldPair(parent, "Vorname:");
Button button1 = createButton(parent, "Model ausgeben!");
button1.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
System.out.println("Vorname: " + person.getVorname());
}
});
Button button2 = new Button(parent, SWT.PUSH);
button2.setText("Model zurücksetzen auf Startwert");
button2.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
person.setVorname("Testname");
}
});
GridData gData = new GridData();
gData.horizontalSpan = 2;
button1.setLayoutData(gData);
gData = new GridData();
gData.horizontalSpan = 2;
button2.setLayoutData(gData);
bindData();
}
private void bindData() {
DataBindingContext bindingContext = new DataBindingContext();
IObservableValue widgetValue = WidgetProperties
.text(SWT.FocusOut).observe(vorname);
IObservableValue modelValue = BeanProperties
.value(Person.class, "vorname")
.observe(person);
bindingContext.bindValue(widgetValue, modelValue);
}
private Text createLabelFieldPair(Composite parent, String labelValue) {
Label label = new Label(parent, SWT.NONE);
label.setText(labelValue);
Text text = new Text(parent, SWT.BORDER);
GridData gridData = new GridData();
gridData.horizontalAlignment = SWT.FILL;
gridData.grabExcessHorizontalSpace = true;
text.setLayoutData(gridData);
return text;
}
private Button createButton(Composite parent, String label){
Button button = new Button(parent, SWT.PUSH);
button.setText(label);
GridData gData = new GridData();
gData.horizontalSpan = 2;
button.setLayoutData(gData);
return button;
}
@Override
public void setFocus() {
}
Die View besteht aus einem Textfeld und zwei Buttons (siehe Abbildung 3). In das Textfeld wird der Vorname eingetragen, der durch das Databinding im Attribut
vorname
einer Person
Instanz gespeichert wird. Mit dem ersten Button ("Model ausgeben!") wird das Attribut vorname
der Person
Instanz ausgegeben. Mit dem zweiten Button ("Model zurücksetzen auf Startwert") wird das Attribut vorname
in der Person
Klasse auf den default Wert "Testname" zurückgesetzt.Betrachten wir die Codezeilen der
createPartControl
Methode etwas genauer. Es wird zuerst eine neue
Person
und eine neue PersonPropertyListener
Instanz erzeugt. Anschließend wird der PersonPropertyListener
für das Attribut vorname
registriert. Danach wird das Attribut vorname
initialisiert. Die bewirkt das erstmalige feuern des PropertyChangeEvent. Auf diesen reagiert der PersonPropertyListener mit der Methode propertyChange, wodurch die Ausgabe des neuen und alten Wertes auf der Standardkonsole folgt.In den darauf folgenden Zeilen wird ein GridLayout mit einem Label mit Textfeld und zwei Buttons erstellt. Für das Erzeugen des Label und Text Paars ist die Methode createLabelFieldPair zuständig.
Zu aller letzt wird die bindData Methode aufgerufen. Diese ist für das Binding des Widgets mit der Bean zuständig.
Zu beachten sei, dass es sich bei der Klasse
Person
um eine Java Bean handelt.
(Dieser Artikel basiert auf dem Artikel JFace Data Binding von Lars Vogel)
Keine Kommentare:
Kommentar veröffentlichen