Recently I have started using JFace Binding. Unfortunately there are not many resources available on the web with non-trivial examples.
Let present example of master-detail view: a drop-down list and two text fields which display some details regarding option chosen from the list.
POJO Category. It contains two fields: name and description which will be displayed as details of the object chosen from the drop-down list:
import java.beans.PropertyChangeListener; import java.io.Serializable; /** * Domain object representing category * */ public class Category implements Serializable { private static final long serialVersionUID = -5542167952605551865L; private String name; private String description; /** * Default constructor */ public Category() { // Do nothing } /** * Constructor * * @param name * name of a category * @param description * description of a category */ public Category(String name, String description) { this.name = name; this.description = description; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the description */ public String getDescription() { return description; } /** * @param description the description to set */ public void setDescription(String description) { this.description = description; } }
Class of model that will be used to bind the data to the view:
import java.util.List; /** * Model for displaying categories * */ public class CategoriesModel extends AbstractModelObject { private List categories; private IDataManager dataManager; private Category category; /** * The constructor */ public CategoriesModel() { this.dataManager = Activator.getDataManager(); this.categories = this.dataManager.getAllCategories(); } /** * @return the category */ public Category getCategory() { return this.category; } /** * @param category * the category to set */ public void setCategory(Category category) { this.category = category; } /** * @return the categories */ public List getCategories() { return categories; } /** * @param categories the categories to set */ public void setCategories(List categories) { this.categories = categories; } }
Class of view (in this case it is Eclipse View containing managed form):
import java.util.logging.Logger; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.UpdateValueStrategy; import org.eclipse.core.databinding.beans.BeansObservables; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.core.databinding.observable.list.WritableList; import org.eclipse.core.databinding.observable.map.IObservableMap; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.jface.databinding.swt.SWTObservables; import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider; import org.eclipse.jface.databinding.viewers.ViewersObservables; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.ManagedForm; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.part.ViewPart; /** * Allows to view list of categories and their details * */ public class CategoryView extends ViewPart { private Logger logger = Logger.getLogger(CategoryView.class.getName()); private static final String FORM_TITLE = Messages .getString("category.view.form.title"); private FormToolkit formToolkit; private CategoriesModel model; private Text nameText; private Text descriptionText; private ComboViewer categoriesComboViewer; private DataBindingContext dbc; /** * {@inheritDoc} */ @Override public void createPartControl(Composite parent) { model = new CategoriesModel(); ManagedForm mForm = new ManagedForm(parent); ScrolledForm scrolledForm = mForm.getForm(); FormToolkit formToolkit = mForm.getToolkit(); Composite formBody = scrolledForm.getBody(); formToolkit.decorateFormHeading(scrolledForm.getForm()); scrolledForm.setText(FORM_TITLE); formBody.setLayout(new GridLayout(2, true)); categoriesComboViewer = new ComboViewer(formBody, SWT.DROP_DOWN | SWT.READ_ONLY); GridData comboGridData = new GridData(); comboGridData.horizontalSpan = 2; comboGridData.horizontalAlignment = GridData.FILL; categoriesComboViewer.getCombo().setLayoutData(comboGridData); nameText = formToolkit.createText(formBody, "", SWT.NONE); GridData nameGridData = new GridData(); nameGridData.horizontalSpan = 2; nameGridData.horizontalAlignment = GridData.FILL; nameText.setLayoutData(nameGridData); descriptionText = formToolkit.createText(formBody, "", SWT.MULTI); GridData textGridData = new GridData(); textGridData.horizontalSpan = 2; textGridData.horizontalAlignment = GridData.FILL; textGridData.heightHint = 100; descriptionText.setLayoutData(textGridData); formToolkit.paintBordersFor(formBody); bindData(); } /** * {@inheritDoc} */ @Override public void setFocus() { // Do nothing } /** * This method binds the value from UI layer to the model object */ protected void bindData() { dbc = new DataBindingContext(); // Seting content provider for combo viewer ObservableListContentProvider categoryViewerContentProvider = new ObservableListContentProvider(); categoriesComboViewer.setContentProvider(categoryViewerContentProvider); IObservableMap[] attributeMaps = BeansObservables.observeMaps( categoryViewerContentProvider.getKnownElements(), Category.class, new String[] { "name" }); categoriesComboViewer.setLabelProvider(new ObservableMapLabelProvider( attributeMaps)); categoriesComboViewer.setInput(new WritableList(model.getCategories(), Category.class)); // Observing changes in selection in combo viewer IObservableValue selection = ViewersObservables .observeSingleSelection(categoriesComboViewer); // Observing the properties of the current selection IObservableValue detailNameObservable = BeansObservables .observeDetailValue(Realm.getDefault(), selection, "name", String.class); IObservableValue detailDescriptionObservable = BeansObservables .observeDetailValue(Realm.getDefault(), selection, "description", String.class); // Binding the Text widgets to the name and description details // (selection's properties). dbc.bindValue(SWTObservables.observeText(nameText, SWT.None), detailNameObservable, new UpdateValueStrategy(false, UpdateValueStrategy.POLICY_NEVER), null); dbc.bindValue(SWTObservables.observeText(descriptionText, SWT.None), detailDescriptionObservable, new UpdateValueStrategy(false, UpdateValueStrategy.POLICY_NEVER), null); } /** * {@inheritDoc} */ public void dispose() { if (formToolkit != null) { formToolkit.dispose(); } super.dispose(); } }
AbstractModelObject which provides methods required by JFace Binding (it’s not checked on compilation level):
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; /** * Provides minimal JavaBeans support for model objects * */ public abstract class AbstractModelObject { private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this); /** * @param listener */ public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } /** * @param propertyName * @param listener */ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(propertyName, listener); } /** * @param listener */ public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } /** * @param propertyName * @param listener */ public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(propertyName, listener); } /** * * @param propertyName * @param oldValue * @param newValue */ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } }
This is a great example. However, I’m trying to do something like this with a TableViewer. And I when creating the BindingContext I get a runtime error “Realm cannot be null.” My class extends a ViewPart, so it doesn’t have a main method. Have you seen this error?
LikeLike
@Igor I haven’t used binding with TableViewer so far. But I suggest you check if you are passing Realm instance to all Observables objects.
LikeLike
I can’t run this program because of some error happen.
1. private IDataManager dataManager;
2.java.lang.IllegalArgumentException: Could not find property with name name in class class testcombo.ViewPart1
at org.eclipse.core.internal.databinding.beans.BeanPropertyHelper.getPropertyDescriptor(BeanPropertyHelper.java:177)
at org.eclipse.core.databinding.beans.BeanProperties.value(BeanProperties.java:116)
at org.eclipse.core.databinding.beans.BeanProperties.value(BeanProperties.java:87)
at org.eclipse.core.databinding.beans.BeansObservables.observeMap(BeansObservables.java:122)
at org.eclipse.core.databinding.beans.BeansObservables.observeMaps(BeansObservables.java:254)
at testcombo.ViewPart1.bindData(ViewPart1.java:102)
at testcombo.ViewPart1.createPartControl(ViewPart1.java:82)
at org.eclipse.ui.internal.ViewReference.createPartHelper(ViewReference.java:367)
at org.eclipse.ui.internal.ViewReference.createPart(ViewReference.java:226)
at org.eclipse.ui.internal.WorkbenchPartReference.getPart(WorkbenchPartReference.java:595)
at org.eclipse.ui.internal.PartPane.setVisible(PartPane.java:313)
at org.eclipse.ui.internal.ViewPane.setVisible(ViewPane.java:529)
at org.eclipse.ui.internal.presentations.PresentablePart.setVisible(PresentablePart.java:180)
at org.eclipse.ui.internal.presentations.util.PresentablePartFolder.select(PresentablePartFolder.java:270)
at org.eclipse.ui.internal.presentations.util.LeftToRightTabOrder.select(LeftToRightTabOrder.java:65)
at org.eclipse.ui.internal.presentations.util.TabbedStackPresentation.selectPart(TabbedStackPresentation.java:473)
at org.eclipse.ui.internal.PartStack.refreshPresentationSelection(PartStack.java:1256)
at org.eclipse.ui.internal.PartStack.setSelection(PartStack.java:1209)
at org.eclipse.ui.internal.PartStack.showPart(PartStack.java:1608)
at org.eclipse.ui.internal.PartStack.createControl(PartStack.java:649)
at org.eclipse.ui.internal.PartStack.createControl(PartStack.java:576)
at org.eclipse.ui.internal.PartSashContainer.createControl(PartSashContainer.java:568)
at org.eclipse.ui.internal.PerspectiveHelper.activate(PerspectiveHelper.java:272)
at org.eclipse.ui.internal.Perspective.onActivate(Perspective.java:981)
at org.eclipse.ui.internal.WorkbenchPage.onActivate(WorkbenchPage.java:2626)
at org.eclipse.ui.internal.WorkbenchWindow$27.run(WorkbenchWindow.java:2964)
at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
at org.eclipse.ui.internal.WorkbenchWindow.setActivePage(WorkbenchWindow.java:2945)
at org.eclipse.ui.internal.WorkbenchWindow.busyOpenPage(WorkbenchWindow.java:760)
at org.eclipse.ui.internal.Workbench$21.runWithException(Workbench.java:1045)
at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3468)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3115)
at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:803)
at org.eclipse.ui.internal.Workbench$28.runWithException(Workbench.java:1384)
at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:179)
at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:150)
at org.eclipse.swt.widgets.Display.syncExec(Display.java:4113)
at org.eclipse.ui.internal.StartupThreading.runWithoutExceptions(StartupThreading.java:94)
at org.eclipse.ui.internal.Workbench.init(Workbench.java:1379)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2335)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at testcombo.Application.start(Application.java:20)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
Could you explain it to me. Thanks!
LikeLike
Do you have public String getName() and void setName(String name) methods?
LikeLike