Swing Designfrage (MVC)

y0dA

Top Contributor
Ähnliche Frage hatte ich schon im Thread http://www.java-forum.org/awt-swing-swt/109087-best-practise-tabbedpanes.html gestellt.
Und ich weiß dass es schon etliche Threads zu MVC gibt bzw. sogar Tutorials von Usern hier geschrieben - aber ich brauche hierbei eigentlich nicht unbedingt das Observer-Pattern (worauf alle Threads etc. basieren) oder etwa doch?

Meine aktualisierte Frage:
Ich will eine Swing Anwendung schreiben in welcher anfangs dem User eine Frage gestellt werden soll und abhängig davon soll danach entweder Seite A oder Seite B "gerendered" werden. Im Detail besteht Seite A aus einem Haufen von Eingabefeldern, welche in die Bereiche C,D und E aufgeteilt sind.

Meine Frage ist ob es in Swing üblich ist dass die Bereich C,D und E eigene Klassen sind oder ob man alles zusammen (auch Seite A und Seite B sowie die "Frageseite") in eine Klasse packt? Falls man eigene Klassen macht, ist es dann üblich dass man bspw. dem Konstruktor das "Model" übergibt oder wie komme ich dann bspw. in der Main-Klasse auf die einzelnen Werte die in den jeweiligen Bereichen/Seiten gesetzt wurden? Wie ist hierbei die beste Vorgehensweise?
 
G

Gast2

Gast
Je nachdem wie groß deine Klassen sind für 2 Eingabefelder würde ich keine eigene Klasse machen.
Aber wenn deine Bereiche eigene Module darstellen die du eventuell wieder verwenden kannst, dann würde ich auf jeden Fall eigenen Klassen machen.

Zu deiner anderen Frage, du kannst DI verwenden oder die Models im Konstruktor übergeben. Oder das Model im Controller halten und du verwendest in deiner GUI nur die Controller.
 

y0dA

Top Contributor
Habe noch eine Frage bezüglich der Listener (Action, Focus etc):

Also ich habe eine View und einen Controller, der Controller ist Member der View und der Controller besitzt das Model. Wenn ich nun bspw. auf einen Button klicke (Um einen Dateipfad anzugeben) soll im Folgenden sowohl die Variable hierzu im Model gesetzt werden als auch das JTextfield vor dem Button. Hierzu habe Ich am Button einen Actionlistener.

Ist zur Zeit so gelöst:
Java:
JTextField text = new JTextField();
button = new JButton("Button");
		buttonImages.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int returnVal = fileChooserDirectory
						.showOpenDialog(buttonImages);
				if (JFileChooser.APPROVE_OPTION == returnVal) {
					File file = fileChooserImagesDirectory.getSelectedFile();
					text.setText(file.getAbsolutePath());
                                        controller.getModel.setTextA(file.getAbsolutePath());
				}
			}
		});

Nun meine Frage, gehört dieser ActionListener nicht eigentlich in den Controller? Falls ja besteht dann das Problem dass ich ja auf der View mehrere Actions habe und das hiesse dann dass ich im Controller, in der Actionlistener Implementierung mehrere IF ELSE Konstrukte drinnen hätte weil ich ja prüfen muss welche Action ausgelöst werden muss. Wird das bei Swing so umgesetzt?
 
Zuletzt bearbeitet:

Michael...

Top Contributor
der Controller ist Member der View
Das wäre mir neu.
Nun meine Frage, gehört dieser ActionListener nicht eigentlich in den Controller?
In diesem Fall ja.

Da der Dateipfad scheinbar im Model gepflegt wird, wäre die Vorgehensweise so:

- Controller registriert sich (z.B. als ActionListener) an View
- Button in View wird gedrückt
- ActionListener im Controller reagiert und öffnet FileChooser
- nach Auswahl der Datei übergibt der Controller den Dateipfad an das Model
- Model informiert seine Observer (in dem Fall die View) über Änderung
- View reagiert auf Meldung des Models, liest den neuen Eintrag aus dem Model und setzt den Inhalt des Textfeldes oder Labels
 

y0dA

Top Contributor
Das wäre mir neu.

Laut diesem Thread wird der Controller aber in der View gesetzt: http://www.java-forum.org/softwareentwicklung/105441-model-view-controller-swing.html
--> Siehe MVC Beispiel von SirWayne.

Bei meinem Programm handelt es sich nur um ein dummes Eingabeformular und da wollte ich eigentlich ohne Oberserver etc auskommen. Also Minimum umsetzen.

Aber um auf deine Anmerkungen zurückzukommen, selbige sind natürlich Top und eigentlich gehört es so gemacht.
Hierzu eine Frage, wie setze ich selbiges um:
Ich habe ein JButton (JFileChooser ..) bei selbigem wird die Action ausgelöst, man kommt in den Controller, dort kann man das Model (welches im Controller ist) setzen und wie bekomme ich nun den neuen Wert in das JTextField. Irgendwie hänge ich da gerade, denn selbst wenn ich das JTextField so initialisiere:
[Java]
private Model model = new Model();
...
JTextField textField = new JTextField(model.getText);
[/code]

wird dann ja nicht der Wert im JTextField aktualisiert?
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Hier mal ein einfaches Bsp. für Dein Vorhaben, das Model enthält in diesem Fall einfach nur den String eines Dateipfades:
Java:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class MVCDemo3 extends JFrame {
	public MVCDemo3() {
		Controller controller = new Controller();
		this.getContentPane().add(controller.getView());
	}

	public static void main(String[] args) {
		JFrame frame = new MVCDemo3();
		frame.setBounds(0, 0, 500, 300);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
	
	class Controller implements ActionListener {
		private Model model;
		private View view;

		public Controller() {
			view = new View(model = new Model(""));
			view.addActionListener(this);
		}
		
		public void actionPerformed(ActionEvent evt) {
			JFileChooser fileChooser = new JFileChooser();
			int value = fileChooser.showOpenDialog(view);
			if (value==JFileChooser.APPROVE_OPTION)
				model.setValue(fileChooser.getSelectedFile().getAbsolutePath());
		}
		
		public JPanel getView() {
			return view;
		}
	}

	class View extends JPanel implements ModelListener {
		private Model model;
		private JLabel label;
		private JButton button;
		
		public View(Model model) {
			this.model = model;
			this.setLayout(new BorderLayout());
			this.add(label = new JLabel("", JLabel.CENTER), BorderLayout.CENTER);
			this.add(button = new JButton("Select File"), BorderLayout.SOUTH);
			model.addModelListener(this);
		}
		
		public void addActionListener(ActionListener listener) {
			button.addActionListener(listener);
		}
		
		public void modelChanged() {
			label.setText(model.getValue());
		}
	}

	class Model {
		private ArrayList<ModelListener> listenerList;
		private String data;

		public Model(String data) {
			this.data = data;
			listenerList = new ArrayList<ModelListener>();
		}

		public void addModelListener(ModelListener listener) {
			this.listenerList.add(listener);
		}

		public void setValue(String newValue) {
			this.data = newValue;
			this.fireModelChanged();
		}
		
		public String getValue() {
			return data;
		}

		private void fireModelChanged() {
			for (int i = 0; i < listenerList.size(); i++)
				listenerList.get(i).modelChanged();
		}
	}

	interface ModelListener {
		public void modelChanged();
	}
}
 
G

Gast2

Gast
Das wäre mir neu.

Warum sollte das neu sein??? Spricht nichts dagegen...


Ich verwende für ActionListener/FocusListener usw. immer als anonyme Klassen sowie du es gemacht hast.
Die stellen deine "GUI Controller" dar.
1. Wie du sagst ist es übersrichlicher nicht 1000 te ActionListener im Controller zu haben oder sogar 1000te Controller Klassen
2. Ist nur unnötiger overhead dann alle wichtigen Daten dem Controller weiter zu reichen.

Ich benutze dann nur noch einen Controller in einer eigenen Klasse, wenn ich z.B. noch einen Service o.ä. auf dem Server aufrufe. Oder noch eine Client Transaktion usw. regeln muss. Das übernimmt der Controller. Und das Model wird nur die Datenhalten, die in der Anwendung auf Client Seite notwendig sind.
 

y0dA

Top Contributor
Warum sollte das neu sein??? Spricht nichts dagegen...


Ich verwende für ActionListener/FocusListener usw. immer als anonyme Klassen sowie du es gemacht hast.
Die stellen deine "GUI Controller" dar.
1. Wie du sagst ist es übersrichlicher nicht 1000 te ActionListener im Controller zu haben oder sogar 1000te Controller Klassen
2. Ist nur unnötiger overhead dann alle wichtigen Daten dem Controller weiter zu reichen.

Ich benutze dann nur noch einen Controller in einer eigenen Klasse, wenn ich z.B. noch einen Service o.ä. auf dem Server aufrufe. Oder noch eine Client Transaktion usw. regeln muss. Das übernimmt der Controller. Und das Model wird nur die Datenhalten, die in der Anwendung auf Client Seite notwendig sind.

Entspricht das aber dann noch dem MVC Prinzip?

@michael..

Java:
        public void modelChanged() {
            label.setText(model.getValue());
        }
Bedeutet dass das ich hier nun alle Objekte der View neu setzen muss? (Meine View besteht ja nicht nur aus einem label :D)? Das würde bedeuten dass immer alles neu gesetzt werden würde auch wenn sich bspw. der Wert von label2 nicht geändert hat?
 
Zuletzt bearbeitet:

ThreadPool

Bekanntes Mitglied
Entspricht das aber dann noch dem MVC Prinzip?

Das MVC Prinzip lässt ich auf zwei Dinge zusammendampfen, Trennung zwischen Darstellung und Domänenmodell sowie Observer Benachrichtigung bei Veränderung des Modells. Das ist der gemeinsame Nenner aller "MVC"-Variationen.

Bedeutet dass das ich hier nun alle Objekte der View neu setzen muss? (Meine View besteht ja nicht nur aus einem label :D)? Das würde bedeuten dass immer alles neu gesetzt werden würde auch wenn sich bspw. der Wert von label2 nicht geändert hat?

Das hängt völlig davon ab wie "feingranular" du die Events haben möchtest, in der Praxis (zumindest in meiner) ist es hauptsächlich so das Alles aktualisiert wird.

Und das ursprüngliche MVC wie es mal in Smalltalk war lässt sich nicht so richtig verallgemeinern, da dort die Controller IHMO (korrigiert mich wenn ich falsch liege) Inputcontroller waren also eigentlich das was dir z.B. der EDT und die JVM im großen Stil abnimmt, verarbeiten von Input, Events auslösen weiterleiten der Events an die Widgets etc. pp.

Du kannst auch mal einen Blick in die Links im folgenden Beitrag werfen.

http://www.java-forum.org/allgemeines/91829-mvc.html#post596074
 
Zuletzt bearbeitet:

Marco13

Top Contributor
der Controller ist Member der View
Das wäre mir neu.
Warum sollte das neu sein??? Spricht nichts dagegen...

Ich finde schon, dass da was dagegen spricht - zumindest wenn man nicht aufpasst. Ich finde, es sollte NICHT so sein, dass dort tatsächlich sowas steht wie
Java:
class View 
{
    private Controller controller; // Nur jetzt ist er ein "Member" im C++-Sinn
    ...
}

Den oder die Controller innerhalb der View zu instantiieren (im Sinne von anonymen Listenern) ist aber OK: Das ist - wenn man nicht nachlässig ist - etwas sehr "atomares", d.h. diese Instantiierung könnte auch woanders gemacht werden. Man sollte versuchen, Schnitstellen-Abhängigkeit zwischen View und Controller zu vermeiden: Spätestens, wenn im Controller "getView" und in der View "getController" vorkommen, hat man IMHO was falsch gemacht...
 
G

Gast2

Gast
Laut diesem Thread wird der Controller aber in der View gesetzt: http://www.java-forum.org/softwareentwicklung/105441-model-view-controller-swing.html
--> Siehe MVC Beispiel von SirWayne.

Bei meinem Programm handelt es sich nur um ein dummes Eingabeformular und da wollte ich eigentlich ohne Oberserver etc auskommen. Also Minimum umsetzen.

Aber um auf deine Anmerkungen zurückzukommen, selbige sind natürlich Top und eigentlich gehört es so gemacht.
Hierzu eine Frage, wie setze ich selbiges um:
Ich habe ein JButton (JFileChooser ..) bei selbigem wird die Action ausgelöst, man kommt in den Controller, dort kann man das Model (welches im Controller ist) setzen und wie bekomme ich nun den neuen Wert in das JTextField. Irgendwie hänge ich da gerade, denn selbst wenn ich das JTextField so initialisiere:
[Java]
private Model model = new Model();
...
JTextField textField = new JTextField(model.getText);
[/code]

wird dann ja nicht der Wert im JTextField aktualisiert?

Was genau verstehst du denn nicht in meinem Beispiel wird doch alles aufgezeigt.

MVC hat immer was mit Observer zu tun. Irgendwie muss deine Model eine Notification API haben, sonst kannst nicht aktualisieren.
 
G

Gast2

Gast
Ich finde schon, dass da was dagegen spricht - zumindest wenn man nicht aufpasst. Ich finde, es sollte NICHT so sein, dass dort tatsächlich sowas steht wie
Java:
class View 
{
    private Controller controller; // Nur jetzt ist er ein "Member" im C++-Sinn
    ...
}

Den oder die Controller innerhalb der View zu instantiieren (im Sinne von anonymen Listenern) ist aber OK: Das ist - wenn man nicht nachlässig ist - etwas sehr "atomares", d.h. diese Instantiierung könnte auch woanders gemacht werden. Man sollte versuchen, Schnitstellen-Abhängigkeit zwischen View und Controller zu vermeiden: Spätestens, wenn im Controller "getView" und in der View "getController" vorkommen, hat man IMHO was falsch gemacht...

Darum lieber anonyme Listener, da sie was mit dem GUI Toolkit zu tun haben, und sagen wir mal für andere Toolkit nicht wiederverwendbar sind.
Und wenn man Controller vom GUI Toolkit reinhält könnte man sie wiedervwenden (zumindest bei Desktopapplikationen).

Aber spricht dagegen den Controller als Membervariable zu halten, wie würdest du es denn machen?
 

Marco13

Top Contributor
Aber spricht dagegen den Controller als Membervariable zu halten, wie würdest du es denn machen?

Schwer so pauschal zu sagen, es gibt ja schon etliche Threads in denen ich über MVC und die Rolle des Controllers philosophiert habe, es gibt IMHO nur in bestimmen Bereichen Fälle, wo man wirklich eine Klasse hat, die dem Namen und Sinn nach ein "Controller" ist (der über einen anonymen Listener hinausgeht). Es kann natürlich Sinn machen, so einen Controller als Instanzvariable vorzuhalten, spätestens wenn man ihn als Listener auch wieder entfernen können will ;) aber ... wie immer mit möglichst wenigen Abhängigkeiten und Implementierungsdetails...
 

y0dA

Top Contributor
Noch was anderes, wie bekomme ich bspw. von einem FocusEvent raus wer der Aufrufer war? Habe beim textField den ActionCommand gesetzt (gilt der auch für FocusEvent?) und sehe den Wert auch beim debuggen in event.getSource() unter command - nur drauf zugreifen kann ich nicht?
 
G

Gast2

Gast
Schwer so pauschal zu sagen, es gibt ja schon etliche Threads in denen ich über MVC und die Rolle des Controllers philosophiert habe, es gibt IMHO nur in bestimmen Bereichen Fälle, wo man wirklich eine Klasse hat, die dem Namen und Sinn nach ein "Controller" ist (der über einen anonymen Listener hinausgeht). Es kann natürlich Sinn machen, so einen Controller als Instanzvariable vorzuhalten, spätestens wenn man ihn als Listener auch wieder entfernen können will ;) aber ... wie immer mit möglichst wenigen Abhängigkeiten und Implementierungsdetails...

Okay das stimmt ;)...

Wie gesagt ich setz nur einen zusätzlichen Controller ein, wenn er wirklich von der GUI Toolkit frei bleibt und es Sinn macht. Wie z.b. wenn ich einen Service vom Server aufrufe und sich dann das Model ändert. Eventuell auch ein bischen Logik vorhanden ist usw.
Aber ich würde diesen zusätzlichen Controller glaub nie als Listener verwenden.

Und ich finde ob die View jetzt eine Abhänigkeit zum Model oder zu so einem zusätzlichen Controller hat finde ich jetzt nun keinen großen Unterschied. Die GUI wird immer Abhänigkeiten haben.
 

Marco13

Top Contributor
...sehe den Wert auch beim debuggen in event.getSource() unter command - nur drauf zugreifen kann ich nicht?

Falls du das meinst:
Java:
Object source = event.getSource();
if (source intanceof JTextField) // Könnte ja auch irgenwas anderes sein
{
    JTextField textField = (JTextField)source;
    ...
}
// Oder:
if (source == meinGanzBestimmtesTextField)
{
    ...
}
 


Schreibe deine Antwort... und nutze den </> Button, wenn du Code posten möchtest...

Ähnliche Java Themen

Neue Themen


Oben