SWT Frage zu MVC und Data-Binding

babuschka

Top Contributor
Hallo Leute,

das lest ihr sicher häufig: ich bin blutiger Anfänger in Sachen Java + SWT + JFace. Und das soll sich natürlich ändern 😉

Zunächst einmal was ich überhaupt vorhabe:
Der Nutzer kann über einen Spinner eine Zahl bestimmen, welche dann rechts daneben in einem Label angezeigt wird. Also wirklich nichts Spektakuläres 😳
Vorweg bevor ich noch Leute verschrecke: es funktioniert bereits 😉

Mein Code sieht folgendermaßen aus:
Die Gui:
Java:
package view;
/**
 * @author M
 * @date 05 August 2010 
 */

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import model.Person;

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.jface.databinding.swt.SWTObservables;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.SWT;

/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit [url=http://www.cloudgarden.com]Cloud Garden (Java Resources)[/url] for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
public class Gui extends org.eclipse.swt.widgets.Composite {
	private Label label1;
	
	private Person person = new Person();;
	private Spinner spinner1;

	/**
	* Auto-generated main method to display this 
	* org.eclipse.swt.widgets.Composite inside a new Shell.
	*/
	public static void main(String[] args) {
		showGUI();
	}
	
	/**
	* Overriding checkSubclass allows this class to extend org.eclipse.swt.widgets.Composite
	*/	
	protected void checkSubclass() {
	}
	
	/**
	* Auto-generated method to display this 
	* org.eclipse.swt.widgets.Composite inside a new Shell.
	*/
	public static void showGUI() {
		Display display = Display.getDefault();
		Shell shell = new Shell(display);
		Gui inst = new Gui(shell, SWT.NULL);
		Point size = inst.getSize();
		shell.setLayout(new FillLayout());
		shell.layout();

		//sets windows title
		shell.setText("MVC Test");
		//sets minimum windows size
		shell.setMinimumSize(152, 65);
		
		if(size.x == 0 && size.y == 0) {
			inst.pack();
			shell.pack();
		} else {
			Rectangle shellBounds = shell.computeTrim(0, 0, size.x, size.y);
			shell.setSize(shellBounds.width, shellBounds.height);
		}
		
		// opens new centered windows
		Monitor primary = display.getPrimaryMonitor();
		Rectangle bounds = primary.getBounds();
		Rectangle rect = shell.getBounds();
		int x = bounds.x + (bounds.width - rect.width) / 2;
		int y = bounds.y + (bounds.height - rect.height) / 2;
		shell.setLocation (x, y);
		
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
	}

	public Gui(org.eclipse.swt.widgets.Composite parent, int style) {
		super(parent, style);
		initGUI();
		
		createBindings();
		createModelListener();
	}

	private void initGUI() {
		try {
			FormLayout thisLayout = new FormLayout();
			this.setLayout(thisLayout);
			{
				label1 = new Label(this, SWT.NONE);
				FormData label1LData = new FormData();
				label1LData.left =  new FormAttachment(0, 1000, 85);
				label1LData.top =  new FormAttachment(0, 1000, 6);
				label1LData.width = 50;
				label1LData.height = 20;
				label1.setLayoutData(label1LData);
				label1.setText("Alter");
			}
			{
				spinner1 = new Spinner (this, SWT.BORDER);
				spinner1.setMinimum(0);
				spinner1.setMaximum(80);
				spinner1.setSelection(20);
				spinner1.setIncrement(1);
				
				FormData spinner1Data = new FormData();
				spinner1Data.left =  new FormAttachment(0, 1000, 0);
				spinner1Data.top =  new FormAttachment(0, 1000, 1);
				spinner1Data.width = 50;
				spinner1Data.height = 20;
				
				spinner1.setLayoutData(spinner1Data);
				spinner1.pack();

			}
			this.layout();
			pack();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void createBindings() {

		Realm.runWithDefault(SWTObservables.getRealm(Display.getCurrent()), new Runnable() {
			public void run() {
				DataBindingContext dbc = new DataBindingContext();
				dbc.bindValue(
						SWTObservables.observeSelection(spinner1),
						BeansObservables.observeValue(person, Person.PROPERTY_AGE),
						null,
						null
				);
				
				// converter from String to Int needed
				dbc.bindValue(SWTObservables.observeText(label1), BeansObservables.observeValue(person, Person.PROPERTY_AGE),
					    new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE), null);
			}
		});
	}
	
	private void createModelListener() {
		person.addPropertyChangeListener(new PropertyChangeListener() {		
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				System.out.println("Modell\u00e4nderung: " + evt.getPropertyName() + " = " + evt.getNewValue());
			}
		});
	}
}
Es wurde Jigloo genutzt.

Die Geschäftslogik:

Java:
package model;
/**
 * @author M
 * @date 05 August 2010 
 */

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class Person {
	/* age of a person */
	private int age;
	
	/* property names */
	public static final String PROPERTY_AGE = "age";
	
	/* list of observers */
	private PropertyChangeSupport support = new PropertyChangeSupport(this);
		
	/**
	 * returns the age of a person 
	 * @return age	age of a person
	 */
	public int getAge() {
		return age;
	}

	/**
	 * sets the age of a person and informs the listeners
	 * @param age 	age of person
	 */
	public void setAge(int age) {
		support.firePropertyChange("age", this.age, this.age = age);
	}

	/**
	 * standard constructor for java-beans specification
	 */
	public Person() {
	}
	
	/**
	 * adds <code>PropertyChangeListener</code> for all attributes 
	 * @param listener
	 */
	public void addPropertyChangeListener( PropertyChangeListener listener ) {
		support.addPropertyChangeListener(listener);
	}
	
	/**
	 * adds <code>PropertyChangeListener</code> for only one attribute
	 * @param propertyName
	 * @param listener
	 */
	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
		support.addPropertyChangeListener(propertyName, listener);
	}
	
	/**
	 * removes <code>PropertyChangeListener</code> for all attributes
	 * @param listener
	 */
	public void removePropertyChangeListener(PropertyChangeListener listener) {
		support.removePropertyChangeListener(listener);
	}
	
	/**
	 * removes <code>PropertyChangeListener</code> for only one attribute
	 * @param propertyName
	 * @param listener
	 */
	public void removePropertyChangeListener(String propertyName,PropertyChangeListener listener) {
		support.removePropertyChangeListener(propertyName, listener);
	}
}

Wie gesagat, das Ganze funktioniert bereits.

Nun finde ich es allerdings komisch, dass mein Controller bereits in der Gui integriert ist.

Ich möchte eine klare Trennung zwischen Code und Gui erreichen. Am liebsten hätte ich den Controller in einer extra Klasse - ist das zu empfehlen? Wie stelle ich das am Dümmsten an?
Welche Strategie wendet ihr an?


Danke schon im Voraus!


MfG

mateit
 
Hi,
hast du schon eine Lösung gefunden? Ich beschäftige mich aktuell mit ähnlichem und frage mich z.B., wo man am besten eine erste Datenvalidierung, und wo z.B. die Datenbindung positionieren sollte. Datenvalidierung geht vielleicht noch im View, aber gehört das Binding wirklich auch dazu?!
 
Danke für die Antwort, habe sie leider erst jetzt gesehen. 🙁
Ich mache es mir vermutlich zu komplex, möchte allerdings nun ein Model View Presenter Controller verwenden (Aufteilung Presenter vom MVP in viewspezifisch und nichtviewspezifisch). Die Validierung würde ich dann im Presenter machen, wobei die View ihren Presenter jeweils selbst erzeugt. Jetzt muss ich nur noch herausfinden, wie ich in rcp der view zugleich den übergeordneten controller mitgebe (ich benutze einen für mehrere views).
 
Danke für die Antwort, habe sie leider erst jetzt gesehen. 🙁
Ich mache es mir vermutlich zu komplex, möchte allerdings nun ein Model View Presenter Controller verwenden (Aufteilung Presenter vom MVP in viewspezifisch und nichtviewspezifisch). Die Validierung würde ich dann im Presenter machen, wobei die View ihren Presenter jeweils selbst erzeugt. Jetzt muss ich nur noch herausfinden, wie ich in rcp der view zugleich den übergeordneten controller mitgebe (ich benutze einen für mehrere views).

"Model View Presenter Controller" da gibt es net ^^... Entweder MVP oder MVC...
Das Databinding ist indem Tutorial doch beschrieben und für einfache Daten/Eingabe Validierung gibt es in dem Tutorial doch genauso Hinweise.
Das Binding unterstützt doch Validierung Strategien...
 
"Model View Presenter Controller" da gibt es net ^^... Entweder MVP oder MVC...
Das Databinding ist indem Tutorial doch beschrieben und für einfache Daten/Eingabe Validierung gibt es in dem Tutorial doch genauso Hinweise.
Das Binding unterstützt doch Validierung Strategien...

Doch, das gibts, siehe g**gle, direkt unter den ersten drei Hits ist ein "Paper" von Martin Hunter. Es ist eine Variante von MVP (ich habe ja nicht gesagt, dass es etwas ganz anderes wäre), mit Unterteilung des Presenters in viewspezifisch (Presenter) und nichtview-spezifisch(Controller).
Die Bekanntmachung von Presenter und Controller mache ich inzwischen über eventbasierte Anmeldung "hallo, da bin ich, lass mich an deinen Events teilhaben", funktioniert bisher ganz gut. Der passive View weiß rein gar nichts vom Model und kümmert sich auch sonst um nichts als nur die Anzeige. Ich denke, damit fahre ich ganz gut.😀
 
Achja: Validierung geschieht im Presenter. Der View sagt nur "es wurde etwas eingegeben", der Presenter generiert dazu eine Decoration.. vermutlich geht's auch anders und eleganter usw. usf., aber mir läuft die Zeit davon und so bin ich schneller, als wenn ich vorher versuche, den Weg der Weisheit zu finden. (soll keine Kritik sein, nur eine Begründung)
 
Wie gesagt ich versteh dein Problem nicht der BindingContext ist doch dein Controller der alles regelt wie die Daten in GUI und in Models kommen.

Von dem her weiß ich nicht was du eigentlich vor hast? Der BindingContext gibt dir doch alle Möglichkeiten mit...

In dem oben genannten ist doch ein Tutorial wie du ein IValidator schreibst...
 
Zuletzt bearbeitet von einem Moderator:
hi,
ich habe vor, ein Frontend für ein Datenstrommanagementsystem zu schreiben. Im Grunde nimmt es Eingaben vom User entgegen (welche Quellen gibt es und wie sollen sie kombiniert werden), parst sie als Anfrage und füttert das dsms damit. Dieses liefert anschließend permanent Ergebnisse, die dann grafisch dargestellt werden sollen.
Was ich mir eigentlich wünsche, ist ein Controller, der vollkommen von der GUI abgeschottet ist, sonst wird das zu chaotisch.
Mein Problem ist, dass meine Javakenntnisse vor zwei Wochen noch gerade soweit gingen, dass ich 'System.out.println()' konnte.. ich habe bisher immer in C, C# programmiert, muss das jetzt allerdings in Java machen.
Die Validierung habe ich erstmal auf Eis gelegt, wenn ich sie einbaue, gucke ich mir das Tutorium nochmal an.
 

Neue Themen


Zurück
Oben