Logo des digitalen Schulbuchs inf-schule.de. Schriftzug in Zustandsübergangsdiagramm eines endlichen Automaten.

Model-View-Control-Architektur

Weitere Aufteilung von Zuständigkeiten

In der Datenmodell-GUI-Architektur ist das GUI-Objekt sowohl für die Präsentation der Daten auf der Benutzeroberfläche als auch für die Ereignisverarbeitung zuständig.

Diese beiden Zuständigkeiten sollen jetzt aufgeteilt werden: Einerseits soll es Präsentationsobjekte geben, die nur für die Darstellung der Daten zuständig sind, andererseits ein Steuerungsobjekt, das die Verbindungen zwischen Präsentationsobjekten und Datenmodellobjekten herstellt und die Ereignisverarbeitung festlegt. Diese weitere Aufteilung der Zuständigkeiten soll spätere Änderungen oder Erweiterungen des Softwaresystems erleichtern und eine Wiederverwendbarkeit einzelnen Komponenten ermöglichen.

Grafische Benutzeroberfläche

Wir betrachten hier noch einmal die folgende einfache grafische Benutzeroberfläche:

GUI

Das Programm zu dieser grafischen Benutzeroberfläche kann auch aus den folgenden Softwarebausteinen zusammengesetzt werden.

Datenmodell (model)

Das Datenmodell bleibt unverändert.

#------------------------------------------------------------------------------
# Datenmodell
#------------------------------------------------------------------------------

class Ampel(object):
    
    def __init__(self, anfangszustand):
        self.zustand = anfangszustand

    def setZustand(self, z):
        self.zustand = z

    def getZustand(self):
        return self.zustand

    def schalten(self):
        if self.zustand == 'rot':
            self.zustand = 'rotgelb'
        elif self.zustand == 'rotgelb':
            self.zustand = 'gruen'
        elif self.zustand == 'gruen':
            self.zustand = 'gelb'
        elif self.zustand == 'gelb':
            self.zustand = 'rot'

    def getLampen(self):
        if self.zustand == 'rot':
            lampen = (True, False, False)
        elif self.zustand == 'rotgelb':
            lampen = (True, True, False)
        elif self.zustand == 'gruen':
            lampen = (False, False, True)
        elif self.zustand == 'gelb':
            lampen = (False, True, False)
        return lampen

Präsentation (view)

Aufgabe eines GUI-Objekts ist es, die grafische Benutzeroberfläche zu erzeugen.

#------------------------------------------------------------------------------
# GUI
#------------------------------------------------------------------------------

from tkinter import *

# Farben
grau     = '#404040'
rotAn    = '#FF0000'
rotAus   = '#550000'
gelbAn   = '#FFFF00'
gelbAus  = '#555500'
gruenAn  = '#00FF00'
gruenAus = '#005500'

class GUI(object):
    def __init__(self, cbEreigninsverarbeitung):
        # Referenzattribute zum Datenmodell
        self.cbWeiterClick = cbEreigninsverarbeitung[0]
        # Erzeugung des Fensters
        self.fenster = Tk()
        self.fenster.title("Ampel")
        self.fenster.geometry("400x300")
        # Zeichenfläche
        self.canvas = Canvas(master=self.fenster)
        self.canvas.place(x=0, y=0, width=400, height=300)
        # Hintergrundbild
        self.hintergrundbild = PhotoImage(file="hintergrund.gif")
        self.canvas.create_image(0, 0, image=self.hintergrundbild, anchor=NW)
        # Ampelanzeige
        # Ampelkasten
        self.canvas.create_rectangle(250, 120, 262, 152, fill=grau)
        # Rot-Licht
        self.id_rot = self.canvas.create_oval(252, 122, 260, 130, fill=grau)
        # Gelb-Licht
        self.id_gelb = self.canvas.create_oval(252, 132, 260, 140, fill=grau)
        # Grün-Licht
        self.id_gruen = self.canvas.create_oval(252, 142, 260, 150, fill=grau)
        # Stange
        self.canvas.create_rectangle(255, 152, 257, 184, fill=grau)
              
        # Button zum Auswerten
        self.buttonWeiter = Button(master=self.fenster,
                                   text="weiter",
                                   command=self.cbWeiterClick)
        self.buttonWeiter.place(x=150, y=270, width=100, height=20)

Beachte, dass ein GUI-Objekt keinen Zugriff auf Datenmodell-Objekte hat. Das ist deshalb möglich, weil hier keine Ereignisverarbeitungsmethoden implementiert sind. Die für die Verarbeitung der Ereignisse erforderlichen Ereignisverarbeitungsmethoden werden dem GUI-Objekt übergeben. Hier wird ein Mechanismus benutzt, den man Callback-Funktion nennt. Es werden Zeiger auf an anderer Stelle festgelegte Funktionsdefinitionen übergeben.

Steuerung (control)

Aufgabe eines Controller-Objekts ist es, die Datenmodell- und GUI-Objekte zu erzeugen und zu verknüpfen.

Beachte, dass ein Controller-Objekt Zugriff auf Datenmodell- und Präsentationsobjekte hat. Beachte auch, dass ein Controller-Objekt die Ereignisverarbeitungsmethoden implementiert, die dem GUI-Objekt bei seiner Erzeugung übergeben werden.

#-----------------------------------------------------------
# Controller
#-----------------------------------------------------------

from ampel import *
from gui_ampel import *

class Controller(object):

    def __init__(self):
        # Erzeugung der Datenmodell-Objekte
        self.ampel = Ampel('rot')
        # Erzeugung und Initialisierung der GUI
        ereignisverarbeitung = [self.weiterClick,]
        self.gui = GUI(ereignisverarbeitung)
        # Initialisierung von Ausgaben
        self.anzeigeAktualisieren()
        # Ereignisschreife
        self.gui.fenster.mainloop()

    def weiterClick(self):
        self.ampel.schalten()
        self.anzeigeAktualisieren()
                    
    def anzeigeAktualisieren(self):
        (lampeRot, lampeGelb, lampeGruen) = self.ampel.getLampen()
        if lampeRot:
            self.gui.canvas.itemconfigure(self.gui.id_rot, fill=rotAn)
        else:
            self.gui.canvas.itemconfigure(self.gui.id_rot, fill=rotAus)
        if lampeGelb:
            self.gui.canvas.itemconfigure(self.gui.id_gelb, fill=gelbAn)
        else:
            self.gui.canvas.itemconfigure(self.gui.id_gelb, fill=gelbAus)
        if lampeGruen:
            self.gui.canvas.itemconfigure(self.gui.id_gruen, fill=gruenAn)
        else:
            self.gui.canvas.itemconfigure(self.gui.id_gruen, fill=gruenAus)

# Erzeugung des Controllers
controller = Controller()

MVC-Architektur

Das folgende Klassendiagramm verdeutlicht noch einmal die Beziehungen zwischen den Komponenten Datenmodell (Model), Präsentation (View) und Steuerung (Control).

Klassendiagramm

Vereinfacht lässt sich die MVC-Architektur wie folgt darstellen.

Klassendiagramm

Hier erfolgt eine strikte Trennung des Datenmodells (Model) von der grafischen Präsentation (View). Die Komponenten Model und View wissen nichts voneinander. Die notwendigen Verbindungen werden von einer dritten Komponente, dem Controller, ausgeführt. Der Controller braucht dazu eine präzise Beschreibung der Schnittstellen von Model und View.

Hinweis

Die hier gezeigte Darstellung der MVC-Architektur orientiert sich sehr stark an den Ausführungen auf den Seiten des HSG.

X

Fehler melden

X

Suche