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

ernst

Top Contributor
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



Java:
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...

Top Contributor
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.
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

Top Contributor
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...

Top Contributor
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

Top Contributor
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

Gesperrter Benutzer
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).
 
Zuletzt bearbeitet:

Michael...

Top Contributor
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
...
 
T

Tomate_Salat

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

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

300px-Model_View_Presenter.png


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 :D).
 

ernst

Top Contributor
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.
...
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

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

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

300px-Model_View_Presenter.png


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 :D).

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

Michael...

Top Contributor
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
Sorry, Copy&Paste Fehler sollte natürlich "-" und "-" heißen, aber kann genauso "=" und "=", "+" und "+"... heißen...
 

H4rr1s

Mitglied
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

Top Contributor
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 ?

Java:
/*
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...

Top Contributor
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

Top Contributor
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

Java:
/*
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

Neues Mitglied
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

Top Contributor
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

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

mfg
javagirli

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

mfg
Ernst

Java:
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();
    }
}


Java:
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);                
    }
}


Java:
/*
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();
    }
}


Java:
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();
        }
    }
}


Java:
/*
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();
    }
}


Java:
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

Top Contributor
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

Top Contributor
-.- 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

Top Contributor
-.- 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
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
F Einfaches Beispiel mit Netty Socket.IO Allgemeine Java-Themen 6
Gossi Threads Suche ein (einfaches) Beispiel Allgemeine Java-Themen 5
E Beispiel für ein möglichst einfaches Interface Allgemeine Java-Themen 22
V Ganz einfaches MVC-Beispiel?! Allgemeine Java-Themen 107
J Einfaches AspectJ Beispiel Allgemeine Java-Themen 2
reibi javax.crypto.SecretKey - Einfaches Beispiel gewünscht ;-) Allgemeine Java-Themen 2
temi Einfaches Eventhandling führt zu Brett vor Kopf Allgemeine Java-Themen 2
S Einfaches Programm programmieren Allgemeine Java-Themen 5
K Einfaches Array in 2 neue aufteilen. Allgemeine Java-Themen 2
A Lotto, einfaches Problem? Allgemeine Java-Themen 11
M einfaches Lagerverwaltungsapp Allgemeine Java-Themen 4
E Einfaches Problem mit Tomcat Allgemeine Java-Themen 18
D Einfaches Nutzen von Plugins mittels generischer Methode Allgemeine Java-Themen 3
W Einfaches Installer/setup tool für java programme das. Allgemeine Java-Themen 4
E (einfaches) Problem mit import und package (export) Allgemeine Java-Themen 4
T Einfaches Java Programm PHP5-fähig machen Allgemeine Java-Themen 19
V Suche einfaches JasperReports Tutorial Allgemeine Java-Themen 23
F Log4j2 SMTP Appender Beispiel Allgemeine Java-Themen 3
marcooooo Frage zum Beispiel im Anhang Allgemeine Java-Themen 16
O Suche größeres Beispiel für WebserverAnwendung mit Java Allgemeine Java-Themen 2
B MVC-Pattern größeres Beispiel Allgemeine Java-Themen 16
M Fabrik Methode, gutes Beispiel? Allgemeine Java-Themen 0
S Ist Java intrinsisch 'sicherer' als zum Beispiel C/C++ ? Allgemeine Java-Themen 2
D API - Beispiel + static member in inner (non static) class Allgemeine Java-Themen 2
Hotkey Beispiel für grosse Java Projekte Allgemeine Java-Themen 9
hdi Beispiel für EDT Violations gesucht Allgemeine Java-Themen 4
hdi Probleme mit Deadlock-Beispiel Allgemeine Java-Themen 11
W Frage zu Vererbung / konkretes Beispiel Allgemeine Java-Themen 4
M Frage zu Interfaces (Beispiel: Comparable) Allgemeine Java-Themen 13
E Exmatrikulations-Beispiel Allgemeine Java-Themen 8
G multithreading, concurrency conveyor belt beispiel Allgemeine Java-Themen 2
T Prototyp Beispiel Allgemeine Java-Themen 12
J Threads, Doppelpufferung --> Beispiel gefunden, geht net Allgemeine Java-Themen 16
F Installer für Windows schreiben! Hat jemand ein Beispiel? Allgemeine Java-Themen 8
K Brauche euren Lösungsweg zu einem File/IO-Beispiel Allgemeine Java-Themen 23
E Servlet-Beispiel gesucht Allgemeine Java-Themen 3
G Public oder Private oder Protected Sinn Allgemeine Java-Themen 14
A Best Practice Wie viele Referenzen machen Sinn? Weniger ist mehr? Allgemeine Java-Themen 1
T Sinn einer toString Methode Allgemeine Java-Themen 3
M Sinn von Kompilierung zur Laufzeit Allgemeine Java-Themen 3
M Sinn von Threads? Allgemeine Java-Themen 1
Thallius Macht das Sinn? Allgemeine Java-Themen 30
A Methoden Der Sinn von system.out.print(); Allgemeine Java-Themen 9
E Serialisierung - Sinn einer generierten serialVersionUID? Allgemeine Java-Themen 4
M Generics (bounded wildcards statt Interface Bezeichnern) -- Sinn oder Unsinn? Allgemeine Java-Themen 2
F Sinn des Serializable Interfaces Allgemeine Java-Themen 8
S Konstrukt Sinn, Zewck und Name Allgemeine Java-Themen 6
N Für welche Art von Berechnungen macht JCUDA Sinn? Allgemeine Java-Themen 12
M Sinn von XML in Java Allgemeine Java-Themen 10
A Was ist der genau Sinn eines Interface? Allgemeine Java-Themen 13
H Was ist der genau Sinn von tString()? Allgemeine Java-Themen 3

Ähnliche Java Themen

Neue Themen


Oben