Выбрать главу

Обратите внимание, что в конце сценария сначала открывается хранилище, как глобальная переменная, а затем запускается графический интерфейс - хранилище остается открытым на протяжении всего времени работы графического интерфейса (функция mainloop возвращает управление только после закрытия главного окна). Как будет показано в следующем разделе, такое удержание хранилища в открытом состоянии существенно отличает графический интерфейс от веб-интерфейса, где каждая операция обычно является автономной программой. Обратите также внимание, что использование глобальных переменных делает программный код более простым, но непригодным для использования вне контекста нашей базы данных; подробнее об этом мы поговорим ниже.

Пользование графическим интерфейсом

Построенный нами графический интерфейс достаточно прост, но он позволяет просматривать и изменять содержимое файла хранилища без ввода программного кода. Чтобы извлечь запись из хранилища и отобразить ее в графическом интерфейсе, необходимо ввести ключ в поле key (ключ) и щелкнуть на кнопке Fetch (Извлечь). Чтобы изменить запись, необходимо изменить содержимое полей записи после ее извлечения из хранилища и щелкнуть на кнопке Update (Изменить) - значения из полей ввода будут сохранены в базе данных. А чтобы добавить новую запись, необходимо заполнить все поля ввода новыми значениями и щелкнуть на кнопке Update (Изменить) - в хранилище будет добавлена новая запись с указанным ключом и значениями полей.

Другими словами, поля ввода служат одновременно и для отображения, и для ввода. На рис. 1.8 изображена форма после добавления новой записи (щелчком на кнопке Update (Изменить)), а на рис. 1.9 - диалог с сообщением об ошибке, когда пользователь попытался извлечь запись с ключом, отсутствующим в хранилище.

Рис. 1.8. Интерфейсpeoplegui.py после добавления нового объекта

Рис. 1.9. Диалог peoplegui.py с сообщением об ошибке

Обратите внимание, что для отображения значений полей, извлеченных из хранилища, здесь также используется функция repr, а для преобразования значений полей в объекты Python, перед тем как они будут записаны в хранилище, - функция eval. Как уже упоминалось выше, это потенциально опасно, так как открывает возможность ввести в поля ввода злонамеренный программный код, но мы пока не будем касаться этой проблемы.

Однако имейте в виду, что при такой реализации строковые значения, вводимые в поля ввода, должны заключаться в кавычки, так как содержимое всех полей ввода, кроме поля key (ключ), интерпретируется как программный код на языке Python. Фактически, чтобы определить

новое значение, в поле ввода можно ввести произвольное выражение на языке Python. Например, если в поле name (имя) ввести выражение Tom'*3, после щелчка на кнопке Update (Изменить) в записи будет сохранено имя TomTomTom. Чтобы убедиться в этом - извлеките запись из хранилища.

Несмотря на наличие графического интерфейса, позволяющего просматривать и изменять записи, мы по-прежнему можем проконтролировать свои действия, открыв и проверив файл хранилища в интерактивном режиме или запустив сценарий, такой как dump_db_classes. py, представленный в примере 1.19. Не забывайте: несмотря на то, что теперь мы можем просматривать записи с помощью графического интерфейса, сама база данных является файлом хранилища, содержащим объекты Python экземпляров классов, поэтому обращаться к ним может любой программный код на языке Python. Ниже приводятся результаты запуска сценария dump_db_classes.py после изменения существующих и добавления новых объектов с помощью графического интерфейса:

...\PP4E\Preview> python dump_db_classes.py

sue =>

Sue Jones 50000.0 bill => bill 9999 nobody =>

John Doh None tomtom =>

Tom Tom 40000 tom =>

Tom Doe 90000 bob =>

Bob Smith 30000 peg =>

1 4 Smith Doe

Пути усовершенствования

Построенный нами графический интерфейс справляется со своей задачей, тем не менее в него можно внести множество разных усовершенствований:

• На настоящий момент графический интерфейс представляет собой набор функций, использующих глобальный список полей (entries) ввода и глобальное хранилище (db). Вместо этого мы могли бы передать db в вызов функции makeWidgets и организовать передачу обоих этих объектов обработчикам событий в виде аргументов, воспользовавшись приемом с инструкцией lambda из предыдущего раздела. Хотя для таких маленьких сценариев это и не так важно, стоит иметь в виду, что явное определение подобных внешних зависимостей делает программный код более простым для понимания и повторного использования в других контекстах.