JFace Databinding

lumo

Top Contributor
hallo,

ich versuche gerade eine eigene komponente mit databinding support zu implementieren.
eigentlich ist das eine einfache komponente, die aus anderen SET/JFace komponenten besteht.

ich hab in einer testanwendung databinding schon verwendet, allerdings nur mit den fertigen viewer und textfeldern...

hier mal meine klasse, der gui componente

Code:
public class BasicComposite extends Composite {
	private Text text;

	/**
	 * Create the composite.
	 * 
	 * @param parent
	 * @param style
	 */
	public BasicComposite(Composite parent, int style) {
		super(parent, style);
		GridLayout gridLayout = new GridLayout(3, true);
		gridLayout.marginHeight = 0;
		gridLayout.marginWidth = 0;
		gridLayout.verticalSpacing = 0;
		setLayout(gridLayout);
		setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		{
			Label label = new Label(this, SWT.NONE);
			label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
					false, 1, 1));
			label.setText("New Label");
		}
		{
			text = new Text(this, SWT.BORDER);
			text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
					2, 1));
		}

	}

	public DataBindingContext bind(Object obj, String fieldName) {
		// if the bindingContext is not valid... create a new one
		DataBindingContext bindingContext = new DataBindingContext();
		//
		IObservableValue textObserveTextObserveWidget = SWTObservables
				.observeText(text, SWT.Modify);
		IObservableValue objNameObserveValue = BeansObservables.observeValue(
				obj, fieldName);
		bindingContext.bindValue(textObserveTextObserveWidget,
				objNameObserveValue, null, null);
		//
		return bindingContext;
	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}
}
und hier noch der test... wo man sieht, dass es nicht klappt...
Code:
public class FormTest {
	// private DataBindingContext m_bindingContext;

	protected Shell shell;
	private SampleObject obj;
	private BasicComposite bc;
	private BasicComposite bc2;

	/**
	 * Launch the application.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		Display display = Display.getDefault();
		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
			public void run() {
				try {
					FormTest window = new FormTest();
					window.open();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Open the window.
	 */
	public void open() {
		Display display = Display.getDefault();
		createContents();
		shell.open();
		shell.layout();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
	}

	/**
	 * Create contents of the window.
	 */
	protected void createContents() {
		shell = new Shell();
		shell.setSize(450, 300);
		shell.setText("SWT Application");
		shell.setLayout(new GridLayout(1, false));
		{
			bc = new BasicComposite(shell, SWT.NONE);
			bc.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1,
					1));
		}
		{
			bc2 = new BasicComposite(shell, SWT.NONE);
			bc2.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
					1, 1));
		}
		obj = new SampleObject();
		bc.bind(obj, "name");
		bc2.bind(obj, "name");
	}
}

eigentlich wollte ich nur, dass ich dann per bind nur noch das objekt mitgeben muss (und den databinding-context)

PS: bei 37°C oder mehr in diesem büro ists schwer nen kühlen kopf zu behalten :bahnhof:
 
Zuletzt bearbeitet:
G

Gast2

Gast
Ich würde das Databinding nicht in die Klasse machen....
Ich würde eine getControl Methode machen und da dein text rausgeben und das Binding von draußen machen wie es üblich ist... =)
 

lumo

Top Contributor
hab jetzt noch ein problem gefunden.
und zwar hab ich als beispiel ein databindign auf ein objekt obj.
dann wird das objekt durch eine neue instanz überlagert (also obj = new SampleObject())
nun klappt das databinding nicht mehr.

jetzt ist die frage... wie kann ich dem erklären dass das obj gleich dem alten obj ist?
oder wie kann ich das alte binding entfernen (gezielt das, aus meiner komponente) um es neu zu verbinden?
 
G

Gast2

Gast
hab jetzt noch ein problem gefunden.
und zwar hab ich als beispiel ein databindign auf ein objekt obj.
dann wird das objekt durch eine neue instanz überlagert (also obj = new SampleObject())
nun klappt das databinding nicht mehr.

jetzt ist die frage... wie kann ich dem erklären dass das obj gleich dem alten obj ist?
oder wie kann ich das alte binding entfernen (gezielt das, aus meiner komponente) um es neu zu verbinden?

He was?
Wenn du die Instanz änderst musst du natürlich das Binding nochmal ausführen...
 

lumo

Top Contributor
klar, aber ich muss die alte instanz aus dem binding entfernen, sonst hab ich schlussendlich ein zugemülltes binding...

bsp

obj -> bind to text1
obj -> bind to text2

obj = new SampleObject();
obj -> bind to text1
obj -> bind to text2

wenn ich mir dann alle bindings ausgeben lasse, hab ich natürlich VIER, sollten aber nur zwei sein.. -> muss ich (bloss wie) die alten bindings (von text1 und text1) auflösen
 
G

Gast2

Gast
also ich würde nichts auflösen... aber hab noch nicht soviel mit dem binding gemacht wildcard weiß bestimm mehr ;)
 

lumo

Top Contributor
so ich habs jetzt mit einem workaround gelöst (bin mir recht sicher dass das schöner geht)

ich hab in meinem plugin eine bindingfactory die die bindings für mich macht.
diese soll jetzt die bindings nicht nur erzeugen, sondern auch merken ;)

ergo, erstelt die Factory ein Product wird dieses Binding gespeichert in einem Product, welches sich merkt, auf welcher componente es hängt, und welches objekt (class) und welcher value (string/bezeichner) damit verbunden ist... so kann ich per .equals dann das richtige objekt raussuchen und disposen

Java:
public class BindingFactory {
	private static final boolean DEBUG = true;
	private static final BindingFactory instance = new BindingFactory();
	private static DataBindingContext bindingContext = null;

	private List<Product> products = new LinkedList<Product>();

	public void removeBinding(Bindable component, Object obj, String value) {
		Product removeMe = new Product(null, component, obj, value);
		for (int i = 0; i < products.size(); i++) {
			Product check = products.get(i);
			if (check.equals(removeMe)) {
				if (DEBUG) {
					System.out.println("Match found");
				}
				check.removeBinding();
				products.remove(i);
			}
		}
	}

	private static class Product {
		private Binding b = null;
		private Bindable component = null;
		private Class<?> obj = null;
		private String value = null;

		public Product(Binding b, Bindable component, Object obj, String value) {
			super();
			this.b = b;
			this.component = component;
			this.obj = obj.getClass();
			this.value = value;
		}

		public boolean equals(Product other) {
			if (component.equals(other.component) && obj.equals(other.obj)
					&& value.equals(other.value)) {
				return true;
			}
			return false;
		}

		public void removeBinding() {
			if (DEBUG) {
				System.out.println("removing binding from " + this);
			}
			b.dispose();
		}

		@Override
		public String toString() {
			return "Product [b=" + b + ", component=" + component + ", obj="
					+ obj + ", value=" + value + "]";
		}
	}

	public DataBindingContext getBindingContext() {
		if (bindingContext == null) {
			bindingContext = new DataBindingContext();
		}
		return bindingContext;
	}

	public static BindingFactory getInstance() {
		instance.getBindingContext();
		return instance;
	}

	/**
	 * UpdateValueStrategy string2ClassStrategy = new UpdateValueStrategy();<br>
	 * string2ClassStrategy.setConverter(new StringToDateConverter());<br>
	 * UpdateValueStrategy class2Stringstrategy = new UpdateValueStrategy();<br>
	 * class2Stringstrategy.setConverter(new DateToStringConverter());<br>
	 * <br>
	 * Sample:<br>
	 * BindingFactory.bind(bc1.getControl(), 300, obj, "date", new
	 * String2Date(), new Date2String());
	 */
	public DataBindingContext bind(Bindable bindable, Integer delay,
			Object obj, String fieldName, IConverter string2ClassConverter,
			IConverter class2StringConverter) {

		if (delay == null || delay < 0) {
			delay = 300;
		}
		UpdateValueStrategy string2ClassStrategy = null;
		UpdateValueStrategy class2Stringstrategy = null;

		if (string2ClassConverter != null & class2StringConverter != null) {
			string2ClassStrategy = new UpdateValueStrategy();
			string2ClassStrategy.setConverter(string2ClassConverter);
			class2Stringstrategy = new UpdateValueStrategy();
			class2Stringstrategy.setConverter(class2StringConverter);
		}

		IObservableValue textObserveTextObserveWidget = null;

		// text field should be bind - this will be the most used case
		if (bindable.getControl() instanceof Text) {
			textObserveTextObserveWidget = SWTObservables.observeDelayedValue(
					delay, SWTObservables.observeText(bindable.getControl(),
							SWT.Modify));
		} else {
			System.err.println(String.format(
					"This type (%s) is not supported by %s yet.", bindable
							.getControl().getClass().getSimpleName().getClass()
							.getSimpleName(), BindingFactory.class
							.getSimpleName()));
		}

		IObservableValue objNameObserveValue = BeansObservables.observeValue(
				obj, fieldName);

		// BIND THE VALUE
		Binding b = bindingContext
				.bindValue(textObserveTextObserveWidget, objNameObserveValue,
						string2ClassStrategy, class2Stringstrategy);
		Product p = new Product(b, bindable, obj, fieldName);
		products.add(p);
		if (DEBUG) {
			System.out.println("added +" + p);
		}
		return bindingContext;
	}
}
 
Zuletzt bearbeitet von einem Moderator:

lumo

Top Contributor
:D

also nochmal, ich versuchs einfacher zu erklären.
ich erstelle ein OBJ auf das wird aufgepasst.
wenn ich die werte im OBJ ändere bekommens alle mit.
wenn ich jetzt das OBJ austausche, gegen eine neue instanz (der variablenname bleibt der selbe)
geht auch der aufpasser verloren.
wenn ich einen neuen aufpasser drauf anstze hab ich einen aufpasser, der nix tut, ausser meinen speicher zuzumüllen. (im prinzip hat dann eine komponente - zb ein textfeld mehrere aufpasse, die aber alle auf meine variable OBJ aufpassen sollen - nur dass eben nur einer die aktuelle version hat)

darum musste ich mir die quell-informationen für das binding merken, sodass ich das binding aus meiner bindingliste (wird bei mir in den products gespeichet) wieder finde :)

ich hoffe ich konnte jetzt etwas licht ins dunkel bringen und nicht den letzten funken verständnis auslöschen ;):toll:
 
G

Gast2

Gast
Ich weiß nicht ob das ein Problem ist ich würde einfach eine methode bindValues() machen. Und diese erneut Aufrufen und das neue Objekt zu binden. Ich glaub nicht das man was aufräumen muss...

Eventuell reicht auch eine einfache Update Methode, warum willst du die Instanz auch ändern???
JFace Data Binding
 
Zuletzt bearbeitet von einem Moderator:

Ähnliche Java Themen


Oben