Для Python существует множество библиотек для создания графического интерфейса пользователя (GUI). Здесь будет рассмотрена только одна -- Tkinter. Это привязка Python к Tcl/Tk. Она поставляется вместе с Python. Для построения графических интерфейсов частенько используют построители (Builders), но мы рассмотрим "ручной" вариант GUI-программирования: он поможет лучше уяснить принципы работы графических приложений.
Почти все современные графические интерфейсы общего назначения строятся по модели WIMP - Window, Icon, Menu, Pointer (окно, иконка, меню, курсор [обычно мыши]). Внутри окон рисуются элементы графического интерфейса, именуемые "виджетами" (widget - штучка).
Вот лишь некоторые виджеты из Tcl/Tk:
Toplevel
Button
Canvas
Checkbutton
Entry
Frame
Label
Listbox
Menu
Menubutton
Message
Label
, но позволяет заворачивать длинные строки и легко меняет свой размер Radiobutton
Scale
Scrollbar
Text
Примеры виджетов (порождены этой программой)
Рассмотрим подробнее следующую программу:
from Tkinter import * import math def Square(radius): return math.pi * radius**2 def calculate_square(): radius = float(radius_entry.get()) try: square = "%11.3f" % Square(radius) except: square = "?" square_label.configure(text=square) root = Tk() root.title("Площадь круга") frame = Frame(root) frame.pack() radius_entry = Entry(frame, width=10) radius_entry.grid(row=0, column=0) square_label = Label(frame, text="?") square_label.grid(row=0, column=1) eval_button = Button(frame, text="Calculate", width=10, command=calculate_square) eval_button.grid(row=1, column=0) exit_button = Button(frame, text="Exit", width=10, command=root.destroy) exit_button.grid(row=1, column=1) root.mainloop()
Результаты работы этой программы:
Заметьте в примере выше способ вызова функции для обработки
собятия нажатие на кнопку: он задается именованным
аргументом command
. Аналогично кнопка
exit_button
выполняет закрытие окна (и всего приложения),
так как ей задан метод destroy
объекта root
.
Окно графического приложения состоит из вложенных друг в друга виджетов. Для примера выше дерево виджетов выглядит так:
Расположением виджетов управляют менеджеры расположения. В Tkinter их три разновидности:
pack
grid
place
В основном GUI-приложения состоят из двух фаз: (I) фазы генерации интерфейса и (II) фазы цикла обработки событий. На фазе генерации интерфейса каждый виджет создается (при этом возможно задание некоторых аргументов); прикрепляется одним из указанных трех методов к своему хозяину. Виджеты появляются на экране только в результате прикрепления к уже прикрепленным виджетам. Для запуска фазы II используется метод mainloop() Toplevel-виджета. На второй фазе изменение свойств виджетов производится с помощью метода configure().
Каждый виджет может обрабатывать возникающие в нем события: движения курсора мыши, ввод с клавиатуры и т.п. Основные события в Tkinter:
KeyPress
KeyRelease
ButtonPress
ButtonRelease
Motion
Enter
Leave
MouseWheel
Visibility
FocusIn
FocusOut
Reparent
Destroy
Activate
Deactivate
Описание события задается строкой (часть элементов может быть опущена):
<модификаторы-тип-детализация>
Например,
Пример программы, в которой текстовое поле перехватывает движения мыши и пишет атрибуты события (event):
from Tkinter import * tk = Tk() txt = Text(tk) txt.pack() def give_info(event): # event.widget - виджет, в котором произошло событие txt.delete("1.0", END) items = event.__dict__.items() items.sort() for k, v in items: txt.insert(END, "%s: %s\n" % (k, v)) txt.bind("<Motion>", give_info) tk.mainloop()
Результат:
Конечно, кажды виджет имеет большое количество всевозможных
параметров, которые можно задавать и затем изменять.
(Например, так мы изменяли текст в этикетке:
Для удобства связи между виджетами применяются специальные
переменные (они бывают четырех типов:
BooleanVar
,
StringVar
,
FloatVar
,
IntegerVar
-- по представляемым ими типам.
Особенность этих переменных в том, что использующие их виджеты могут изменять свое состояние в зависимости от этих переменных и, наоборот, переменные могут изменять состояние в зависимости от изменения состояния виджетов под действием пользователя графического интерфейса.
Следующая программа dclock.py иллюстрирует работу переменной, в результате чего мы получаем "электронные часы":
Напоследок важное замечание: не гонитесь за использованием как можно большего числа различных штучек, так как удобство интерфейса зависит не от этого.