Рис. 1.6. Получение ввода пользователя
Программный код, представленный выше, демонстрирует множество особенностей программирования графических интерфейсов, но модуль tkinter обладает намного более широкими возможностями, чем можно было бы заключить из этих примеров. В модуле tkinter реализованы более 20 виджетов и еще множество способов дать пользователю возможность вводить данные, включая элементы ввода многострочного текста, «холсты» для рисования, раскрывающиеся меню, радиокнопки и флажки, полосы прокрутки, а также механизмы управления размещением виджетов и обработки событий. Помимо модуля tkinter в состав стандартной библиотеки языка Python входят также расширения, такие как PMW, и инструменты Tix и ttk, которые добавляют дополнительные виджеты для использования в графических интерфейсах, построенных на базе tkinter, и позволяющие придать интерфейсу еще более профессиональный внешний вид. Чтобы в общих чертах продемонстрировать имеющиеся возможности, давайте задействуем модуль tkinter для создания интерфейса к нашей базе данных.
Графический интерфейс к хранилищу
Первое, что необходимо сделать для нашего приложения баз данных, - это создать графический интерфейс для просмотра хранящихся данных (форму с именами и значениями полей) и реализовать способ извлечения записей по ключу. Также было бы полезно иметь возможность изменять значения полей в записях и добавлять новые записи, заполняя пустую форму. Для простоты мы реализуем единый графический интерфейс, позволяющий решать все эти задачи. На рис. 1.7 изображено окно, которое мы создадим, отображенное в Windows 7, с содержимым записи, полученной по ключу sue (здесь снова используется хранилище в том состоянии, в каком мы его оставили в последний раз). Данная запись в действительности является экземпляром нашего класса, сохраненным в файле хранилища, но пользователю это должно быть безразлично.
Рис. 1.7. Главное окно сценария peoplegui.py
Реализация графического интерфейса
Кроме того, чтобы не усложнять пример, допустим, что все записи в базе данных имеют один и тот же набор полей. Было бы совсем несложно создать более универсальную реализацию, способную работать с любыми наборами полей (и при этом создать универсальный инструмент конструирования форм с графическим интерфейсом), но мы отложим реализацию до следующих глав в этой книге. Сценарий в примере 1.29 реализует графический интерфейс, изображенный на рис. 1.7.
Пример 1.29. PP4E\Preview\peoplegui.py
Реализация графического интерфейса для просмотра и изменения экземпляров класса, хранящихся в хранилище;
хранилище находится на том же компьютере, где выполняется сценарий в виде одного или более локальных файлов;
from tkinter import *
from tkinter.messagebox import showerror
import shelve
shelvename = ‘class-shelve’
fieldnames = (‘name’, ‘age’, ‘job’, ‘pay’)
def makeWidgets(): global entries window = Tk()
window.title(‘People Shelve’) form = Frame(window) form.pack() entries = {}
for (ix, label) in enumerate((‘key’,) + fieldnames): lab = Label(form, text=label) ent = Entry(form) lab.grid(row=ix, column=0) ent.grid(row=ix, column=1) entries[label] = ent
Button(window, text=”Fetch”, command=fetchRecord).pack(side=LEFT) Button(window, text=”Update”, command=updateRecord).pack(side=LEFT) Button(window, text=”Quit”, command=window.quit).pack(side=RIGHT) return window
def fetchRecord():
key = entries[‘key’].get() try:
record = db[key] # извлечь запись по ключу, отобразить в форме
except:
showerror(title=’Error’, message=’No such key!’) else:
for field in fieldnames:
entries[field].delete(0, END)
entries[field].insert(0, repr(getattr(record, field)))
def updateRecord():
key = entries[‘key’].get() if key in db:
record = db[key] # изменяется существующая запись
else:
from person import Person # создать/сохранить новую запись
record = Person(name=’?’, age=’?’) # evaclass="underline" строки должны
# заключаться в кавычки
for field in fieldnames:
setattr(record, field, eval(entries[field].get())) db[key] = record
db = shelve.open(shelvename) window = makeWidgets() window.mainloop()
db.close() # в эту точку программа попадает при щелчке на кнопке Quit # или при закрытии окна
Для размещения надписей и полей ввода в этом сценарии вместо метода pack используется метод grid. Как мы увидим далее, этот метод располагает виджеты по столбцам и строкам сетки, что обеспечивает более естественное для форм выравнивание надписей и полей ввода по горизонтали. Далее мы также увидим, что неплохого размещения виджетов на форме можно добиться и с помощью метода pack, добавив вложенные контейнеры для размещения виджетов по горизонтали и надписи фиксированной длины. Пока графический интерфейс никак не обрабатывает изменение размеров окна (для этого необходимы параметры настройки, которые мы будем исследовать позже), тем не менее объем программного кода реализации такой возможности при использовании любого из методов, grid или pack, будет примерно один и тот же.