Datenmodell-GUI-Architektur
Grafische Benutzeroberfläche für eine Ampel
Ziel ist es, eine einfache grafische Benutzeroberfläche zu erzeugen, von der aus ein Objekt der
Klasse Ampel
aktiviert werden kann.
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) = self.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:
(b) Erkläre mit Hilfe des Quelltextes das folgende Klassendiagramm zum Software-System.
(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?