Upload
hartwin-bortner
View
107
Download
2
Embed Size (px)
Citation preview
Grafische Benutzeroberflächen
Klaus Becker
2009
2 Grafische Benutzeroberflächen
Inhalte: Benutzerfreundlichkeit Aufbau und Verhalten GUI-Entwicklung (mit Tkinter) GUI-Objekte und Datenmodell-Objekte GUI-Entwicklung mit Werkzeugen
3 Teil 1
Benutzerfreundlichkeit
4 Einstieg - Anhalteweg eines AutosReaktionsweg = (Geschwindigkeit [in km/h] / 10) * 3
Bremsweg = (Geschwindigkeit [in km/h] / 10)2
Anhalteweg = Reaktionsweg + Bremsweg
textbasierte, synchronisierte
Benutzeroberfläche
multimediale, asynchrone Benutzeroberfläche
5 Fachkonzept - Software-Ergonomie
Die Software-Ergonomie befasst sich mit der Gestaltung benutzerfreundlicher Computer-Programme. Ziel ist es, die Zusammenarbeit zwischen Mensch und Maschine so zu gestalten, dass nicht der Mensch sich an den Gegebenheiten der Maschine orientieren muss, sondern dass umgekehrt die Maschine eine Kommunikationsschnittstelle zur Verfügung stellt, die sich an den Bedürfnissen der sie bedienenden Menschen orientiert.Kriterien zur Beschreibung von Benutzerfreundlichkeit:
Aufgabenangemessenheit: Das Programm konzentriert sich auf die eigentliche Aufgabe und minimiert unnötiger Interaktionen.
Selbstbeschreibungsfähigkeit: Der Programm liefert die zur Bedienung erforderlichen Hilfen und Rückmeldungen.
Steuerbarkeit: Das Programm gibt dem Benutzer die Möglichkeit, mit Hilfe von Dialogen den Ablauf zu steuern.
Erwartungskonformität: Das Programm ist auf die Erwartungen der intendierten Benutzer abgestimmt.
Fehlertoleranz: Das Programm erkennt fehlerhafte Bedienungen und hilft bei der Korrektur.
Individualisierbarkeit: Das Programm lässt sich an individuelle Bedürfnisse anpassen.
Lernförderlichkeit: Das Programm unterstützt den Benutzer beim Erlernen der Funktionalitäten.
6 Übungen (siehe 10.1.3)Beurteilen Sie die im Einstieg gezeigten Programme hinsichtlich der Kriterien für Benutzerfreundlichkeit.
7 Teil 2
Aufbau und Verhalten
8 Einstieg - Analyse einer GUIZiel ist es herauszufinden, wie eine graphische Benutzeroberfläche (GUI) aufgebaut ist und wie ihr Verhalten zustande kommt. Bearbeiten Sie die Aufgaben des Abschnitts 10.2.1.# -*- coding: iso-8859-1 -*-from Tkinter import *# Ereignisverarbeitung
def Button_Berechnen_Click(): # Übernahme der Daten geschwindigkeit = float(entryGeschwindigkeit.get()) # Verarbeitung der Daten reaktionsweg = (geschwindigkeit/10)*3 bremsweg = (geschwindigkeit/10) * (geschwindigkeit/10) anhalteweg = reaktionsweg + bremsweg # Anzeige der Daten anzeigeReaktionsweg = '%.2f'%(reaktionsweg) labelWertReaktionsweg.config(text=anzeigeReaktionsweg) anzeigeBremsweg = '%.2f'%(bremsweg) labelWertBremsweg.config(text=anzeigeBremsweg) anzeigeAnhalteweg = '%.2f'%(anhalteweg) labelWertAnhalteweg.config(text=anzeigeAnhalteweg)
# Erzeugung des FensterstkFenster = Tk()tkFenster.title("Anhalteweg")tkFenster.geometry('300x287')# Rahmen für die ÜberschriftframeUeberschrift = Frame(master=tkFenster, background="#889E9D")frameUeberschrift.place(x=5, y=5, width=290, height=45)...
G(raphical) U(ser) I(interface)
Auszug aus dem Quelltext
9 Fachkonzept - GUI
Eine grafische Benutzeroberfläche (auch kurz GUI für Graphical User Interface) ist aus Komponenten aufgebaut. Jede Komponente wird mit einem grafische Symbol dargestellt.
10 Fachkonzept - GUI-Komponente
Grafische Benutzeroberflächen können u. a. folgende Komponenten haben:
Fenster: Eine GUI kann aus einem oder mehreren Fenstern bestehen.
Rahmen / Tafel: Rahmen (bzw. Tafeln) dienen als Behälter für andere Komponenten.
Schaltfäche (Button): Mit Schaltflächen werden in der Regel Programmaktionen ausgelöst.
Schriftfeld (Label): Schriftfelder dienen dazu, Texte auf dem Bildschirm darzustellen.
Eingabefeld: In Eingabefelder kann der Benutzer Zeichenketten eingeben.
Leinwand (Canvas): Eine Leinwand ist ein Bereich, in dem man z. B. Figuren zeichnen und Bilder anzeigen kann
Textfeld: Ein Textfeld ist ein Eingabebereich, in den mehrzeilige Texte geschrieben werden können.
...
11 Fachkonzept - GUI-Objekt
Ein Objekt ist eine Einheit, die Daten verwalten und verarbeiten kann. Jedes Objekt ist einer Klasse zugeordnet. Diese legt den Aufbau des Objekts genau fest. Ein Objekt muss erzeugt werden, bevor es zur Datenverwaltung und -verarbeitung benutzt werden kann. Die zugehörige Klasse liefert den hierzu benötigten Bauplan.
Komponenten einer Benutzeroberfläche werden programmtechnisch durch Objekte (im Sinne der objektorientierten Programmierung) dargestellt. Zu jeder Komponente gibt es ein entsprechendes GUI-Objekt, das die Daten und Operationen der Komponente verwaltet.
12 Fachkonzept - GUI-Objekt
...# Erzeugung des FensterstkFenster = Tk()...# Rahmen für die ÜberschriftframeUeberschrift = Frame(master=tkFenster, background="#889E9D")...# Eingabefeld für die GeschwindigkeitentryGeschwindigkeit = Entry(master=frameEingaben)...# Schaltfläche BerechnenbuttonBerechnen = Button(master=frameVerarbeitung, text="berechnen", command=...)...# Label für den Wert des ReaktionswegslabelWertBremsweg = Label(master=frameAusgaben, background="white", text="")...
objektname = GUIKlasse(...)
Erzeugung eines GUI-Objekts
13 Fachkonzept - GUI-Objekt
...# Label für die Überschrift labelUeberschrift = Label(master=frameUeberschrift, \ background="white", \ text="Anhalteweg eines Autos")...
GUI-Komponenten haben Eigenschaften wie z. B. eine bestimmte Hintergrundfarbe. Zur Verwaltung solcher Eigenschaften haben die zugehörigen Objekte Attribute, denen ein bestimmter Wert zugewiesen werden kann.
Attributwerte
Attribute
14 Fachkonzept - GUI-Objekt
def Button_Berechnen_Click(): # Übernahme der Daten geschwindigkeit = float(entryGeschwindigkeit.get()) # Verarbeitung der Daten reaktionsweg = (geschwindigkeit/10)*3 bremsweg = (geschwindigkeit/10) * (geschwindigkeit/10) anhalteweg = reaktionsweg + bremsweg # Anzeige der Daten anzeigeReaktionsweg = '%.2f'%(reaktionsweg) labelWertReaktionsweg.config(text=anzeigeReaktionsweg) anzeigeBremsweg = '%.2f'%(bremsweg) labelWertBremsweg.config(text=anzeigeBremsweg) anzeigeAnhalteweg = '%.2f'%(anhalteweg) labelWertAnhalteweg.config(text=anzeigeAnhalteweg)
Zur Verarbeitung der verwalteten Daten stellen Objekte Operationen (man sagt auch Methoden) bereit.
OperationObjekt
objektname.operation
Aktivierung einer Operation
15 Fachkonzept - Ereignissteuerung
def Button_Berechnen_Click(): ...
# Erzeugung des FensterstkFenster = Tk()...buttonBerechnen = Button(master=frameVerarbeitung, \ text="berechnen", \ command=Button_Berechnen_Click)...# Aktivierung des FensterstkFenster.mainloop()
Aktionen des Benutzers wie z. B. das Anklicken einer Schaltfläche lösen Ereignisse aus. Ein Ereignis ist eine Zustandsänderung in einem Objekt, die von Interesse ist und daher mit einer Prozedur zur Ereignisverarbeitung verknüpft werden kann.
Aktierung der Ereignisschleife
Ereignisverarbeitungsprozedur
wiederhole:
wenn ein Ereignis eintritt:
führe die zugeordneten Prozedur zur Ereignisverarbeitung aus
Ereignisschleife
16 Fachkonzept - Laufzeitfehler
Laufzeitfehler sind Fehlersituationen, die während der Ausführung eines Programms auftreten.
Beispiele:- Eine Operation soll mit Daten ausgeführt werden, deren Typ nicht passt.- Eine Division durch 0 soll ausgeführt werden.- Eine Datei soll geladen werden, die nicht vorhanden ist.- ...
>>> Exception in Tkinter callbackTraceback (most recent call last): File ... return self.func(*args) File ... in Button_Berechnen_Click geschwindigkeit = float(entryGeschwindigkeit.get())ValueError: invalid literal for float(): gering
17 try-except-Anweisung
def Button_Berechnen_Click(): try: # Übernahme der Daten geschwindigkeit = float(entryGeschwindigkeit.get()) # Verarbeitung der Daten reaktionsweg = (geschwindigkeit/10)*3 bremsweg = (geschwindigkeit/10) * (geschwindigkeit/10) anhalteweg = reaktionsweg + bremsweg # Anzeige der Daten anzeigeReaktionsweg = '%.2f'%(reaktionsweg) labelWertReaktionsweg.config(text=anzeigeReaktionsweg) anzeigeBremsweg = '%.2f'%(bremsweg) labelWertBremsweg.config(text=anzeigeBremsweg) anzeigeAnhalteweg = '%.2f'%(anhalteweg) labelWertAnhalteweg.config(text=anzeigeAnhalteweg) except: entryGeschwindigkeit.delete(0, END)
try: [Anweisungen]except: [Anweisungen]
18 Übungen (siehe 10.2.5)Bearbeiten Sie die Aufgaben des Abschnitts 10.2.5.
19 Teil 3
Entwicklung
20 Einstieg - "chuck a luck"Der Spieler / die Spielerin zahlt zuerst einen Dollar (Cent) als Einsatz. Diesen setzt er / sie auf eine Zahl des Spielfeldes. Anschließend wirft er / sie drei Würfel. Jetzt wird bestimmt, wie viele Würfel mit der gesetzten Spielzahl übereinstimmen. Gibt es keine Übereinstimmungen, dann ist der Einsatz verloren. Ansonsten wird erhält der Spieler / die Spielerin den Einsatz zurück und zusätzlich für jede Übereinstimmung einen Dollar (Cent).
21 Zielsetzung und VorgehensweiseEs soll ein Programm zur Simulation des Spiels chuck-a-luck entwickelt werden. Über eine grafische Benutzeroberfläche soll der Spieler / die Spielerin die Spielaktionen durchführen können. Das Programm soll selbstbeschreibend und fehlertolerant gestaltet werden.
Gehen Sie den Abschnitt "GUI-Entwicklung mit Tkinter" (siehe 10.3.2) Schritt für Schritt durch und entwickeln Sie parallel dazu ein Programm zum chuck-a-luck-Spiel.
Hinweis: Tkinter steht für Toolkit-Interface und ist eine Bibliothek, die all die Programmeinheiten enthält, die man zur Erzeugung von Komponenten einer grafischen Benutzeroberfläche mit Python benötigt. Dieses Modul gehört zur Standarddistribution von Python und kann daher direkt genutzt werden.
22 Erzeugung eines Fensters
# -*- coding: iso-8859-1 -*-
from Tkinter import *
# Erzeugung des FensterstkFenster = Tk()tkFenster.title("chuck a luck")tkFenster.geometry('350x145')# Aktivierung des FensterstkFenster.mainloop()
Tk-Objekt
23 Anzeige von Text und Daten
# -*- coding: iso-8859-1 -*-from Tkinter import *# Erzeugung des FensterstkFenster = Tk()tkFenster.title("Test")tkFenster.geometry('120x110')# Label mit Überschrift für das KontolabelUeberschriftKonto = Label(master=tkFenster, \ text="Konto", \ background="#FFCFC9")labelUeberschriftKonto.place(x=10, y=10, width=100, height=20)# Label für den KontostandlabelKonto = Label(master=tkFenster)labelKonto.config(text="100")labelKonto.config(background="#FFCFC9")labelKonto.place(x=45, y=40, width=30, height=30)# Aktivierung des FensterstkFenster.mainloop()
Label-Objekt
Label-Objekt
24 Anklicken von Schaltflächen
...# Ereignisverarbeitungdef Button_Einsatz_Click(): # Verwaltung der Daten konto = int(labelKonto.cget('text')) # Verarbeitung der Daten konto = konto - 1 # Anzeige der Daten labelKonto.config(text=str(konto))
# Erzeugung des Fensters...# Label für das KontolabelKonto = Label(master=tkFenster, \ text="100", \ background="#FFCFC9")labelKonto.place(x=45, y=35, width=30, height=30)# Button zum AuswertenbuttonEinsatz = Button(master=tkFenster, \ text="Einsatz zahlen", \ command=Button_Einsatz_Click)buttonEinsatz.place(x=10, y=75, width=100, height=20)...
Ereignisverarbeitung
Button-Objekt
25 Datenverarbeitung
...# Ereignisverarbeitungdef Button_Einsatz_Click(): # Schritt 1: Verwaltung der Daten konto = int(labelKonto.cget('text')) # Schritt 2: Verarbeitung der Daten konto = konto - 1 # Schritt 3: Anzeige der Daten labelKonto.config(text=str(konto))
# Erzeugung des Fensters...# Label für das KontolabelKonto = Label(master=tkFenster, \ text="100", \ background="#FFCFC9")labelKonto.place(x=45, y=35, width=30, height=30)# Button zum AuswertenbuttonEinsatz = Button(master=tkFenster, \ text="Einsatz zahlen", \ command=Button_Einsatz_Click)buttonEinsatz.place(x=10, y=75, width=100, height=20)...
Daten-verarbeitungs-
muster
Button-Objekt
Schritt 1: Erst werden die benötigten Daten von Attributen betreffender GUI-Objekte übernommen und in Hilfsvariablen zwischengespeichert. Beachte, dass hier oft Tyanpassungen erforderlich sind.
Schritt 2: Die jetzt mit Hilfe von Variablen erfassten Daten werden mit Hilfe geeigneter Anweisungen verarbeitet.
Schritt 3: Die Ergebnisse der Verarbeitung werden zur Anzeige auf dem Bildschirm an geeignete GUI-Objekte weitergegeben. Auch hier können Typumwandlungen erforderlich sein.
26 Eingabe von Daten
...# Ereignisverarbeitungdef Button_Verdoppeln_Click(): # Verwaltung der Daten zahl = int(entryZahl.get()) # Verarbeitung der Daten zahl = zahl * 2 # Anzeige der Daten entryZahl.delete(0, END) entryZahl.insert(0, str(zahl))
# Erzeugung des Fensters...# Eingabefeld für die ZahlentryZahl = Entry(master=tkFenster, \ background="white")entryZahl.place(x=45, y=35, width=30, height=30)# Button zum AuswertenbuttonVerdoppeln = Button(master=tkFenster, \ text="Eingabe verdoppeln", \ command=Button_Verdoppeln_Click)...
Entry-Operationen
Entry-Objekt
Entry-Operationen
27 Gestaltung des Layout
...
...# Erzeugung des FensterstkFenster = Tk()tkFenster.title("Test")tkFenster.geometry('200x200')# Rahmen KontoframeKonto = Frame(master=tkFenster, background="#FFCFC9")frameKonto.place(x=30, y=40, width=110, height=100)# Label mit Überschrift für das KontolabelUeberschriftKonto = Label(master=frameKonto, text="Konto", background="white")labelUeberschriftKonto.place(x=5, y=5, width=100, height=20)# Label für den KontostandlabelKonto = Label(master=frameKonto, text="100", background="white")labelKonto.place(x=40, y=35, width=30, height=30)# Button zum AuswertenbuttonEinsatz = Button(master=frameKonto, text="Einsatz zahlen", command=...)buttonEinsatz.place(x=5, y=75, width=100, height=20)# Aktivierung des FensterstkFenster.mainloop()
Frame-Objekt
28 Gestaltung des Layout
...
...# Erzeugung des FensterstkFenster = Tk()tkFenster.title("Test")tkFenster.geometry('200x200')# Rahmen KontoframeKonto = Frame(master=tkFenster, background="#FFCFC9")frameKonto.place(x=30, y=40, width=110, height=100)# Label mit Überschrift für das KontolabelUeberschriftKonto = Label(master=frameKonto, text="Konto", background="white")labelUeberschriftKonto.place(x=5, y=5, width=100, height=20)# Label für den KontostandlabelKonto = Label(master=frameKonto, text="100", background="white")labelKonto.place(x=40, y=35, width=30, height=30)# Button zum AuswertenbuttonEinsatz = Button(master=frameKonto, text="Einsatz zahlen", command=...)buttonEinsatz.place(x=5, y=75, width=100, height=20)# Aktivierung des FensterstkFenster.mainloop()
Master-Slave-
Hierarchie
Pixel-Koordinatensyste
me
29 Verarbeitung von Ereignissen
...# Ereignisverarbeitung
def wuerfelAWerfen(event): # Verarbeitung der Daten wuerfelA = randint(1, 6) # Anzeige der Daten labelWuerfelA.config(text=str(wuerfelA))
def alleWuerfelWerfen(event): # Verwaltung und Verarbeitung der Daten from random import randint wuerfelA = randint(1,6) wuerfelB = randint(1,6) wuerfelC = randint(1,6) # Anzeige der Daten labelWuerfelA.config(text=str(wuerfelA)) labelWuerfelB.config(text=str(wuerfelB)) labelWuerfelC.config(text=str(wuerfelC))
...
...# Label Würfel AlabelWuerfelA = Label(master=frameWuerfel, \ text="1", \ background="white")labelWuerfelA.bind("<Double-Button-1>", wuerfelAWerfen)...# Button zum WürfelnbuttonWuerfel = Button(master=frameWuerfel, \ text="Wuerfel werfen")buttonWuerfel.bind("<Button-1>", alleWuerfelWerfen)...
Ereignis
Ereignisverarbeitung
Ereignis
Ereignisverarbeitung
Übergabe eines Event-Objekts
30
Auswahlmöglichkeit mit Radiobutton
...# Ereignisverarbeitungdef Button_Auswahl_Click(): # Verwaltung der Daten zahl = spielzahl.get() # Anzeige der Daten labelAusgewaehlteZahl.config(text=str(zahl))...# Radiobutton für die Zahlspielzahl = IntVar()radiobutton1 = Radiobutton(master=frameZahl, text='1', value=1, variable=spielzahl)radiobutton1.place(x=5, y=30, width=30, height=18)radiobutton2 = Radiobutton(master=frameZahl, text='2', value=2, variable=spielzahl)radiobutton2.place(x=40, y=30, width=30, height=18)radiobutton3 = Radiobutton(master=frameZahl, text='3', value=3, variable=spielzahl)radiobutton3.place(x=75, y=30, width=30, height=18)# Label mit ausgewählter ZahllabelAusgewaehlteZahl = Label(master=frameZahl, text="", background="white")labelAusgewaehlteZahl.place(x=40, y=52, width=30, height=18)# Button zum AuswertenbuttonAuswahl = Button(master=frameZahl, text="Auswahl anzeigen", \ command=Button_Auswahl_Click)...
Radiobutton-Objekt
IntVar-Objekt als Kontrollvariable
31 Einbindung von Bildern
# -*- coding: iso-8859-1 -*-from Tkinter import *# Erzeugung des FensterstkFenster = Tk()tkFenster.title("Test")tkFenster.geometry('120x110')# Rahmen WürfelframeWuerfel = Frame(master=tkFenster, background="#FBD975")frameWuerfel.place(x=5, y=5, width=110, height=100)# Bilderwuerfel1 = PhotoImage(file="w1.gif")# Label Würfel BlabelWuerfelB = Label(master=frameWuerfel, image=wuerfel1)labelWuerfelB.place(x=40, y=35, width=30, height=30)# Aktivierung des FensterstkFenster.mainloop()
PhotoImage-Objekt
32 Einbindung von Bildern
...
# Ereignisverarbeitung
def Button_Wuerfel_Click(): # Verwaltung und Verarbeitung der Daten wuerfelB = randint(1,6) # Anzeige der Daten labelWuerfelB.config(text=str(wuerfelB)) if wuerfelB == 1: labelWuerfelB.config(image=wuerfel1) elif wuerfelB == 2: labelWuerfelB.config(image=wuerfel2) elif wuerfelB == 3: labelWuerfelB.config(image=wuerfel3) elif wuerfelB == 4: labelWuerfelB.config(image=wuerfel4) elif wuerfelB == 5: labelWuerfelB.config(image=wuerfel5) elif wuerfelB == 6: labelWuerfelB.config(image=wuerfel6)
...
...# Bilderwuerfel1 = PhotoImage(file="w1.gif")wuerfel2 = PhotoImage(file="w2.gif")wuerfel3 = PhotoImage(file="w3.gif")wuerfel4 = PhotoImage(file="w4.gif")wuerfel5 = PhotoImage(file="w5.gif")wuerfel6 = PhotoImage(file="w6.gif")# Label Würfel BlabelWuerfelB = Label( \ master=frameWuerfel, image=wuerfel1)labelWuerfelB.place(...)# Button zum WürfelnbuttonWuerfel = Button( \ master=frameWuerfel, \ text="Wuerfel werfen", \ command=Button_Wuerfel_Click)...
33 Einbindung von Bildern
...
# Ereignisverarbeitung
def Button_Wuerfel_Click(): # Verwaltung und Verarbeitung der Daten wuerfelB = randint(1,6) # Anzeige der Daten labelWuerfelB.config(text=str(wuerfelB)) labelWuerfelB.config( \ image=wuerfelbilder[wuerfelB-1])
...
...wuerfelbilder = [ \ PhotoImage(file="w1.gif"), \ PhotoImage(file="w2.gif"), \ PhotoImage(file="w3.gif"), \ PhotoImage(file="w4.gif"), \ PhotoImage(file="w5.gif"), \ PhotoImage(file="w6.gif") \ ]# Label Würfel BlabelWuerfelB = Label( \ master=frameWuerfel, image=wuerfelbilder[0])labelWuerfelB.place(...)# Button zum WürfelnbuttonWuerfel = Button( \ ... command=Button_Wuerfel_Click)...
34 Eine Leinwand für Grafiken
...# Ereignisverarbeitungdef Button_Zeichnen_Click(): # Anzeige der Daten z = randint(0, 1) if z > 0: canvas.itemconfigure(id_pfeilnachoben, fill="black") canvas.itemconfigure(id_pfeilnachunten, fill="#FFCFC9") else: canvas.itemconfigure(id_pfeilnachoben, fill="#FFCFC9") canvas.itemconfigure(id_pfeilnachunten, fill="black")...# Leinwand canvas = Canvas(master=tkFenster, background="#FFCFC9")canvas.place(x=5, y=5, width=110, height=100)id_pfeilnachunten = canvas.create_line(20, 40, 20, 60, arrow=LAST, fill="#FFCFC9")id_pfeilnachoben = canvas.create_line(90, 60, 90, 40, arrow=LAST, fill="#FFCFC9")...# Button zum ZeichnenbuttonZeichnen = Button(master=canvas, text="Zeichnen", \ command=Button_Zeichnen_Click)...
Canvas-Objekt
35 Animation mit einem Timer
...# Ereignisverarbeitung
def Button_Zaehlen_Click(): # Verwaltung der Daten stand = int(entryZaehler.get()) if stand > 0: # Verarbeitung der Daten stand = stand - 1 # Anzeige der Daten entryZaehler.delete(0, END) entryZaehler.insert(0, str(stand)) # rekursiver Aufruf der Prozedur tkFenster.after(1000, Button_Zaehlen_Click)
# Erzeugung des Fensters...buttonZaehlen = Button(master=frameZaehler, \ text="Herunterzählen", \ command=Button_Zaehlen_Click)buttonZaehlen.place(x=5, y=75, width=100, height=20)
...
after-Methode
36 Übungen (siehe 10.3.5)Bearbeiten Sie die Aufgaben des Abschnitts 10.2.5.
37 Teil 4
GUI-Objekte und Datenmodell-Objekte
38
Exkurs - Datenhaltung m. GUI-Objekten
...
# Ereignisverarbeitung
def Button_Wuerfel_Click(): # Verwaltung und Verarbeitung der Daten wuerfelB = randint(1,6) # Anzeige der Daten labelWuerfelB.config(text=str(wuerfelB)) labelWuerfelB.config( \ image=wuerfelbilder[wuerfelB-1])
...
...wuerfelbilder = [ \ PhotoImage(file="w1.gif"), \ PhotoImage(file="w2.gif"), \ PhotoImage(file="w3.gif"), \ PhotoImage(file="w4.gif"), \ PhotoImage(file="w5.gif"), \ PhotoImage(file="w6.gif") \ ]# Label Würfel BlabelWuerfelB = Label( \ master=frameWuerfel, image=wuerfelbilder[0])labelWuerfelB.place(...)# Button zum WürfelnbuttonWuerfel = Button( \ ... command=Button_Wuerfel_Click)...
unbefriedigende Lösung: aktuelles
Würfelergebnis wird hier zusätzlich als
Zeichenkette abgespeichert
39
Exkurs - Datenhaltung m. globalen Var.
# -*- coding: iso-8859-1 -*-from Tkinter import *from random import randint
# Datenmodellkonto = 100wuerfelA = 1wuerfelB = 1wuerfelC = 1zahl = None
# Ereignisverarbeitung
def Button_Einsatz_Click(): global konto # Verarbeitung der Daten konto = konto - 1 # Anzeige der Daten labelKonto.config(text=str(konto)) ...
...
def Button_Wuerfel_Click(): global wuerfelA, wuerfelB, wuerfelC # Verwaltung und Verarbeitung der Daten wuerfelA = randint(1,6) wuerfelB = randint(1,6) wuerfelC = randint(1,6) # Anzeige der Daten if wuerfelA == 1: labelWuerfelA.config(image=wuerfel1) elif wuerfelA == 2: labelWuerfelA.config(image=wuerfel2) elif wuerfelA == 3: labelWuerfelA.config(image=wuerfel3) elif wuerfelA == 4: labelWuerfelA.config(image=wuerfel4) elif wuerfelA == 5: labelWuerfelA.config(image=wuerfel5) elif wuerfelA == 6: labelWuerfelA.config(image=wuerfel6) ...
unbefriedigende Lösung: Spieldaten
mit globalen Variablen verwalten
40 Exkurs - Datenmodell-Objekt
# -*- coding: iso-8859-1 -*-from random import randint# Datenmodellclass ChuckALuck(object): def __init__(self): self.konto = 100 self.spielzahl = 1 self.wuerfelA = 1 self.wuerfelB = 1 self.wuerfelC = 1
def einsatzZahlen(self): self.konto = self.konto - 1
def spielzahlSetzen(self, zahl): self.spielzahl = zahl
...
...
def wuerfelWerfen(self): self.wuerfelA = randint(1,6) self.wuerfelB = randint(1,6) self.wuerfelC = randint(1,6)
def gewinnAuszahlen(self): gewinn = 0 if self.spielzahl == self.wuerfelA: gewinn = gewinn + 1 if self.spielzahl == self.wuerfelB: gewinn = gewinn + 1 if self.spielzahl == self.wuerfelC: gewinn = gewinn + 1 if gewinn > 0: self.konto = self.konto + (gewinn + 1)
Bauplan für ein Objekt zur
Verwaltung der Spieldaten
41 Exkurs - Datenmodell-Objekt
# -*- coding: iso-8859-1 -*-from random import randint# Datenmodellclass ChuckALuck(object): def __init__(self): self.konto = 100 self.spielzahl = 1 self.wuerfelA = 1 self.wuerfelB = 1 self.wuerfelC = 1
def einsatzZahlen(self): ...
def spielzahlSetzen(self, zahl): ...
def wuerfelWerfen(self): ...
def gewinnAuszahlen(self): ...
>>> spiel = ChuckALuck()>>> spiel.konto100>>> spiel.einsatzZahlen()>>> spiel.konto99>>> spiel.spielzahlSetzen(6)>>> spiel.spielzahl6>>> spiel.wuerfelWerfen()>>> spiel.wuerfelA3>>> spiel.wuerfelB6>>> spiel.wuerfelC6>>> spiel.gewinnAuszahlen()>>> spiel.konto102
Bauplan für ein Datenmodell-Objekt
Erzeugung und Nutzung des Datenmodell-
Objekts
42
Exkurs - Datenmodell- und GUI-Objekte
...# Datenmodellfrom chuckaluck_datenmodell import ChuckALuckspiel = ChuckALuck()# Ereignisverarbeitungdef Button_Einsatz_Click(): # Verarbeitung der Daten spiel.einsatzZahlen() # Anzeige der Daten labelKonto.config(text=str(spiel.konto))def Button_Wuerfel_Click(): # Verarbeitung der Daten spiel.wuerfelWerfen() # Anzeige der Daten labelWuerfelA.config(image=wuerfelbilder[spiel.wuerfelA-1]) ...def Button_Gewinn_Click(): # Verarbeitung der Daten spiel.spielzahlSetzen(spielzahl.get()) spiel.gewinnAuszahlen() # Anzeige der Daten labelKonto.config(text=str(spiel.konto))...
Verarbeitung der Daten mit Datenmodell-Objekt
Anzeige der Daten mit GUI-Objekt
43 Exkurs - verfeinertes Datenmodell
# Datenmodellclass ChuckALuck(object): def __init__(self): self.konto = 100 self.spielzahl = 1 self.wuerfelA = 1 self.wuerfelB = 1 self.wuerfelC = 1 self.zustand = "spielBeginnt"
def einsatzZahlen(self): if self.zustand == "spielBeginnt": self.konto = self.konto - 1 self.zustand = "einsatzGezahlt"
...
Zustandsdiagramm
44 Exkurs - verfeinertes Datenmodell
def Button_Einsatz_Click(): # Verarbeitung der Daten spiel.einsatzZahlen() # Anzeige der Daten labelKonto.config(text=str(spiel.konto))
def Button_Wuerfel_Click(): # Verarbeitung der Daten spiel.wuerfelWerfen() # Anzeige der Daten labelWuerfelA.config(image=wuerfelbilder[spiel.wuerfelA-1]) labelWuerfelB.config(image=wuerfelbilder[spiel.wuerfelB-1]) labelWuerfelC.config(image=wuerfelbilder[spiel.wuerfelC-1])
def Radiobutton_Click(): # Verarbeitung der Daten spiel.spielzahlSetzen(spielzahl.get()) def Button_Gewinn_Click(): # Verarbeitung der Daten spiel.gewinnAuszahlen() # Anzeige der Daten labelKonto.config(text=str(spiel.konto))
Zustandsdiagramm
45 ÜbungenTesten Sie die Datenmodell-Objekte wie gezeigt. Analysieren Sie auch das Zusammenspiel der Datenmodell- und GUI-Objekte.
46 Teil 5
GUI-Entwicklung mit Werkzeugen
47 GUI-BuilderEin GUI-Builder ist ein Werkzeug, das den Benutzer bei der Entwicklung einer Benutzeroberfläche unterstützt. Der Benutzer kann mit einfachen Maus-Operationen die gewünschte Benutzeroberfläche erstellen, das Werkzeug erzeugt den zugehörigen Quelltext.
Es gibt eine ganze Reihe von GUI-Buildern, die die Erstellung einer Benutzeroberfläche unter Python unterstützen. Aber nur wenige erzeugen einen einfach zu durchschauenden Quelltext, der zusätzlich noch mit dem hier eingeschlagenen Weg kompatibel ist.
Tk_happy ist ein GUI-Builder für Python, der das Modul Tkinter benutzt. Auf der Projekthomepage von Tk_happy wird dieser GUI-Builder so beschrieben:
"The main idea behind tk_happy is to allow a fully "wired" python Tkinter GUI application to be created in minutes. The users main responsibility is to add logic to the Tkinter framework created by tk_happy."
Achtung: Tk_happy ist für den Einsatz im Unterricht wenig geeignet.
48 Beispiel - Simulation eines WürfelsDie folgende grafische Benutzeroberfläche soll - ohne das Werkzeug Tk_happy- mit dem Werkzeug Tk_happyerstellt werden.
49
...def Button_Wuerfeln_Click(event): from random import randint # Verarbeitung der Daten augen = randint(1, 6) # Anzeige der Daten labelWuerfel.config(text=int(augen))# Erzeugung des Fenstersfenster = Tk()fenster.title("Würfeln")fenster.geometry('300x200')# Rahmen für die Benutzungsoberflächerahmen = Frame(master=fenster, background="white")rahmen.place(x=0, y=0, width=300, height=200)# Label für das WürfelergebnislabelWuerfel = Label(master=rahmen, background="blue", foreground="white", text="1")labelWuerfel.place(x=138, y=72, width=24, height=24)# Button WuerfelnbuttonWuerfeln = Button(master=rahmen, text="würfeln")buttonWuerfeln.bind("<ButtonRelease-1>", Button_Wuerfeln_Click)buttonWuerfeln.place(x=100, y=150, width=101, height=25)# Aktivierung des Fenstersfenster.mainloop()
Vorbereitung - GUI-Objekte
Erzeugung der GUI-Objekte
50
...class Wuerfel(object): def __init__(self): ... # Label für das Würfelergebnis self.labelWuerfel = Label(master=self.rahmen, background="blue", ...) self.labelWuerfel.place(x=138, y=72, width=24, height=24) # Button Wuerfeln self.buttonWuerfeln = Button(master=self.rahmen, text="würfeln") self.buttonWuerfeln.bind("<ButtonRelease-1>", self.Button_Wuerfeln_Click) self.buttonWuerfeln.place(x=100, y=150, width=101, height=25) # Aktivierung des Fensters self.fenster.mainloop() def Button_Wuerfeln_Click(self, event): from random import randint # Verarbeitung der Daten augen = randint(1, 6) # Anzeige der Daten self.labelWuerfel.config(text=int(augen))
# Erzeugung des GUI-ObjektswuerfelGUI = Wuerfel()
Vorbereitung - GUI-Klasse
Objekt zur Verwaltung der GUI-
Objekte
Definition einer GUI-Klasse
51
...class Wuerfel(object): def __init__(self, master): self.master = master self.rahmen = Frame(master=self.master, background="white") ... # Label für das Würfelergebnis self.labelWuerfel = Label(master=self.rahmen, background="blue", ...) ... # Button Wuerfeln self.buttonWuerfeln = Button(master=self.rahmen, text="würfeln") self.buttonWuerfeln.bind("<ButtonRelease-1>", self.Button_Wuerfeln_Click) ... def Button_Wuerfeln_Click(self, event): from random import randint augen = randint(1, 6) self.labelWuerfel.config(text=int(augen))# Erzeugung der Objektefenster = Tk()fenster.title("Würfeln")fenster.geometry('300x200')wuerfelGUI = Wuerfel(fenster)fenster.mainloop()
Vorbereitung - GUI-Klasse
Definition einer GUI-Klasse
Objekt zur Verwaltung der GUI-
Objekte
52 Exkurs - Tk_happyDas Werkzeug Tk_happy stellt dem Benutzer drei Fenster zur Verfügung.
Menu-Fenster
Formular-Fenster
Objekt-Inspektor
53
...class _Wuerfel: def __init__(self, master): ... self.master.title("Wuerfel") self.Button_Wuerfeln = Button(self.master,text="wuerfeln", \ background="SystemButtonFace", width="15") self.Button_Wuerfeln.place(x=100, y=150, width=101, height=25) self.Button_Wuerfeln.bind("<ButtonRelease-1>", self.Button_Wuerfeln_Click) self.Label_Wuerfel = Label(self.master,text="6", foreground="white", \ background="blue", width="15") self.Label_Wuerfel.place(x=138, y=72, width=24, height=24) ... def Button_Wuerfeln_Click(self, event): #click method for component ID=1 pass
def main(): root = Tk() app = _Wuerfel(root) root.mainloop()
if __name__ == '__main__': main()
Exkurs - Tk_happy
von Tk_happy erzeugter Quelltext
54
...class _Wuerfel: def __init__(self, master): ... self.master.title("Wuerfel") self.Button_Wuerfeln = Button(self.master,text="wuerfeln", \ background="SystemButtonFace", width="15") self.Button_Wuerfeln.place(x=100, y=150, width=101, height=25) self.Button_Wuerfeln.bind("<ButtonRelease-1>", self.Button_Wuerfeln_Click) self.Label_Wuerfel = Label(self.master,text="6", foreground="white", \ background="blue", width="15") self.Label_Wuerfel.place(x=138, y=72, width=24, height=24) ...
def Button_Wuerfeln_Click(self, event): #click method for component ID=1 from random import randint # Verarbeitung der Daten augen = randint(1, 6) # Anzeige der Daten self.Label_Wuerfel.config(text=int(augen))
...
Exkurs - Tk_happy
ergänzter Quelltext
55 Exkurs - PythonCardPythonCard ist ein Werkzeug zur Entwicklung grafischer Benutzeroberflächen für Python-Programme. Auf der Projekthomepage von PythonCard wird dieser GUI-Builder so beschrieben:
"PythonCard is a GUI construction kit for building cross-platform desktop applications on Windows, Mac OS X, and Linux, using the Python language. The PythonCard motto is "Simple things should be simple and complex things should be possible." PythonCard is for you if you want to develop graphical applications quickly and easily with a minimum of effort and coding."
PythonCard benutzt wxPython. Wenn du PythonCard benutzen willst, dann musst du sowohl wxPython als auch PythonCard installieren.
Für weitere Informationen siehe 10.4.2.
56 Teil 6
Miniprojekte
57 Vorgehensweise
Schritt 1: Entwurf zur Benutzeroberfläche
Überlege dir zunächst, was die Benutzeroberfläche alles leisten soll: In welcher Weise soll sie den Benutzer informieren? In welcher Weise soll der Benutzer selbst agieren können?Entwickle (am besten auf Papier) einen ersten Entwurf für eine Benutzersoberfläche, die das Gewünschte leistet. Schritt 2: Struktur der Benutzeroberfläche
Erzeuge mit Hilfe geeigneter Komponenten eine Benutzeroberfläche, die den Entwurf umsetzt. Lass zunächst alle Details der Prozeduren, die bei bestimmten Ereignissen ausgeführt werden sollen, weg. Das Programm sollte lauffähig sein, aber noch nicht in der gewünschten Weise beim Eintreten der jeweiligen Ereignisse reagieren.Schritt 3: Dynamik der Benutzeroberfläche
Bei etwas komplexeren Programmen solltest du zunächst ein eigenständiges Datenmodell entwickeln und unabhängig von der Benutzeroberfläche testen. Implementiere jetzt die Prozeduren zur Ereignisbearbeitung. Teste alle Funktionalitäten des Programms Mach das Programm möglichst fehlertolerant.
Schritt 4: Layout der Benutzeroberfläche
Zum Abschluss kannst du das Layout der Benutzeroberfläche nochmal überarbeiten und nach deinen Wünschen gestalten.
58 Miniprojekt - ZiegenproblemWeißt du, worum es beim Ziegenproblem geht? Wenn nicht, dann lies dir die Problemstellung bei Wikipedia durch.
Mit Hilfe eines Simulationsprogramms soll herausgefunden werden, ob es für den Kandidaten günstiger ist, bei seiner ersten Wahl zu bleiben, oder umzuwählen.
Entwickle ein Programm zur Simulation des Ziegenproblemspiels. Über eine grafische Benutzeroberfläche soll der Spieler / die Spielerin die Spielaktionen des Kandidaten durchführen können. Die Aktionen des Moderators sollen vom Programm übernommen werden. Das Programm soll selbstbeschreibend und fehlertolerant gestaltet werden. Orientiere dich bei der Entwicklung an den im letzten Abschnitt aufgezeigten Schritten.
59 Miniprojekt - TaschenrechnerDer Taschenrechner soll folgendermaßen funktionieren:
Der Benutzer / die Benutzerin kann einfache Rechenaufgaben wie z. B. 342*28= mit geeigneten Schaltflächen (die den Tasten entsprechen) eintippen. Mit einer bestimmten Schaltfläche kann man den Taschenrechner aktivieren, die Rechnung durchzuführen und das Ergebnis im Display anzuzeigen.
Es soll ein Programm zur Simulation eines Taschenrechners entwickelt werden. Über eine grafische Benutzeroberfläche soll der Benutzer / die Benutzerin die Aktionen ausführen können. Das Programm soll selbstbeschreibend und fehlertolerant gestaltet werden. Orientiere dich bei der Entwicklung an den im letzten Abschnitt aufgezeigten Schritten.