Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield,...

15
Języki skryptowe Python Wykład 9 Graficzne interfejsy użytkownika Janusz Szwabiński Plan wykładu: Kilka uwag na temat projektowania GUI Przegląd bibliotek GUI Pierwsze kroki w Tkinter Materiały do wykładu: http://tkinter.unpythonic.net/wiki/ (http://tkinter.unpythonic.net/wiki/) https://wiki.python.org/moin/GuiProgramming (https://wiki.python.org/moin/GuiProgramming) Mark Roseman, Modern Tkinter for Busy Python Developers Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine users as very intelligent but very busy (Alan Cooper, About Face 2.0) No matter how cool your interface is, less of it would be better (j.w.) Im większy jest obiekt na ekranie i im bliżej kursora myszki się znajduje, tym łatwiej w niego kliknąć (prawo Fitta) dobry interfejs graficzny czyni program łatwym i intuicyjnym w obsłudze GUI decyduje o popularności programu tandetny program z bardzo dobrym GUI często będzie bardziej popularny niż nawet najlepszy program bez dobrego interfejsu użytkownika elementy na brzegach ekranu wydają się większe Po pierwsze nie przeszkadzać!

Transcript of Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield,...

Page 1: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

Języki skryptowe ­ Python

Wykład 9 ­ Graficzne interfejsy użytkownika

Janusz Szwabiński

Plan wykładu:

Kilka uwag na temat projektowania GUIPrzegląd bibliotek GUIPierwsze kroki w Tkinter

Materiały do wykładu:

http://tkinter.unpythonic.net/wiki/ (http://tkinter.unpythonic.net/wiki/)https://wiki.python.org/moin/GuiProgramming (https://wiki.python.org/moin/GuiProgramming)Mark Roseman, Modern Tkinter for Busy Python DevelopersMark Summerfield, Rapid GUI Programming with Python and Qt

Kilka uwag na temat projektowania GUI

Imagine users as very intelligent but very busy (Alan Cooper, About Face 2.0)

No matter how cool your interface is, less of it would be better (j.w.)

Im większy jest obiekt na ekranie i im bliżej kursora myszki się znajduje, tymłatwiej w niego kliknąć (prawo Fitta)

dobry interfejs graficzny czyni program łatwym i intuicyjnym w obsłudzeGUI decyduje o popularności programu ­ tandetny program z bardzo dobrym GUI często będziebardziej popularny niż nawet najlepszy program bez dobrego interfejsu użytkownikaelementy na brzegach ekranu wydają się większe

Po pierwsze ­ nie przeszkadzać!

Page 2: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

In [1]: from IPython.display import ImageImage(filename='images/konqueror.png')

Po drugie ­ elementy łatwe do znalezienia!

In [2]: Image(filename='images/bad-functionaloverload1.jpg')

Po trzecie ­ konwencje są dobre!

Out[1]:

Out[2]:

Page 3: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

In [3]: Image(filename='images/ui_conventions.png')

Po czwarte ­ poziomy projektowania

Każdy interfejs projektujemy na dwóch poziomach:

szata graficzna ­ układ elementów na ekraniefunkcjonalność ­ zdarzenia i ich obsługa

Podstawowymi klockami do budowy graficznej części interfejsu są kontrolki (ang. widgets):

przyciskipaski przewijaniatekstypola tekstowe...

Natomiast funkcjonalność realizuje się poprzez funkcje zwrotne (ang. callback) przypisane zdarzeniom.

Po piąte ­ papier ciągle żywy

Out[3]:

Page 4: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

In [4]: #źródło: http://www.mobiloud.com/blog/2013/01/build-app-with-no-programming/Image(filename='images/ui_paper_design.png')

Przegląd bibliotek GUI

Out[4]:

Page 5: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

Nazwa Opis URL

Tkinter

najpopularniejszy zestaw narzędzido tworzenia GUI, dołączany do każdej dystrybucjiPythona

http://tkinter.unpythonic.net/wiki/(http://tkinter.unpythonic.net/wiki/)

WxPythonbardzo popularna nakładka nabibliotekę WxWidgets

http://www.wxpython.org/ (http://www.wxpython.org/)

PyQt nakładka na bibliotekę Qt http://pyqt.sourceforge.net/ (http://pyqt.sourceforge.net/)

PyGObjectnakładka na bibliotekiGLib/GObject/GIO/GTK+

https://wiki.gnome.org/action/show/Projects/PyGObject(https://wiki.gnome.org/action/show/Projects/PyGObject)

PyFLTK nakładka na bibliotekę FLTK http://pyfltk.sourceforge.net/ (http://pyfltk.sourceforge.net/)

PyGUIpythonowa warstwa abstrakcjiwykorzystująca systemowebiblioteki GUI

http://www.cosc.canterbury.ac.nz/greg.ewing/python_gui/(http://www.cosc.canterbury.ac.nz/greg.ewing/python_gui/)

Jython dostęp do biblioteki Swing http://www.jython.org/ (http://www.jython.org/)

Sugarplatforma stanowiąca częśćprojektu OLPC

http://wiki.sugarlabs.org/ (http://wiki.sugarlabs.org/)

Więcej  pod  adresem  https://wiki.python.org/moin/GuiProgramming(https://wiki.python.org/moin/GuiProgramming)

Pierwsze kroki w Tkinter

zestaw narzędzi do tworzenia GUIelement standardowej biblioteki Pythona (https://docs.python.org/2/library/tkinter.html(https://docs.python.org/2/library/tkinter.html))interfejs do Tk GUI Toolkitłatwy w użyciuprzenośny

Pierwsze okno w Tkinter

In [2]: from Tkinter import *# otwieramy główne okno aplikacjiroot = Tk()#uruchamiamy pętlę zdarzeńroot.mainloop()

Trochę kosmetyki:

Page 6: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

In [3]: from Tkinter import *root = Tk()

# tytuł oknaroot.title(u'Witaj świecie')# rozmiar oknaroot.geometry('250x200+200+200')root.mainloop ()

Najważniejsze kontrolki

Nazwa Opis

Button prosty przycisk używany do wykonania jakiegoś polecenia lub innej operacji

Canvas "płótno", kontrolka umożliwiająca rysowanie obiektów

CheckButton reprezentuje zmienną mogącą przyjmować jedną z dwóch wartości

Entry pole do wprowadzania tekstu

Frame kontrolka używana do grupowania innych kontrolek

Label kontrolka umożliwiająca wyświetlenie tekstu lub obrazu

Listbox lista elementów do wyboru

Menu panel menu

MenuButton wpis w menu

Message kontrolka do wyświetlania tekstu (zawijanie)

RadioButtonkontrolka wyboru, występuje w grupach odpowiadających różnym wartościom tej samejzmiennej

Scale suwak do ustalania wartości numerycznej zmiennej

Scrollbar pasek przesuwania

Text wyświetlanie tekstu z formatowaniem

Kosmetyki ciąg dalszy:

In [4]: root = Tk()txt = 'Witaj świecie'root.title(txt)root.geometry('250x200+0+0')# przygotowujemy etykietęlbl = Label(root, text=txt)# umieszczamy ją u dołu ekranulbl.pack(side=BOTTOM)#uruchamiamy programroot.mainloop()

W stronę programu ­ przyciski

Page 7: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

In [4]: %%writefile progs/GUI/witaj-5.py

# -*- coding: utf-8 -*-from Tkinter import *

#funkcja zwrotnadef quit(): import sys; sys.exit() root = Tk()txt = 'Witaj świecie'root.title(txt)root.geometry('250x200+0+0')#etykieta wstawiona u góry ekranulbl = Label(root,text=txt)lbl.pack(side=TOP)#przyciskbtn = Button(root, text="Koniec", command=quit)#wstawiamy go u dołu ekranubtn.pack(side=BOTTOM)#uruchamiamy pętlę zdarzeńroot.mainloop()

In [5]: !python progs/GUI/witaj-5.py

własność command obiektu Button definiuje funkcję zwrotną, czyli akcję, która zostanie wykonanapo naciśnięciu przyciskujego naciśnięcie wyłapywane jest w pętli zdarzeń (mainloop())

To samo tylko w ujęciu obiektowym:

Overwriting progs/GUI/witaj-5.py

Page 8: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

In [6]: %%writefile progs/GUI/witaj-6.py

# -*- coding: utf-8 -*-

from Tkinter import *

class Example: def __init__(self,master): self.lbl = Label(master,text="Witaj świecie!") self.lbl.pack(side=TOP) self.btn = Button(master,text="Koniec",command=self.quit) self.btn.pack(side=BOTTOM) def quit(self): import sys; sys.exit() if __name__ == "__main__": root = Tk() root.title("Witaj świecie") root.geometry('250x200+0+0') ex = Example(root) root.mainloop()

In [6]: !python progs/GUI/witaj-6.py

W stronę programu ­ menu

Overwriting progs/GUI/witaj-6.py

Page 9: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

In [8]: %%writefile progs/GUI/witaj-7.py

# -*- coding: utf-8 -*-

from Tkinter import *

def nf(): print "Tworzę nowy plik..."

def makeFileMenu(): # menu "Plik" File_button = Menubutton(mBar, text='Plik', underline=0) File_button.pack(side=LEFT, padx="1m") File_button.menu = Menu(File_button)

#dodaj pozycje "Nowy" i "Zakończ" w menu "Plik" File_button.menu.add_command(label='Nowy...', underline=0, command=nf) File_button.menu.add_command(label='Zakończ', underline=0, command='exit') #wskaźnik powrotny do menu File_button['menu'] = File_button.menu return File_button

root = Tk()root.title('Witaj świecie')root.geometry('250x200+0+0')

# menumBar = Frame(root, relief=RAISED, borderwidth=2)mBar.pack(side=TOP,fill=X)File_button = makeFileMenu()mBar.tk_menuBar(File_button)

# etykietalbl = Label(root,text="Witaj świecie")lbl.pack(side=BOTTOM)

root.mainloop()

In [7]: !python progs/GUI/witaj-7.py

I jeszcze jeden przykład menu:

Overwriting progs/GUI/witaj-7.py

Tworzę nowy plik...Tworzę nowy plik...Tworzę nowy plik...

Page 10: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

In [20]: %%writefile progs/GUI/witaj-7a.py# -*- coding: utf-8 -*-

from Tkinter import *def donothing(): filewin = Toplevel(root) button = Button(filewin, text="Do nothing button") button.pack() root = Tk()menubar = Menu(root)filemenu = Menu(menubar, tearoff=0)filemenu.add_command(label="New", command=donothing)filemenu.add_command(label="Open", command=donothing)filemenu.add_command(label="Save", command=donothing)filemenu.add_command(label="Save as...", command=donothing)filemenu.add_command(label="Close", command=donothing)

filemenu.add_separator()

filemenu.add_command(label="Exit", command=root.quit)menubar.add_cascade(label="File", menu=filemenu)editmenu = Menu(menubar, tearoff=0)editmenu.add_command(label="Undo", command=donothing)

editmenu.add_separator()

editmenu.add_command(label="Cut", command=donothing)editmenu.add_command(label="Copy", command=donothing)editmenu.add_command(label="Paste", command=donothing)editmenu.add_command(label="Delete", command=donothing)editmenu.add_command(label="Select All", command=donothing)

menubar.add_cascade(label="Edit", menu=editmenu)helpmenu = Menu(menubar, tearoff=0)helpmenu.add_command(label="Help Index", command=donothing)helpmenu.add_command(label="About...", command=donothing)menubar.add_cascade(label="Help", menu=helpmenu)

root.config(menu=menubar)root.mainloop()

In [8]: !python progs/GUI/witaj-7a.py

W stronę programu ­ Canvas i Scale

In [21]: %%writefile progs/GUI/demo-1.py

# -*- coding: utf-8 -*-

from Tkinter import *import string

Overwriting progs/GUI/witaj-7a.py

Page 11: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

class Demo(Frame): def createWidgets(self): #przycisk "Koniec" self.QUIT = Button(self, text='KONIEC', foreground='red', command=self.quit) self.QUIT.pack(side=LEFT, fill=BOTH)

# Scena self.draw = Canvas(self, width="5i", height="5i") # Kontrola prędkości self.speed = Scale(self, orient=HORIZONTAL, label="Prędkość piłki", from_=-100, to=100) self.speed.pack(side=BOTTOM, fill=X)

# Piłka self.ball = self.draw.create_oval("0i", "0i", "0.10i", "0.10i", fill="red") self.x = 0.05 self.y = 0.05 self.velocity_x = 0.3 self.velocity_y = 0.5

self.draw.pack(side=LEFT)

def moveBall(self, *args): #zmień prędkość na przeciwną na brzegach canvas if (self.x > 5.0) or (self.x < 0.0): self.velocity_x = -1.0 * self.velocity_x if (self.y > 5.0) or (self.y < 0.0): self.velocity_y = -1.0 * self.velocity_y

#zmiana położenia odpowiadająca prędkości deltax = (self.velocity_x * self.speed.get() / 100.0) deltay = (self.velocity_y * self.speed.get() / 100.0) self.x = self.x + deltax self.y = self.y + deltay

#rysowanie piłki self.draw.move(self.ball, "%ri" % deltax, "%ri" % deltay) self.after(10, self.moveBall)

def __init__(self, master=None): Frame.__init__(self, master) Pack.config(self) self.createWidgets() self.after(10, self.moveBall)

demo = Demo()

demo.mainloop()

In [9]: !python progs/GUI/demo-1.py

Overwriting progs/GUI/demo-1.py

Page 12: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

Zarządzanie geometrią

packnajprostszy (najszybszy) sposóbdzięki kontenerowi Frame można budować skomplikowane interfejsy

gridprzypomina tabele HTMLumożliwia tworzenie skomplikowanych interfejsówkażda kontrolka ma przynajmniej jedną komórkękontrolki mogą się rozciągać na wiele komórek

placenajbardziej precyzyjny sposóbrozmieszczenie kontrolek na podstawie podanych współrzędnychuciążliwe (raczej nie dla leniwych)

Przykład wykorzystania funkcji grid:

In [23]: %%writefile progs/GUI/demo-2.py

# -*- coding: utf-8 -*-

from Tkinter import *

root = Tk()root.title("Formularz")#Label(root,text="Imię").grid(row=0,sticky=W)Label(root,text="Imię").grid(row=0)Label(root,text="Nazwisko").grid(row=1,sticky=W)

e1 = Entry(root)e2 = Entry(root)e1.grid(row=0,column=1)e2.grid(row=1,column=1)

root.mainloop()

In [24]: !python progs/GUI/demo-2.py

Obsługa zdarzeń

prosta i wygodnafunkcje zwrotne można przypisać każdemu zdarzeniu dla każdej kontrolkifunkcjami zwrotnymi mogą być:

wyrażenia lambdazwykłe funkcje użytkownikametody

zdarzenia reprezentowane są za pomocą tzw. deskryptorów

Overwriting progs/GUI/demo-2.py

Page 13: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

<Modyfikator-Typ-Kwalifikator>dopuszczalnych jest wiele modyfikatorów jednocześnienie wszystkie sekcje deskryptora są wymagane

Typy zdarzeń:

Źródło Zdarzenia

Klawiatura KeyPress, KeyRelease

Myszka ButtonPress, ButtonRelease, Motion, Enter, Leave, MouseWheel

OknoVisibility, Unmap, Map, Expose, FocusIn, FocusOut, Circulate, Colourmap, Gravity, Reparent, Property, Destroy, Activate, Deactivate

Kwalifikatory ­ myszka:

Wartość Opis

1 lewy przycisk

2 środkowy przycisk

3 prawy przycisk

4 kółko w górę

5 kółko w dół

Kwalifikatory ­ klawiatura:

Wartość Opis

A­Z poszczególne litery

BackSpace klawisz BackSpace

... ...

Modyfikatory:

Źródło Wartość

myszka Double, Triple, B1, B2,...

klawiatura Control, Shift, Alt, Meta

Any

Przykłady deskryptorów:

<Double-Button-1> ­ powójne kliknięcie lewym przyciskiem myszki<KeyPress-Tab> ­ wciśnięcie tabulatora<Control-B1-Motion> ­ przeciąganie myszki z wciśniętym jej lewym przyciskiem i wciśniętymklawiszem Control

Propagacja zdarzeń:

Page 14: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

cztery poziomy dowiązaniakontrolkaokno nadrzędne (root lub TopLevel)klasaaplikacja

zdarzenie "przechodzi" w dół powyższego łańcucha aż do natrafienia na odpowiednią funkcjęzwrotnąaby przerwać dalszą propagację, funkcja zwrotna musi zwrócić wartość break

Dowiązania:

do kontrolki widget.bind(descriptor, callback, add=None)do okna nadrzędnego toplevel.bind(descriptor, callback, add=None)do klasy widget.bind_class(class_name, descriptor, callback, add=None)do całej aplikacji widget.bind_all(descriptor, callback, add=None)

In [26]: %%writefile progs/GUI/demo-3.py

# -*- coding: utf-8 -*-

from Tkinter import *

root = Tk()

def callback(event): print "Kliknąłeś w punkcie: ", event.x, event.y, "w chwili: ", event.time frame = Frame(root, width=100, height=100)frame.bind("<Button-1>", callback)frame.pack() root.mainloop()

In [11]: !python progs/GUI/demo-3.py

Overwriting progs/GUI/demo-3.py

Kliknąłeś w punkcie: 17 22 w chwili: 866125018Kliknąłeś w punkcie: 78 27 w chwili: 866125674Kliknąłeś w punkcie: 41 49 w chwili: 866126242Kliknąłeś w punkcie: 78 66 w chwili: 866126738Kliknąłeś w punkcie: 15 84 w chwili: 866127810Kliknąłeś w punkcie: 22 47 w chwili: 866128482Kliknąłeś w punkcie: 22 47 w chwili: 866128674Kliknąłeś w punkcie: 22 47 w chwili: 866128842Kliknąłeś w punkcie: 22 47 w chwili: 866129018Kliknąłeś w punkcie: 22 47 w chwili: 866129202

Page 15: Języki skryptowe Pythonprac.im.pwr.wroc.pl/~szwabin/assets/prog/lec/9.pdf · Mark Summerfield, Rapid GUI Programming with Python and Qt Kilka uwag na temat projektowania GUI Imagine

Wybrane własności zdarzeń:

Własność Opis

num numer przycisku myszki, który został wciśnięty

height/width wysokość/szerokość wyeksponowanego okna

keycode kod wciśniętego klawisza

time czas wystąpienia zdarzenia

x/y położenie myszki względem kontrolki

x_root/y_root położenie myszki względem okna głównego

char wciśnięty klawisz (jako znak)

widget kontrolka, dla której wystąpiło zdarzenie

W stronę programu ­ wczytywanie plików

In [2]: %%writefile progs/GUI/demo-4.py

from Tkinter import *from tkFileDialog import askopenfilename

root = Tk()filename = askopenfilename(filetypes=[("allfiles","*"),("pythonfiles","*.py")])print filename

In [13]: !python progs/GUI/demo-4.py

Overwriting progs/GUI/demo-4.py

/home/szwabin/Dropbox/Zajęcia/PythonIntro/9_GUI/9_gui.ipynb