Einstieg - Grafische Benutzeroberflächen zur Roboterwelt

Grafische Darstellung der Roboterwelt

Mit Hilfe einer grafischen Benutzeroberfläche (GUI) soll das System zur Simulation eines Roboters benutzerfreundlich gestaltet werden. Ziel ist es, eine Roboterwelt wie die folgende

GUI zur Roboterwelt

grafisch so darzustellen.

GUI zur Roboterwelt

Da es nicht so einfach ist, eine solche Benutzeroberfläche zu entwickeln, werden wir hier schrittweise vorgehen.

Textuelle Darstellung des Roboters

Ziel ist es, zunächst eine sehr einfache grafische Benutzeroberfläche zur Steuerung des Roboters zu entwickeln.

GUI zur Roboterwelt

Der Roboter wird mit Hilfe von drei Schaltflächen gesteuert. Die jeweilge Position des Roboters wird auf einem Schriftfeld textuell dargestellt.

Wir gehen davon aus, dass das Datenmodell in der Datei roboterwelt.txt (die man in roboterwelt.py umbenennen sollte) deklariert ist und eine Basisversion der Klasse Roboter enthält.

Das folgende Programm erzeugt (in Teilen) die oben gezeigte grafische Benutzeroberfläche:

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

from roboterwelt import *

welt = Welt(5, 5)
rob = Roboter()
rob.setWelt(welt)

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

from tkinter import *

def buttonSchrittClick():
    rob.schritt()
    labelAusgabe.config(text=str(rob.getZustand()))
        
# Erzeugung des Fensters
fenster = Tk()
fenster.title("Roboterwelt")
fenster.geometry('330x330')
# Rahmen 
rahmenRoboter = Frame(master=fenster, background="gray")
rahmenRoboter.place(x=5, y=5, width=320, height=320)
# Label
labelAusgabe = Label(master=rahmenRoboter, background="white",
                     text=str(rob.getZustand()))
labelAusgabe.place(x=78, y=18, width=164, height=164)      
# Button schritt
buttonSchritt = Button(master=rahmenRoboter, text="schritt",
                       command=buttonSchrittClick)
buttonSchritt.place(x=110, y=200, width=100, height=27)
# Aktivierung der Ereignisschleife
fenster.mainloop()

Aufgabe 1

Analysiere und teste das Programm. Ergänze die fehlenden Teile (Schaltflächen zum Links- und Rechtsdrehen).

Aufgabe 2

(a) Wie viele Objekte werden im Programm oben erzeugt? Verdeutliche die Situation mit einem Objektdiagramm.

(b) Das Programm ist (auch optisch) in zwei Bereiche aufgeteilt: Datenmodell- und GUI-Bereich. Welche Aufgaben erfüllen das Objekt im Datenmodellbereich, welche die im GUI-Bereich?

Ein Objekt zur Verwaltung der GUI-Komponenten

Das bisher betrachtete Programm zu der oben gezeigten grafischen Benutzeroberfläche hat folgende Objekt-Struktur:

...
#--------------------------------------------------------------
# Datenmodell
#--------------------------------------------------------------
...
welt = Welt(5, 5)
rob = Roboter()
rob.setWelt(welt)
#--------------------------------------------------------------
# GUI
#--------------------------------------------------------------
...
# Erzeugung des Fensters
fenster = Tk()
...
# Label
labelAusgabe = Label(master=rahmenRoboter, background="white",
                     text=str(rob.getZustand()))
... 
# Button schritt
buttonSchritt = Button(master=rahmenRoboter, text="schritt",
                       command=buttonSchrittClick)
...

Mit einem Objektdiagramm lässt sich diese Struktur so darstellen:

OD zur Roboterwelt

Neben den Datenmodell-Objekten gibt es eine Vielzahl von Objekten zur Verwaltung der GUI-Komponenten.

Die Objekte zur Verwaltung der GUI-Komponenten sollen künftig von einem Manager-Objekt gui erzeugt und verwaltet werden. Dieses Manager-Objekt gui soll zudem Zugriff auf die Datenmodell-Objekte haben.

Das folgende Objektdiagramm verdeutlicht die gewünschte Struktur:

OD zur Roboterwelt

Diese Struktur wird von dem folgenden Programm erzeugt:

from tkinter import *
from roboterwelt import *

class Gui(object):

    def __init__(self, rob, welt):
        # Referenzattribute zum Datenmodell
        self.rob = rob
        self.welt = welt
        # Erzeugung des Fensters
        self.fenster = Tk()
        self.fenster.title("Roboterwelt")
        self.fenster.geometry('330x330')
        # Rahmen 
        self.rahmenRoboter = Frame(master=self.fenster, background="gray")
        self.rahmenRoboter.place(x=5, y=5, width=320, height=320)
        # Label
        self.labelAusgabe = Label(master=self.rahmenRoboter, background="white",
                                  text=str(self.rob.getZustand()))
        self.labelAusgabe.place(x=78, y=18, width=164, height=164)
        # Button links
        self.buttonLinks = Button(master=self.rahmenRoboter, text="links",
                                  command=self.buttonLinksClick)
        self.buttonLinks.place(x=5, y=200, width=100, height=27)
        # Button schritt
        self.buttonSchritt = Button(master=self.rahmenRoboter, text="schritt",
                                    command=self.buttonSchrittClick)
        self.buttonSchritt.place(x=110, y=200, width=100, height=27)
        # Button rechts
        self.buttonRechts = Button(master=self.rahmenRoboter, text="rechts",
                                   command=self.buttonRechtsClick)
        self.buttonRechts.place(x=215, y=200, width=100, height=27)
        # Ereignisschreife
        self.fenster.mainloop()        

    def buttonSchrittClick(self):
        self.rob.schritt()
        self.labelAusgabe.config(text=str(self.rob.getZustand()))
            
    def buttonLinksClick(self):
        self.rob.links()
        self.labelAusgabe.config(text=str(self.rob.getZustand()))
             
    def buttonRechtsClick(self):
        self.rob.rechts()
        self.labelAusgabe.config(text=str(self.rob.getZustand()))

# Erzeugung der Datenmodell-Objekte
welt = Welt(5, 5)
rob = Roboter()
rob.setWelt(welt)
# Erzeugung des Gui-Objekts
gui = Gui(rob, welt)

Aufgabe 3

Teste und analysiere das Programm.

Aufgabe 4

Zeichne ein Klassendiagramm zum gezeigten Programm. Berücksichtige hierbei, welche Objektbeziehungen kennt-Beziehungen bzw. hat-Beziehungen sind.

Von der textuellen Ausgabe zur grafischen Darstellung

Die textuelle Ausgabe des Roboterzustands soll durch eine grafische Darstellung der Roboterwelt ersetzt werden:

GUI zur Roboterwelt

Die Bausteine zur Erstellung der Grafiken werden hier bereitgestellt.

Das bisher entwickelte Programm mit einer textuellen Ausgabe des Roboterzustands hat folgende Klassen-Struktur:

KD zur Roboterwelt

Ein Gui-Objekt hat die volle Kontrolle über die Objekte zur Verwaltung der GUI-Komponenten, u. a. also auch über ein Label-Objekt, das für die Ausgabe der Roboterdaten zuständig ist.

Um aus einer textuellen Ausgabe eine grafische Darstellung zu erhalten, wird zunächst das Label-Objekt gegen ein Canvas-Objekt ausgetauscht:

KD zur Roboterwelt

Zudem werden Hilfsoperationen erzeugeWeltGrafik, erzeugeRoboterGrafik, aktualisiereWeltGrafik und aktualisiereRoboterGrafik zur Erzeugung und Aktualisierung der jeweiligen grafischen Darstellung der Roboterwelt deklariert.

Die Struktur des Programms ist im folgenden Quelltextauszug zu sehen:

from tkinter import *
from roboterwelt import *

#---------------------------------------------------------------------------------

class Gui(object):

    def __init__(self, rob, welt):
        # Referenzattribute zum Datenmodell
        self.rob = rob
        self.welt = welt
        # Erzeugung des Fensters
        self.fenster = Tk()
        self.fenster.title("Roboterwelt")
        self.fenster.geometry('330x330')
        # Rahmen 
        self.rahmenRoboter = Frame(master=self.fenster, background="gray")
        self.rahmenRoboter.place(x=5, y=5, width=320, height=320)
        # Canvas
        self.canvas = Canvas(master=self.rahmenRoboter, background="white",
                             width=164, height=164)
        self.canvas.place(x=78, y=18)
        self.erzeugeWeltGrafik()
        self.erzeugeRoboterGrafik()
        # Button schritt
        self.buttonSchritt = Button(master=self.rahmenRoboter, text="schritt",
                                    command=self.buttonSchrittClick)
        self.buttonSchritt.place(x=110, y=200, width=100, height=27)
        ...
        # Button Marke setzen
        self.buttonMarkeSetzen = Button(master=self.rahmenRoboter,
                                        text="Marke setzen",
                                        command=self.buttonMarkeSetzenClick)
        self.buttonMarkeSetzen.place(x=5, y=240, width=100, height=27)
        ...
        # Ereignisschreife
        self.fenster.mainloop()        

    def erzeugeWeltGrafik(self):
        ...

    def erzeugeRoboterGrafik(self):
        ...

    def aktualisiereWeltGrafik(self):        
        ...

    def aktualisiereRoboterGrafik(self):
        ...
        
    def buttonSchrittClick(self):
        self.rob.schritt()
        self.aktualisiereRoboterGrafik()
    ...        
    def buttonMarkeSetzenClick(self):
        self.rob.markeSetzen()
        self.aktualisiereWeltGrafik()
        self.aktualisiereRoboterGrafik()
    ...

# Erzeugung der Datenmodell-Objekte
welt = Welt(5, 5)
rob = Roboter()
rob.setWelt(welt)
# Erzeugung des Gui-Objekts
gui = Gui(rob, welt)

Aufgabe 5

(a) Lade die Dateien roboterwelt.txt und gui_roboterwelt.txt herunter und ändere die Dateiendungen. Teste das gesamte Programm.

(b) Vergleiche das Programm zur Erzeugung der grafischen Benutzeroberfläche mit grafischer Darstellung der Roboterwelt mit dem entsprechenden Programm, bei dem eine textuelle Ausgabe des Roboterzustands erfolgt. An welchen Stellen sind Änderungen vorgenommen worden?

X

Fehler melden

X

Suche