Datenmodell-GUI-Architektur

Grafische Benutzeroberfläche für einen Kartenstapel

Ziel ist es, eine einfache grafische Benutzeroberfläche zu erzeugen, von der aus ein Objekt der Klasse Ampel aktiviert werden kann.

Grafische Benutzeroberfläche

Zur Verwaltung einer Ampel benutzen wir die bereits entwickelte Klasse Ampel aus der Datei ampel.py.

Verwendung von GUI-Objekten

Der folgende Quelltext zeigt, wie man eine grafische Benutzeroberfläche zur Anzeige einer Ampel mit Hilfe von tkinter-Objekten erzeugen kann.

#------------------------------------------------------------------------------
# Erzeugung des Datenmodell-Objekts
#------------------------------------------------------------------------------

from ampel import Ampel
ampel = Ampel('rot')

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

from tkinter import *

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

# Ereignisverarbeitung
def buttonWeiterClick():
    # Verarbeitung der Daten
    ampel.schalten()
    # Aktualisierung der Anzeige
    (lampeRot, lampeGelb, lampeGruen) = ampel.getLampen()
    if lampeRot:
        canvas.itemconfigure(id_rot, fill=rotAn)
    else:
        canvas.itemconfigure(id_rot, fill=rotAus)
    if lampeGelb:
        canvas.itemconfigure(id_gelb, fill=gelbAn)
    else:
        canvas.itemconfigure(id_gelb, fill=gelbAus)
    if lampeGruen:
        canvas.itemconfigure(id_gruen, fill=gruenAn)
    else:
        canvas.itemconfigure(id_gruen, fill=gruenAus)

# Erzeugung des Fensters
fenster = Tk()
fenster.title("Ampel")
fenster.geometry("400x300")
# Zeichenfläche
canvas = Canvas(master=fenster)
canvas.place(x=0, y=0, width=400, height=300)
# Hintergrundbild
hintergrundbild = PhotoImage(file="hintergrund.gif")
canvas.create_image(0, 0, image=hintergrundbild, anchor=NW)
# Ampelanzeige
# Ampelkasten
canvas.create_rectangle(250, 120, 262, 152, fill=grau)
# Rot-Licht
id_rot = canvas.create_oval(252, 122, 260, 130, fill=grau)
# Gelb-Licht
id_gelb = canvas.create_oval(252, 132, 260, 140, fill=grau)
# Grün-Licht
id_gruen = canvas.create_oval(252, 142, 260, 150, fill=grau)
# Stange
canvas.create_rectangle(255, 152, 257, 184, fill=grau)
# Aktualisierung der Anzeige
(lampeRot, lampeGelb, lampeGruen) = ampel.getLampen()
if lampeRot:
    canvas.itemconfigure(id_rot, fill=rotAn)
else:
    canvas.itemconfigure(id_rot, fill=rotAus)
if lampeGelb:
    canvas.itemconfigure(id_gelb, fill=gelbAn)
else:
    canvas.itemconfigure(id_gelb, fill=gelbAus)
if lampeGruen:
    canvas.itemconfigure(id_gruen, fill=gruenAn)
else:
    canvas.itemconfigure(id_gruen, fill=gruenAus)        
# Button zum Weiterschalten
buttonWeiter = Button(master=fenster,
                           text="weiter",
                           command=buttonWeiterClick)
buttonWeiter.place(x=150, y=270, width=100, height=20)
# Ereignisschleife starten
fenster.mainloop()

Aufgabe 1

(a) Teste zunächst das GUI-Programm. Beachte, dass du hierzu ein Hintergrundbild in einer Datei hintergrund.gif vorliegen muss.

(b) Welche Objekte werden hier zur Realisierung der grafischen Benutzeroberfläche erzeugt und benutzt?

Eine Klasse zur Beschreibung der GUI

Zur Strukturierung des Programms ist es günstig, die grafische Benutzeroberfläche mit Hilfe einer Klasse GUI zu realisieren. Aufgabe eines Objektes der Klasse GUI ist es, sämtliche tkinter-Objekte zu verwalten, die zur Erzeugung der GUI benötigt werden. Zudem soll ein Objekt der Klasse GUI die Ereignisverarbeitung übernehmen.

#------------------------------------------------------------------------------
# Import des Datenmodells
#------------------------------------------------------------------------------

from ampel import Ampel

#------------------------------------------------------------------------------
# GUI-Klasse
#------------------------------------------------------------------------------

from tkinter import *

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

class GUI(object):
    def __init__(self, datenmodell):
        # Referenzattribute zum Datenmodell
        self.ampel = datenmodell[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)
        # Aktualisierung der Anzeige
        self.anzeigeAktualisieren()
        # Button zum Weiterschalten
        self.buttonWeiter = Button(master=self.fenster,
                                   text="weiter",
                                   command=self.buttonWeiterClick)
        self.buttonWeiter.place(x=150, y=270, width=100, height=20)

    def buttonWeiterClick(self):
        # Verarbeitung der Daten
        self.ampel.schalten()
        # Aktualisierung der Anzeige
        self.anzeigeAktualisieren()

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

#------------------------------------------------------------------------------
# Erzeugung der Objekte
#------------------------------------------------------------------------------

ampel = Ampel('rot')
datenmodell = [ampel]
gui = GUI(datenmodell)
gui.fenster.mainloop()

Aufgabe 2

(a) Teste zunächst das Programm (mit einem eigenen Hintergrundbild oder auch ohne Hintergrundbild). Mache dich anschließend mit dem Quelltext vertraut. Analysiere insbesondere die Ereignisverarbeitungsprozedur.

(b) Ergänze das Programm so, dass zwei Ampeln simuliert werden.

Aufgabe 3

In dieser Aufgabe geht es um die Objektstruktur des Software-Systems (mit GUI-Klasse).

(a) Begründe anhand des Quelltextes, dass u.a. folgende Objekte am Gesamtsystem beteiligt sind:

Objektdiagramm

(b) Erkläre mit Hilfe des Quelltextes das folgende Klassendiagramm zum Software-System.

Klassendiagramm

(c) Das Software-System benutzt eine 2-Schichten-Architektur: Die obere Schicht ist für die GUI zuständig, die untere für das Datenmodell. Warum ist es günstig, wenn in der unteren Schicht (d.h. im Datenmodell) keine Bezüge auf die obere Schicht (d.h. die GUI) genommen werden?

Zwei-Schichten_Architektur
X

Fehler melden

X

Suche