JFace Data Binding/Getting started

From Eclipsepedia

Jump to: navigation, search

This page shows you how to create a simple example application using data binding that you can play with.

Setup

  1. Download and install the Eclipse 3.3 SDK.
  2. Start the Eclipse SDK and select a new workspace directory. Close the Welcome view - the Package Explorer should now be showing but empty.
  3. Create a new plug-in project: Hit Ctrl+3, enter 'npip' (just the letters, not the quotes), hit Return.
  4. Enter a project name, for example 'GettingStarted'.
  5. Keep the default options (Target: Eclipse 3.3, plug-in will make contributions to UI, no RCP application) and click the Finish button.
  6. In the plug-in manifest editor, switch to the 'Dependencies' tab.
  7. Under 'Required Plug-ins', click 'Add...'.
  8. In the dialog, type '*databinding'. (Note the leading wildcard character.)
  9. Multi-select org.eclipse.core.databinding, org.eclipse.core.databinding.beans, and org.eclipse.jface.databinding, and click 'OK'.
  10. Save and then close the plug-in manifest editor.
  11. Create a new Java package (File > New > Package) and pick a name for it, e.g. 'starting'.
  12. Create a new Java class (File > New > Class) in that package, called 'GettingStarted'.

Example Code

Copy the following example code - consisting of three parts - into the new class. Use 'Source > Organize Imports' to get the appropriate import statements (make sure to select the SWT types for Text, Button, and Label, and to select org.eclipse.core.databinding.observable.Realm).

Save the file and then select 'Run > Run As > Java Application'. Enter a numeric value in the text field and observe how the label is updated automatically. Click on the button to double the amount. You can also try entering a non-numeric value.

public class GettingStarted {

	static Model model = new Model();
	
	static void init(Shell shell) {
		Text text = new Text(shell, SWT.BORDER);
		Label label = new Label(shell, SWT.NONE);

		Button button = new Button(shell, SWT.PUSH);
		button.setText("Double!");
		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				model.setAmount(model.getAmount() * 2);
			}
		});
		
		DataBindingContext dbc = new DataBindingContext();

		IObservableValue modelObservable = BeansObservables.observeValue(model, "amount");

		dbc.bindValue(SWTObservables.observeText(text, SWT.Modify), modelObservable, null, null);
		dbc.bindValue(SWTObservables.observeText(label), modelObservable, null, null);
		
		GridLayoutFactory.swtDefaults().generateLayout(shell);
	}

The above code assumes that a SWT Shell has already been created, and that there is a model object with an 'amount' property. Both will be implemented in the remaining two code pieces.

A text widget, a label, and a button are created within the shell. When the button is clicked, the model's amount will be doubled, using the getter and setter methods supported by the model object.

A data binding context is created. This is an object that will hold on to the bindings that you create. Bindings can be created between observable objects. In our example, we create one observable for our model object's property, and two observables on the UI side, one for the text, and another one for the label. The two 'null' arguments are for configuring validators or converters; by passing null, we will get default validators and converters. Note that the model property is of a numeric type while the text widget holds strings. Clearly, some kind of conversion is needed here.

	static class Model {
		private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
		public void addPropertyChangeListener(String propertyName,
				PropertyChangeListener listener) {
			changeSupport.addPropertyChangeListener(propertyName, listener);
		}
		public void removePropertyChangeListener(String propertyName,
				PropertyChangeListener listener) {
			changeSupport.removePropertyChangeListener(propertyName, listener);
		}
		private int amount = 0;
		public void setAmount(int newAmount) {
			int oldAmount = this.amount;
			this.amount = newAmount;
			changeSupport.firePropertyChange("amount", oldAmount, newAmount);
		}
		public int getAmount() {
			return amount;
		}
	}

This is a pretty basic model class that conforms to the JavaBeans specification by delegating listener management to a PropertyChangeSupport object. For convenience, it is implemented as a static inner class. You can easily add more properties to the model class, but don't forget to implement public getters and setters for them, and to make appropriate calls to changeSupport.firePropertyChange() from all setters.

	public static void main(String[] args) {
		final Display display = new Display();
		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
			public void run() {
				Shell shell = new Shell(display);
				init(shell);
				shell.pack();
				shell.open();
				while (!shell.isDisposed()) {
					if (!display.readAndDispatch())
						display.sleep();
				}
			}
		});
		display.dispose();
	}
}

This is the standard SWT event loop with one complication - a SWT Realm is created and made the default realm for our application. Think of a Realm as an abstraction of SWT's UI thread. If everything in your application happens in the UI thread, you don't have to deal with Realms in your binding code. For more details on this, see the FAQ or the wiki page that explains in detail what a Realm is.