# einfaches Beispiel zu MVC und Sinn V --> M ?



## ernst (13. Aug 2012)

Hallo allerseits,
versuche gerade das MVC Entwurfsmuster zu verstehen:
C --> V--> M  und C --> M

Deshalb habe ich den Vorschlag in
Tutorial: Model-View-Controller (MVC) Struktur in Java Projekten nutzen  BigBastis Blog
in einem einfachen Beispiel nachprogrammiert (siehe unten).
Leider fehlt dort die Implementierung von V --> M

1)
Warum kann eigentlich V auf M direkt zugreifen, ohne den Controler zu verwenden?
Dann kann man das MVC ja gleich - ohne Verwendung von C - modellieren.
Also wie folgt:
V --> M

2) 
Wie kann man das Java-Beispiel möglichst einfach ergänzen, so dass auch V --> M
implementiert wird und einen Sinn ergibt ?

mfg
Ernst




```
package MainTaschenrechnermvc10;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class TaschenrechnerMVC10 {

    public static void main(String[] args) {
        TRController trController = new TRController();
        trController.getTRView().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

class TRModel {

    private double sum;

    public TRModel() {
        reset();
    }

    public void addiere(double wert1, double wert2) {
        sum = wert1 + wert2;
    }

    public void reset() {
        sum = 0;
    }

    public double getSumme() {
        return sum;
    }
}

class TRView extends JFrame {
    private Container mycont;
    private JButton mybtPlus;
    private JTextField mytfZahl1;
    private JTextField mytfZahl2;
    private JTextField mytfErg;
    private JLabel dummyLabel1;
    private JLabel dummyLabel2;
    private JPanel myp;
    private GridLayout myGL23;

    public TRView() {
        mycont = getContentPane();
        mybtPlus = new JButton("+");
        mytfZahl1 = new JTextField("hier 1. Zahl eingeben", 30);
        mytfZahl2 = new JTextField("hier 2. Zahl eingeben", 30);
        mytfErg = new JTextField("hier kommt das Ergebnis", 30);
        dummyLabel1 = new JLabel();
        dummyLabel2 = new JLabel();
        myp = new JPanel();
        myGL23 = new GridLayout(2, 3);
        myp.setLayout(myGL23);
        myp.add(mytfZahl1);
        myp.add(mytfZahl2);
        myp.add(mytfErg);
        myp.add(mybtPlus);
        myp.add(dummyLabel1);
        myp.add(dummyLabel2);
        mycont.add(myp);
        setTitle("Einfaches MVC");
        setLocation(30, 60);
        setSize(600, 400);
        setVisible(true);
    }

    public String getJTextField1() {
        return mytfZahl1.getText();
    }

    public String getJTextField2() {
        return mytfZahl2.getText();
    }

    public String getJTextFieldErg() {
        return mytfErg.getText();
    }

    public void setJTextField1(String str) {
        this.mytfZahl1.setText(str);
    }

    public void setJTextField2(String str) {
        this.mytfZahl2.setText(str);
    }

    public void setJTextFieldErg(String str) {
        this.mytfErg.setText(str);
    }

    public void setAdditionsListener(ActionListener l) {
        mybtPlus.addActionListener(l);
    }
}

class TRController {

    private TRView trView;
    private TRModel trModel;

    public TRController() {
        trView = new TRView();
        trModel = new TRModel();
        addListener();
    }

    public TRView getTRView() {
        return trView;
    }

    public void addListener() {
        trView.setAdditionsListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                double wert1 = Double.valueOf(trView.getJTextField1());
                double wert2 = Double.valueOf(trView.getJTextField2());
                trModel.addiere(wert1, wert2);
                trView.setJTextFieldErg(String.valueOf(trModel.getSumme()));
            }
        });
    }
}
```


----------



## Michael... (13. Aug 2012)

ernst hat gesagt.:


> 1)
> Warum kann eigentlich V auf M direkt zugreifen, ohne den Controler zu verwenden?
> Dann kann man das MVC ja gleich - ohne Verwendung von C - modellieren.
> Also wie folgt:
> V --> M


kann man, dann muss die View aber den Controller selbst implementieren. Der Controller dient ja dazu - wie der Name schon sagt - zu steuern, um z.B. Benutzereingaben/aktionen kontrolliert auf das Model zu übertragen.


ernst hat gesagt.:


> 2)
> Wie kann man das Java-Beispiel möglichst einfach ergänzen, so dass auch V --> M
> implementiert wird und einen Sinn ergibt ?


Bei Deinem Taschenrechnerbeispiel ist das schwierg. TRModel ist kein Model und enthält nur Methoden die eigentlich in einen Controller gehören.
Ein Model bei einem Taschenrechner würde m.M. nur Sinn machen, um den Zwischenwerte zu speichern oder wenn er Memoryfunktionen anbietet.


----------



## ernst (13. Aug 2012)

> kann man, dann muss die View aber den Controller selbst implementieren. Der Controller dient ja dazu - wie der Name schon sagt - zu steuern, um z.B. Benutzereingaben/aktionen kontrolliert auf das Model zu übertragen.




1) Welchen Sinn macht es, dass V auf M direkt zugreift?
Der Zugriff auf M  soll doch über den Controler geschehen ?
Also wäre MVC doch so besser:
C --> M und C --> V

2) Ich werde versuchen, deinen Vorschlag mit den Memoryfunktionen zu implementieren.

mfg
Ernst


----------



## Michael... (13. Aug 2012)

ernst hat gesagt.:


> 1) Welchen Sinn macht es, dass V auf M direkt zugreift?
> Der Zugriff auf M  soll doch über den Controler geschehen ?


Das MVC Konzept sieht vor, dass sich die View die Daten direkt aus dem Model holt.
Da die View direkt vom Model über Änderungen benachrichtigt wird, macht es auch Sinn, dass die View sich die geänderten Daten über das Modell holt. Der Controller dient  ja nur daszu die Aktionen der View zu steuern. Eine passive, nur anzeigende View kann dann auf einen Controller verzichten.


----------



## ernst (13. Aug 2012)

Michael... hat gesagt.:


> Das MVC Konzept sieht vor, dass sich die View die Daten direkt aus dem Model holt.
> Da die View direkt vom Model über Änderungen benachrichtigt wird, macht es auch Sinn, dass die View sich die geänderten Daten über das Modell holt. Der Controller dient  ja nur daszu die Aktionen der View zu steuern. Eine passive, nur anzeigende View kann dann auf einen Controller verzichten.



Ich verstehe noch nicht den Zusammenhang.
Wie läuft der Informationsfluss ab?
Daten (z.B. zu addierende Zahlen) werden vom Benutzer eingegeben.
Dies geschieht doch z.B. in einem Textfeld innerhalb des Controlers.
Der Controler verändert darauf die Daten im Model.
Das Model benachrichtigt die View über die geänderten Daten.
Daraufhin stellt die View die Daten auf dem Bildschirm dar.
Ist das so korrekt ?

mfg
Ernst


----------



## faetzminator (13. Aug 2012)

Richtig, so würde ich ebenfalls ein MVC-Modell implementieren.
Edit: Noch zwei kleine Anmerkungen: Wenn GUI unabhängig implementiert werden soll, kann das GUI einen Event (eines Textfeldes) abfangen und mit eigener Impl dem Controller übergeben (bzw. einen neuen Event gegenüber dem Controller feuern). Ebenfalls kann der Event des Models ("Daten geändert") an den Controller gerichtet werden, welcher dem GUI in diesem Fall ein repaint auslöst (ebenfalls wieder eigenes Interface).


----------



## Michael... (13. Aug 2012)

ernst hat gesagt.:


> Ich verstehe noch nicht den Zusammenhang.
> Wie läuft der Informationsfluss ab?
> Daten (z.B. zu addierende Zahlen) werden vom Benutzer eingegeben.
> Dies geschieht doch z.B. in einem Textfeld innerhalb des Controlers.


Ein Textfeld ist Bestandteil der View.

Bei einem einfachen Taschenrechner macht es eigentlich keinen Sinn mit einem Model zu arbeiten. Das einzige Datum, welches das Model halten und verwalten könnte wäre das aktuelle Zwischenergebnis evtl. die nächste auszuführende Operation.
Je nach Implementierung könnte das so aussehen:
Anwender gibt 3 ins Textfeld der View ein.
Anwender drückt "+" der View --> Controller erhält "Nachricht", dass "+" gedrückt wurde.
Controller liest den Wert in Textfeld aus oder hat den Wert bereits über ein Event erhalten.
Controller setzt das aktuelle Zwischenergebnis im Modell auf 3 und den auszuführenden Operator auf "+" --> Modell benachrichtigt View, dass allgemein, dass sich Werte geändert haben oder auch speziell welche Werte sich geändert haben.
View liest Zwischergebnis aus Model und stellt es im Textfeld dar ==> 3 (stand zwar vorher schon drin, aber nicht als Zwischenergebnis, sondern als Eingangsgröße)
Anwender gibt 5 ins Textfeld der View ein.
Anwender drückt "+" der View --> Controller erhält "Nachricht", dass "-" gedrückt wurde.
Controller bemerkt, dass noch ein auszuführender Operator (+) im Model steht.
Controller liest Zwischenergebnis aus Model (3) und liest den Wert aus dem Textfeld (5) aus und führt darauf die Operation (+) aus ==> 8
Controller setzt das aktuelle Zwischenergebnis im Modell auf 8 und den auszuführenden Operator auf "-" --> Modell benachrichtigt View, dass allgemein, dass sich Werte geändert haben oder auch speziell welche Werte sich geändert haben.
View liest Zwischergebnis aus Model und stellt es im Textfeld dar ==> 8
...


----------



## Tomate_Salat (13. Aug 2012)

Imho interessant ist in diesem Zusammenhang auch das MVP-Pattern.

Hier agiert der Presenter so, wie du es wahrscheinlich vom Controller erwartet hättest. 







Ich präferiere das MVP. Also wenn das nicht gerade so eine "Schulaufgabe" o.ä. mit Vorgabe ist, würde ich dir empfehlen, darauf auch mal einen Blick zu werfen(zumal der Beitrag von mir dann nicht allzuviel OT war ).


----------



## ernst (13. Aug 2012)

Michael... hat gesagt.:


> Ein Textfeld ist Bestandteil der View.
> 
> Bei einem einfachen Taschenrechner macht es eigentlich keinen Sinn mit einem Model zu arbeiten. Das einzige Datum, welches das Model halten und verwalten könnte wäre das aktuelle Zwischenergebnis evtl. die nächste auszuführende Operation.
> Je nach Implementierung könnte das so aussehen:
> ...


Müsste es in der letzten Zeile nicht statt 
"Anwender drückt "+" der View --> Controller erhält "Nachricht", dass "-" gedrückt wurde."
besser heissen:
Anwender drückt "=" der View --> Controller erhält "Nachricht", dass "=" gedrückt wurde.

Warum + und - ??

mfg
Ernst


----------



## Landei (13. Aug 2012)

Tomate_Salat hat gesagt.:


> Imho interessant ist in diesem Zusammenhang auch das MVP-Pattern.
> 
> Hier agiert der Presenter so, wie du es wahrscheinlich vom Controller erwartet hättest.
> 
> ...



MOVE sieht auch interessant aus: http://cirw.in/blog/time-to-move-on


----------



## Michael... (14. Aug 2012)

ernst hat gesagt.:


> Müsste es in der letzten Zeile nicht statt
> "Anwender drückt "+" der View --> Controller erhält "Nachricht", dass "-" gedrückt wurde."
> besser heissen:
> Anwender drückt "=" der View --> Controller erhält "Nachricht", dass "=" gedrückt wurde.
> ...


Sorry, Copy&Paste Fehler sollte natürlich "-" und "-" heißen, aber kann genauso "=" und "=", "+" und "+"... heißen...


----------



## H4rr1s (14. Aug 2012)

Es gibt verschiedene "Interpretationen" von MVC.

Ich verwende meist folgenden:

C kennt V ---- V aber weder C noch V

Erreicht man indem V seine Elemente über Getter-Methoden an C gibt und C die Events impl.

C kennt M ---- M aber werder V noch C

somit läuft die komplette Kommunikation über C. V und M können beliebig geändert werden ohne das der jeweilige Gegenpart betroffen ist.

C darf in diesem Fall auf gar keinen Fall als eine Klasse verstanden werden, sondern viel mehr als Sammelsurium aus Klassen und Hilfsklassen. Hier ist der Planungsaufwand am größten da C bei diesem Ansatz von Änderungen meistens betroffen ist und "wartbar" bleiben muss.

Grüße
H4rr1s


----------



## ernst (14. Aug 2012)

Michael... hat gesagt.:


> Sorry, Copy&Paste Fehler sollte natürlich "-" und "-" heißen, aber kann genauso "=" und "=", "+" und "+"... heißen...


Ok, habe versucht eure Infos zu  MVC  als einfaches Demoprogramm (Addition mit Zwischenspeicher) zu implementieren.
Ist das (siehe unten) so weit korrekt ?


```
/*
R O G R A M M B E S C H R E I B U N G
Dies ist ein Demo-Programm für MVC
I) Informationsfluß
 +-- CONTROLER --+
 |               |
 v               v 
VIEW --------> MODEL
 
Die Pfeile bedeuten Assoziationen. 
Nicht eingezeichnet sind die Events (in entgegengesetzter Richtung) 
von (siehe Wikipedia)
VIEW --> CONTROLER
MODEL --> VIEW 
 
II) 
Anwender gibt im Textfeld der View eine Zahl ein (z.B. 3) und
Anwender drückt ein Button der View (z.B. +)  
-->
Listener (Wanze) im Controler liest den Wert (also 3) im Textfeld aus 
und speichert das Zwischenergebnis im Model durch die Methde
setSpeicherwert() ab, also (3)
--> 
Das Model benachrichtigt die View über die Observer-Technik, daß Daten
verändert wurden.
-->
Die View gibt diesen Wert (also 3) durch die Methode update() 
im Textfeld aus.

Anwender gibt im Textfeld der View eine Zahl ein (z.B. 5) und
Anwender drückt ein Button der View (z.B. =)  
-->
Listener (Wanze) im Controler liest den Wert (also 5) im Textfeld aus 
und addiert im Model zum alten Zwischenergebnis (also 3) durch die Methde
addiereSpeicherwert(5) den neuen Wert dazu (also 3+5) und speichert dieses
Ergebnis im Model (speicherwert=8) ab.
--> 
Das Model benachrichtigt die View über die Observer-Technik, daß Daten
verändert wurden.
-->
Die View gibt diesen Wert (also 8) durch die Methode update() 
im Textfeld aus.
*/
package taschenrechnermvc60;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;
import javax.swing.*;

public class MainTaschenrechnerMVC60 {

    public static void main(String[] args) {
        TRController trController = new TRController();
        trController.getTRView().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}
/*
TRModel wird überwacht, deswegen muß es von der Klasse Observable
erben. Durch die Anweisungen:
setChanged();
notifyObservers();        
in einer Methode f(), wirft eine überwachte Klasse ein spezielles 
Objekt, das von der Methode update einer überwachenden Klasse
eingefangen wird. 
*/  
class TRModel extends Observable {
    private double speicherwert;

    public TRModel() {
        speicherwert=0;
    }
    
    public double getSpeicherwert(){
        return speicherwert;
    }

    public void setSpeicherwert(double wert){
        speicherwert=wert;
        setChanged();
        notifyObservers();        
    }

    public void addiereDazu(double wert) {
        speicherwert=speicherwert+wert;
        setChanged();
        notifyObservers();        
    }
}

/*
TRView ist eine überwachende Klasse. Deswegen muß sie die 
Schnittstelle Observer implementieren und unbedingt die Methode
update() ausprogrammieren. 
update() wird immer dann aufgerufen, wenn sich in einer überwachten
Klasse etwas ändert (dies muß durch die Anweisungen setchanged()
und notifyObservers() vorbereitet werden).        
*/  

class TRView extends JFrame implements Observer {
    private TRModel trModel;
    // Stelle in MyFenster deklarieren, an die montiert wird.
    private Container mycont;
    // Buttons deklarieren
    private JButton mybtPlus;
    private JButton mybtGleich;    
    // Textfelder deklarieren
    private JTextField mytfZahl;
    // Eine Zeichenfläche deklarieren
    private JPanel myp;
    private GridLayout myGL13;

    // Konstruktor
    public TRView(TRModel m){
        trModel = m;
        // Überwachung
        this.trModel.addObserver(this);
        // Liefert die Stelle in MyFenster, an die montiert wird.
        mycont = getContentPane();
        // Erzeugt jeweils ein Button
        mybtPlus = new JButton("+");
        mybtGleich = new JButton("=");        
        // Erzeugt jeweils ein einzeiliges Textfeld mit dem vorgegebenen
        // Text und der vorgegebenen Spaltenzahl. Dieser Text kann 
        // (im Gegensatz zu einem Label) editiert werden
        mytfZahl = new JTextField("hier Zahl eingeben", 30);
        // Erzeugt eine Zeichenfläche
        myp = new JPanel();
        // Erzeugt ein Layout
        myGL13 = new GridLayout(1, 3);
        // Ordnet das Layout der Zeichenfläche (Panel) myp zu
        // ("formatiert" die Zeichenfläche damit)
        myp.setLayout(myGL13);
        // Montiert die grafischen Komponenten in die Zeichenfläche
        myp.add(mytfZahl);
        myp.add(mybtPlus);
        myp.add(mybtGleich);        
        // Montiert die Zeichenfläche in das Fenster MyFenster
        mycont.add(myp);
        // Fensterüberschrift festlegen
        setTitle("Einfaches MVC");
        // Koordinaten des linken, oberen Ecks des Fensters festlegen
        // Koordinate x = 30, Koordinate y = 60.		
        setLocation(30, 60);
        // Die Breite des Fensters in x-Richtung = 600
        // Die Breite des Fensters in y-Richtung = 400		
        setSize(600, 400);
        // Macht das Fenster sichtbar
        setVisible(true);
    }

    public String getJTextField() {
        return mytfZahl.getText();
    }

    public void setJTextField(String str) {
        this.mytfZahl.setText(str);
    }
    
    public void setAdditionsListener(ActionListener l) {
        mybtPlus.addActionListener(l);
    }
  
    public void setGleichListener(ActionListener l) {
        mybtGleich.addActionListener(l);
    }
    
    public void update(Observable m, Object o) {
        if (m == trModel) {
            setJTextField(String.valueOf(trModel.getSpeicherwert()));            
        }
    }
}

class TRController {
    private TRView trView;
    private TRModel trModel;

    public TRController() {
        trModel = new TRModel();
        trView = new TRView(trModel);        
        addListener();
    }

    public TRView getTRView() {
        return trView;
    }

/*    
    public void addListener() {
        trView.setAdditionsListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                double wert = Double.valueOf(trView.getJTextField());
                trModel.setSpeicherwert(wert);                
            }
        });

        trView.setGleichListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                double wert = Double.valueOf(trView.getJTextField());
                trModel.addiereDazu(wert);                
            }
        });
    }
  */  
    public void addListener() {
        AdditionsListener al;
        GleichListener gl;
        al = new AdditionsListener(trView, trModel);
        gl = new GleichListener(trView, trModel);        
        trView.setAdditionsListener(al);
        trView.setGleichListener(gl);        
    }
}

class AdditionsListener implements ActionListener{
    private TRView trView;
    private TRModel trModel;
    
    public AdditionsListener(TRView ptrView, TRModel ptrModel){
        trView = ptrView;
        trModel = ptrModel;
    }
    
    public void actionPerformed(ActionEvent e){
        double wert = Double.valueOf(trView.getJTextField());
        trModel.setSpeicherwert(wert);                
    }
}


class GleichListener implements ActionListener{
    //trView.setAdditionsListener(new ActionListener() {
    private TRView trView;
    private TRModel trModel;
    
    public GleichListener(TRView ptrView, TRModel ptrModel){
        trView = ptrView;
        trModel = ptrModel;
    }
    
    public void actionPerformed(ActionEvent e){
        double wert = Double.valueOf(trView.getJTextField());
        trModel.addiereDazu(wert);                
    }
}
```


----------



## Michael... (14. Aug 2012)

Sieht ganz gut aus. Würde sagen MVC sauber implementiert.

Wenn Du den Taschenrechner um weitere Rechenoperationen erweiterst. Musst Du halt die gewählte Operation irgendwo "speichern" (am besten im Model) und die Listener anpassen. z.B. ist eine Eingabe 3+4+5+6+7+8+9= aktuell auch nicht möglich bzw. würde nur 8+9=17 berechnet werden.


----------



## ernst (14. Aug 2012)

Michael... hat gesagt.:


> Sieht ganz gut aus. Würde sagen MVC sauber implementiert.
> 
> Wenn Du den Taschenrechner um weitere Rechenoperationen erweiterst. Musst Du halt die gewählte Operation irgendwo "speichern" (am besten im Model) und die Listener anpassen. z.B. ist eine Eingabe 3+4+5+6+7+8+9= aktuell auch nicht möglich bzw. würde nur 8+9=17 berechnet werden.



1)
Habe eine einfache Animation (Wagen bewegen von links nach rechts) mit MVC gemacht.
Ist das korrekt (siehe unten)

2)
MVC ist ein Entwurfsmuster. Das 3 Schichtenmodell doch auch.
Was ist der Unterschied bzw. in welchem Verhältnis stehen sie zueinander?
(Die unterschiedlichen Meinungen darüber im Internet  verwirren mich).

mfg
Ernst


```
/*
P R O G R A M M B E S C H R E I B U N G
Dies ist ein Demo-Programm für MVC (Animation)
I) Informationsfluß
 +-- CONTROLER --+
 |               |
 v               v 
VIEW --------> MODEL
 
Die Pfeile bedeuten Assoziationen. 
Nicht eingezeichnet sind die Events (in entgegengesetzter Richtung) 
von (siehe Wikipedia)
VIEW --> CONTROLER
MODEL --> VIEW 
 
II) 
Ein Wagen fährt immer wieder (ohne Einwirkung eines Anwenders) 
von links nach rechts

Ein Timer wirft immer wieder in regelmäßigen Zeitintervallen ein 
Objekt (ActionEvent), das mit der Methode actionPerformed() im Controler
eingefangen wird.
--> 
Mit der Methode updaten() in Model werden die Daten (Koordinaten) des 
Autos verändert. 
-->
Das Model benachrichtigt die View über die Observer-Technik, daß Daten
verändert wurden.
-->
Die View zeichnet das Auto neu und gibt es auf dem Bildschirm  aus.
*/

package wagenanimationmvc20;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;
import javax.swing.*;

public class MainWagenAnimationMVC20 {

    public static void main(String[] args){
        SpielController spielController = new SpielController();
        spielController.getSpielView().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

/*
TRModel wird überwacht, deswegen muß es von der Klasse Observable
erben. Durch die Anweisungen:
setChanged();
notifyObservers();        
in einer Methode f(), wirft eine überwachte Klasse ein spezielles 
Objekt, das von der Methode update einer überwachenden Klasse
eingefangen wird. 
*/  
class SpielModel extends Observable{
    private Wagen wagen;

    public Wagen getWagen(){
        return wagen;
    }
    
    public void updaten() {
        wagen.fahren();
        setChanged();
        notifyObservers();        
    }
    
    public SpielModel() {
        wagen=new Wagen();
    }
}

/*
TRView ist eine überwachende Klasse. Deswegen muß sie die 
Schnittstelle Observer implementieren und unbedingt die Methode
update() ausprogrammieren. 
update() wird immer dann aufgerufen, wenn sich in einer überwachten
Klasse etwas ändert (dies muß durch die Anweisungen setchanged()
und notifyObservers() vorbereitet werden).        
*/  
class SpielView extends javax.swing.JFrame implements Observer{
    private Container mycont;
    private SpielJPanel spielJPanel;
    private SpielModel spielModel;

  
    public SpielView(SpielModel spielModel) {
        this.spielModel = spielModel;
        // Überwachung: Es wird ein Überwacher (=Wanze, Detektiv) an
        // dem Objekt spielModell angebracht.
        this.spielModel.addObserver(this);
        mycont = getContentPane();                
        this.setSize(500,500);
        spielJPanel = new SpielJPanel();
        mycont.add(spielJPanel);
        this.setVisible(true);        
    }

    public SpielJPanel getSpielJPanel(){
        return spielJPanel;
    }
    
    public void setNewView(){
        Wagen w;
        w = spielModel.getWagen();
        spielJPanel.setX(w.getOrtX());        
        spielJPanel.setY(w.getOrtY());                
    }

    // Wenn sich im überwachten Modell Daten aändern, wird ein Event
    // ausgelöst (ein spezielles Objekt geworfen) das von der Methde
    // update() eingefangen wird. Diese Methode wird dann also aufgerufen
    public void update(Observable m, Object o) {
        if (m == spielModel) {
            setNewView();
            spielJPanel.repaint();
        }
    }
}

class SpielJPanel extends javax.swing.JPanel {
    // Daten für Methode paintComponent() ---
    private int x;
    private int y;

    public int getX(){
        return x;
    }
    
    public void setX(int x){
        this.x=x;
    }
    
    public int getY(){
        return y;
    }

    public void setY(int y){
        this.y=y;
    }
  
    public SpielJPanel() {
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.red);
        g.fillRect(x, y, 30, 25);
    }
}

class SpielController {

    private SpielView spielView;
    private SpielModel spielModel;
    private Timer timer;

    public SpielController() {
        spielModel = new SpielModel();        
        spielView = new SpielView(spielModel);
        timer = new Timer(2,
                new ActionListener() {
                    public void actionPerformed(ActionEvent ae) {
                        spielModel.updaten();
                    }
                });
        timer.start();

    }

    public SpielView getSpielView() {
        return spielView;
    }

}
```


----------



## javagirli (28. Aug 2012)

Hallo Ernst
Damit ich deinen Gedankengang ganz nachvollziehen kann, braucht es
(mindestens) noch die Klasse Wagen...;-)...
Kannst du uns diese noch bereitstellen?

mfg
javagirli


----------



## bERt0r (28. Aug 2012)

Hab mal so drüber geschaut, das einzige was mir komisch vorkommt ist setChanged(). Was ist das für eine Funktion und wo ist die definiert?


----------



## ernst (29. Aug 2012)

javagirli hat gesagt.:


> Hallo Ernst
> Damit ich deinen Gedankengang ganz nachvollziehen kann, braucht es
> (mindestens) noch die Klasse Wagen...;-)...
> Kannst du uns diese noch bereitstellen?
> ...



Unten befindet sich das gesamte lauffähige Programm, das ich noch etwas verbessert (strukturierter dargestellt)  habe

mfg
Ernst


```
package wagenanimationmvc11;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

class AnimationController {
    private AnimationView animationView;
    private AnimationModel animationModel;
    
    public AnimationController() {
        Timer timer;        
        animationModel = new AnimationModel();        
        animationView = new AnimationView(animationModel);
        TimerActionListener tal;
        tal=new TimerActionListener(animationModel);
        timer = new Timer(2,tal);
        timer.start();
    }
    
    public AnimationView getAnimationView() {
        return animationView;
    }
}

class TimerActionListener implements ActionListener {
    private AnimationModel animationModel;    

    public TimerActionListener(AnimationModel animationModel){
        this.animationModel=animationModel;
    }
    
    public void actionPerformed(ActionEvent ae) {
        animationModel.updaten();
    }
}
```



```
package wagenanimationmvc11;
import java.awt.Color;
import java.awt.Graphics;

class AnimationJPanel extends javax.swing.JPanel {
    private Wagen wagen;

    public void setWagen(Wagen wagen){
        this.wagen=wagen;
    }

    public AnimationJPanel(Wagen wagen) {
        this.wagen=wagen;
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.red);
        g.fillRect(wagen.getX(), wagen.getY(), 30, 25);                
    }
}
```



```
/*
AnimationModel wird überwacht, deswegen muß es von der Klasse Observable
erben. Durch die Anweisungen:
setChanged();
notifyObservers();        
in einer Methode f(), wirft eine überwachte Klasse ein spezielles 
Objekt, das von der Methode update einer überwachenden Klasse
eingefangen wird. 
*/  

package wagenanimationmvc11;

import java.util.Observable;

class AnimationModel extends Observable{
    private Wagen wagen;

    public Wagen getWagen(){
        return wagen;
    }
    
    public void updaten() {
        wagen.fahren();
        setChanged();
        notifyObservers();        
    }
    
    public AnimationModel() {
        wagen=new Wagen();
    }
}
```



```
package wagenanimationmvc11;
import java.awt.Container;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JFrame;

/*
AnimationView ist eine überwachende Klasse. Deswegen muß sie die 
Schnittstelle Observer implementieren und unbedingt die Methode
update() ausprogrammieren. 
update() wird immer dann aufgerufen, wenn sich in einer überwachten
Klasse etwas ändert (dies muß durch die Anweisungen setchanged()
und notifyObservers() vorbereitet werden).        
*/  
class AnimationView extends javax.swing.JFrame implements Observer{
    private AnimationJPanel animationJPanel;
    private AnimationModel animationModel;
    
    public AnimationView(AnimationModel animationModel) {
        Container mycont;        
        this.animationModel = animationModel;
        // Überwachung: Es wird ein Überwacher (= Wanze, Detektiv) an
        // dem Objekt animationModell angebracht.
        this.animationModel.addObserver(this);
        mycont = getContentPane();                
        this.setSize(500,500);
        animationJPanel = new AnimationJPanel(animationModel.getWagen());
        mycont.add(animationJPanel);
        this.setVisible(true);        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
    }
    
    public AnimationJPanel getAnimationJPanel(){
        return animationJPanel;
    }

    // Wenn sich im überwachten Modell Daten aändern, wird ein Event
    // ausgelöst (ein spezielles Objekt geworfen) das von der Methde
    // update() eingefangen wird. Diese Methode wird dann also aufgerufen
    public void update(Observable m, Object o) {
        if (m == animationModel) {
            animationJPanel.repaint();
        }
    }
}
```



```
/*
R O G R A M M B E S C H R E I B U N G
Dies ist ein Demo-Programm für MVC (Animation)
I) Informationsfluß
 +-- CONTROLER --+
 |               |
 v               v 
VIEW --------> MODEL
 
Die Pfeile bedeuten Assoziationen. 
Nicht eingezeichnet sind die Events (in entgegengesetzter Richtung) 
von (siehe Wikipedia)
VIEW --> CONTROLER
MODEL --> VIEW 
 
II) 
Ein Wagen fährt immer wieder (ohne Einwirkung eines Anwenders) 
von links nach rechts

Ein Timer wirft immer wieder in regelmäßigen Zeitintervallen ein 
Objekt (ActionEvent), das mit der Methode actionPerformed() im Controler
eingefangen wird.
--> 
Mit der Methode updaten() in Model werden die Daten (Koordinaten) des 
Autos verändert. 
-->
Das Model benachrichtigt die View über die Observer-Technik, daß Daten
verändert wurden.
-->
Die View zeichnet das Auto neu und gibt es auf dem Bildschirm  aus.
 
*/

package wagenanimationmvc11;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;
import javax.swing.*;

public class MainWagenAnimationMVC11 {
    public static void main(String[] args){
        AnimationController animationController = new AnimationController();
    }
}
```



```
package wagenanimationmvc11;

class Wagen{
    private int x;
    private int y;
    private int schritt;

    public Wagen(){
        x=0;
        y=0;
        schritt = 1;
    }

    public void setX(int pX){
        x = pX;
    }

    public int getX(){
        return x;
    }

    public void setY(int pY){
        y = pY;
    }

    public int getY(){
        return y;
    }


    void fahren(){
        if(x <= 400){
            x = x + schritt;
        }
        else{
            x=0;
        }
    }

    void setSchritt(int pSchritt){
        schritt = pSchritt;
    }
}
```


----------



## ernst (29. Aug 2012)

bERt0r hat gesagt.:


> Hab mal so drüber geschaut, das einzige was mir komisch vorkommt ist setChanged(). Was ist das für eine Funktion und wo ist die definiert?



1)
setChanged() ist eine Methode der Klasse Observable, die von der Entwicklungsumgebung
geliefert wird (stammt also nicht von mir).

2)
setChanged() setzt ein Änderungsflag und zeigt damit an, daß eine
Änderunge erfolgt ist.
Falls eine Änderung erfolgte, wird sie durch notifyObservers() 
übermittelt. 
Gibt es keine Änderung, dann übermittelt notifyObservers() auch nichts.

mfg
Ernst


----------



## bERt0r (29. Aug 2012)

-.- Klar, Observeable hab ich wohl schon ne Weile nicht mehr benutzt 
Was ich noch anmerken würde ist, dass du da vielleicht schon ein bisschen MVC Overkill gemacht hast. In meinen Augen wäre eigentlich der Wagen das Model, du siehst die Animation des Wagens als Model und das wirkt mMn nach ein bisschen komisch (der Code im AnimationModel ist ziemlich trivial weil du nochmal in die Klasse Wagen ausgelagert hast). Das ganze ist aber nicht weiter schlimm und wenn du deine Wagen Objekte auch anderweitig brauchst, wo sie nicht Observiert werden sollen geht das auch voll in Ordnung. Auf jeden Fall hast du's sauber aufgeteilt.


----------



## ernst (30. Aug 2012)

bERt0r hat gesagt.:


> -.- Klar, Observeable hab ich wohl schon ne Weile nicht mehr benutzt
> Was ich noch anmerken würde ist, dass du da vielleicht schon ein bisschen MVC Overkill gemacht hast. In meinen Augen wäre eigentlich der Wagen das Model, du siehst die Animation des Wagens als Model und das wirkt mMn nach ein bisschen komisch (der Code im AnimationModel ist ziemlich trivial weil du nochmal in die Klasse Wagen ausgelagert hast). Das ganze ist aber nicht weiter schlimm und wenn du deine Wagen Objekte auch anderweitig brauchst, wo sie nicht Observiert werden sollen geht das auch voll in Ordnung. Auf jeden Fall hast du's sauber aufgeteilt.



Das Programm soll später so erweitert werden, dass neben dem Wagen noch andere Fahrzeuge mit verschiedenen Geschwindigkeiten fahren können, wie z.B. LKW, Motorrad usw.
Dann kann Wagen nicht mehr das Modell sein.
Hätte dann meine Aufteilung einen Sinn ?


mfg
Ernst


----------



## Michael... (30. Aug 2012)

ernst hat gesagt.:


> Das Programm soll später so erweitert werden, dass neben dem Wagen noch andere Fahrzeuge mit verschiedenen Geschwindigkeiten fahren können, wie z.B. LKW, Motorrad usw.
> Dann kann Wagen nicht mehr das Modell sein.
> Hätte dann meine Aufteilung einen Sinn ?


Ja.


----------



## ernst (31. Aug 2012)

Michael... hat gesagt.:


> Ja.



Dank an alle

mfg
ERnst


----------

