2015-05-03 Översikt • Olika former av programflöden 729G06 – Föreläsning 4 Händelsedriven GUI-programmering • Vad är ett GUI? • GUI-programmering i Python med Tkinter • ”Widgetar” Annika Silvervarg Ciltab, IDA, Linköpings universitet 1 Textbaserat gränssnitt – Exempel Textbaserat gränssnitt – Programflöde Enter name: Amanda • Linjär/hierarkisk interaktion Enter title: Giant Slayer • Visa alternativ för användaren Enter sex (m/f): f • Ta emot kommando från användaren Choose appearance 1. unwashed 2. sparkling 3. retro • Ta eventuellt emot ytterligare information från användaren • Interaktion m h a tangentbord • Typisk interaktion >1 • Kör kommando Do you have a magic bag (y/n)? y • Välj ett alternativ Are you happy (y/n)? n • Svara på en fråga Do you have a secret (y/n)? n Generate story (y=yes, n=no, start over)? n GUI = Graphical User Interface GUI – Exempel • Gränssnitt - något som ligger mellan två andra saker • För GUI är det gränssnittet mellan användaren och programmet Name Amanda • Alternativ till GUI: textbaserat gränssnitt, fysiskt gränssnitt Title the Giant Slayer Sex Female Male Appearance Other unwashed has magic bag is happy has secret Reset Quit 1 2015-05-03 GUI - Programflöde GUI - Exempel • Icke-linjär interaktion • Reaktivt - Händelsestyrt • Interaktion via mus och tangentbord • Interaktion med en begränsad och standardiserad uppsättning widgets (oftast) GUI – beståndsdelar Widgets (window gadgets) • Widgets: instanser av olika typer av GUI-element • Fönster: dialogrutor, öppna dokument etc Label Text input field Label Text input field Drop Down • Behållare (Containers) : Frame, Panel, Canvas Radio Button 1 • Funktionalitet för att ordna layout av widgets etc • Koppling mellan widgets och faktisk funktionalitet Radio Button 2 Radio Button 3 Selected Checkbox Unselected Checkbox Selected Checkbox Unselected Checkbox Button 1 Widgets i Tkinter Button 2 Widgets • Widgets är objekt (dvs instanser av olika widgetklasser) • Olika inställningar kan ges när man skapar en widget • Widgets kan placeras i ett GUI på tre sätt – det finns tre "geometry managers" (i andra språk också kallade för "layout managers") http://pythonwiki.tiddlyspot.com/#%5B%5BVisual%20Guide%20to%20Tkinter%20widgets%5D%5D 2 2015-05-03 Ett fönster Flera fönster import Tkinter as tk import Tkinter as tk # skapa ett Tk-fönster root= tk.Tk() # skapa ett Tk-fönster root = tk.Tk() # starta GUI-loopen root.mainloop() # skapa ett till fönster top = tk.Toplevel() Ett fönster i Tkinter är ett objekt av typen Tk. För att utritning av fönster etc ska göras, måste man starta GUI:ts huvudloop: mainloop() # starta GUI-loopen root.mainloop() För att skapa fler än ett fönster används klassen Toplevel fönster utöver det första Skapa widgets • När man skapar en widget, dvs skapar en instans av en widgetklass, måste man ange dess förälder. Föräldern är ett fönster eller en widget som kan agera "container" Button • En knapp • Knappar kan ha text på • Knappar kan tryckas på • Knappar kan vara avstängda (disabled) mm • Widget(parent, attribute1=v1, attribute2=v2,…) • w = Widget(parent, attribute1=v1, attribute2=v2,…) Button import Tkinter as tk # skapa ett Tk-fönster root = tk.Tk() # skapa en knapp button = tk.Button(root, text="Press Me!") button.pack() Widget - Händelse • Koppla beteende till en widget genom att koppla en funktion/metod till det • Vi kan koppla till en funktion som ett kommando som körs när vi aktiverar en widget • Vi kan binda ihop en viss händelse relaterat till widgeten med en viss funktion # starta GUI-loopen root.mainloop() 3 2015-05-03 Widget – kommando Button med kommando • Man kan koppla ett kommando till vissa widgets import Tkinter as tk • T ex knappar: def callback(): print("Something happened!") • button = tk.Button(text="OK", command=do_this) • do_this är namnet på en funktion/metod # skapa ett Tk-fönster root = tk.Tk() button = tk.Button(root, text="Press Me!", command=callback) button.pack() # starta GUI-loopen root.mainloop() Händelser Händelser forts. • Förutom att vissa widgets kan ha kommandon kopplade till sig, kan olika former av interaktion med GUI:t producera händelser – events: • Funktionen man binder till ett event ska ta in en instans av klassen Event som parameter: def key_handler(event): print("A key was pressed”) • <Enter> - när musen förs in i över en widget • <Leave> - när musen lämnar en widget • <KeyPress> - när en tangent trycks ner • Från ett event-objekt kan man läsa av diverse information med event.attribut, där attribut kan vara t ex • <KeyRelease> - när en tangent åker upp igen • <Button-1> - när musknapp 1 trycks • widget – vilken widget instans som genererade händelsen • <Button-2> - när musknapp 2 trycks • x, y – musens position i pixlar • char – teckenkoden för keyboard event som en sträng • En händelse beskrivs med hjälp av en sträng, t ex "<Button-1>" • keysym – teknet för ett keyboard event • Dessa händelser kan kopplas till funktioner/metoder med bind() : • type – typen av event • widget.bind("<Button-1>", function) Button – Händelser Label def callback(): print("Something happened!") • Labels används som etiketter i ett GUI, t ex för att berätta vad som ska skrivas i ett textfält. def over_me(event): print("You are over me!") print("event type: " + event.type) print("mouse pos: (" + str(event.x) + ", " + str(event.y) + ")") • Man kan välja om texten i etiketten ska var centrerad, höger- eller vänsterjusterad #label label1 = tk.Label(root, text="Write something") label1.pack() def left_me(event): print("You left me!") # skapa ett Tk-fönster root = tk.Tk() button = tk.Button(root, text="Press Me!", command=callback) button.bind("<Enter>", over_me) button.bind("<Leave>", left_me) button.pack() 27 4 2015-05-03 Entry Entry • Ett Entry är ett textfält som har en rad def key(event): if event.widget == entry1: print(entry1.get()) if event.widget == entry2: print("Entry 2 changed") • Vi läser från ett entry genom att anropa dess metod get() • Vi ändrar texten som står i ett entry genom att använda metoderna insert() och delete() • insert() behöver ett start-index och en sträng, t ex entry1.insert(0, "hej") entry1 = tk.Entry(root) entry1.bind("<KeyRelease>", key) entry1.pack() • delete() behöver ett index för att ta bort ett tecken, eller ett start-index och slut-index. Man kan använda Tkinter.END för att ange slut-index entry2 = tk.Entry(root) entry2.bind("<KeyRelease>", key) entry2.pack() 30 Entry – Button sammankoppling via händelse Frame • En behållare (eng container) för andra widgets def clear_entry2(): entry2.delete(0, tk.END) • Ett användningsområde för Frames är att gruppera widgets, t ex kan flera widgets läggas in i en frame, sen lägger man till den frame:n till ett fönster button2 = tk.Button(root, text="Clear", command=clear_entry2) button2.pack() 31 Layout • Det finns sätt att bestämma hur widgets ska organiseras i en container: • pack • grid • place • Vi ska koncentrera oss på grid Grid • Vi lägger ut våra widgets i en matris/tabell/rutnät • Matrisen har rader och kolumner av celler • En widget placeras på en viss rad, i en viss kolumn • En widget kan sträcka sig över fler än en rad/kolumn • Vi kan fästa en widget i t ex ett hörn eller vid en kant där den stannar om en cell skulle vara större än den widget som finns inuti den 5 2015-05-03 Layout med grid() Exempel på label, textfält och knapp 0 0 title_label = tk.Label(frame, text="The best game character ever", background="red", font = myFont) title_label.grid(row=0, column=0, columnspan=2, sticky=tk.E+tk.W+tk.N+tk.S) 1 The best game character ever 1 Name Bob 2 Game Bob's Great Adventure 3 name_label = tk.Label(frame, text="Name", font = myFont) name_label.grid(row=1, column=0, sticky=tk.NW) name_entry = tk.Entry(frame, font = myFont) name_entry.grid(row=1, column=1, sticky=tk.NW) Ok game_label = tk.Label(frame, text="Game", font = myFont) game_label.grid(row=2, column=0, sticky=tk.NW) game_entry = tk.Entry(frame, font = myFont) game_entry.grid(row=2, column=1, sticky=tk.NW) button = tk.Button(frame, text="Ok", font = myFont) button.grid(row=3, column=1, sticky=tk.SE) Radiobutton Tk-variabler • En grupp av knappar där endast en kan vara aktiv • Tk-variabler är objekt som Tkinter använder för att lagra värden i • Knappar grupperas ihop genom att de tilldelas samma Tk-variabel att lagra sitt värde i • T ex finns: • En funktion kan anges som ett kommando till varje radioknapp • StringVar som tar hand om strängar • IntVar som tar hand om int:ar • En Tk-variabel kan ropa på en funktion när förändring sker, antingen när någon läser från den, eller när någon skriver till den Radiobuttons def radio(): print(radio_value.get()) # Tk-variabel att lagra radioknapp-gruppens värde i radio_value = tk.StringVar() radio_value.set("inget valt") Checkbutton • En knapp som antingen är på eller av • Värdet avläses från en Tkinter-variabel (IntVar) som man kopplar till knappen radio_button1 = tk.Radiobutton(root, text="Hejsan", variable=radio_value, value="hejsan", command=radio) radio_button1.pack() radio_button2 = tk.Radiobutton(root, text="Hoppsan", variable=radio_value, value="hoppsan", command=radio) radio_button2.pack() radio_button3 = tk.Radiobutton(root, text="Svejsan", variable=radio_value, value="svejsan", command=radio) radio_button3.pack() 6 2015-05-03 Checkboxes def check_changed(name, index, mode): if name == "check1": print("check 1: " + str(check_val1.get())) elif name == "check2": print("check 2: " + str(check_val2.get())) Text • En Text-widget innehåller flera rader text • Diverse metoder finns för att manipulera innehållet • För att ändra hela texten används text.insert(tk.END, ”text som ska visas”) check_val1 = tk.IntVar(name="check1") check_val1.trace('w', check_changed) check_val2 = tk.IntVar(name="check2") check_val2.trace('w', check_changed) checkbutton1 = tk.Checkbutton(root, variable=check_val1, text="box of check I am") checkbutton1.pack() checkbutton2 = tk.Checkbutton(root, variable=check_val2, text="box of check I am too") checkbutton2.pack() Text text = tk.Text(root, width=25, height=10) text.insert(tk.END, "This is the text widget.\nWith many lines.") text.pack() Combobox • En combobox visar det alternativ som är valt. Klickar man på dess expandera-knapp, rullas alternativen ut i en vertikal lista. • Valt alternativ lagras i en Tk-variabel som är kopplad till comboboxen • Combobox finns bara i ttk ttk - widgets med anpassat utseende • Sedan Tk 8.5 finns modulen ttk som har widgets som efterliknar det körande operativsystemets stil • Widgets som finns som ttk-varianter: • Button • Checkbutton • Entry • Label • LabelFrame ttk - widgets med anpassat utseende • ttk lägger även till fyra nya widgets: • Combobox • Notebook • Progressbar • Separator • ttk importeras med: from Tkinter import ttk • Menubutton • PanedWindow • Radiobutton • Scale • Scrollbar 7 2015-05-03 Combobox def combo_value_changed(name, index, mode): print(combo_value.get()) combo_value = tk.StringVar() combo_value.set("Choose") combobox = ttk.Combobox(root, textvariable=combo_value, values=["eggs", "bacon", "spam"]) combo_value.trace('w', combo_value_changed) combobox.pack() Bra Tkinter-referenser • Tkinter 8.5 reference: a GUI for Python. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html • An Introduction to Tkinter. 1999. Fredrik Lund http://www.pythonware.com/library/tkinter/introduction/index.htm • An introduction to Tkinter. 2005. http://effbot.org/tkinterbook/ • TkDocs Tutorial. http://www.tkdocs.com/tutorial/index.html • OBS! Python 3 ändringar (som ni kan bortse ifrån just nu, Lab4 kör 2.7): • Tkinter -> tkinter • import ttk -> from tkinter import ttk 8
© Copyright 2024