Тонкости использования языка Python: Часть 9. Разработка GUI-приложений

Статья является частью миницикла, посвященного тонким вопросам применения Python и разработки приложений на этом языке. В статье представлен обзор инструментов для создания GUI-приложений, доступных в Python, и общие принципы построения таких приложений.

Олег Цилюрик, преподаватель тренингового отделения, Global Logic

Фото автораОлег Иванович Цилюрик, много лет был разработчиком программного обеспечения в крупных центрах разработки: ВНИИ РТ, НПО "Дельта", КБ ПМ. Последние годы работал над проектами в области промышленной автоматики, IP телефонии и коммуникаций. Автор нескольких книг. Преподаватель тренингового отделения международной софтверной компании Global Logic.



10.01.2014

Введение

Ещё одной привлекательной особенностью Python является простота, скорость и гибкость в создании приложений с графическим интерфейсом пользователя (GUI). Это преимущество связано не только с большим количеством поддерживаемых графических библиотек: Tkinter, PyQt, PyGTK, wxPython, Pygames и др. Основная причина заключается в интерпретирующей природе платформы Python, так как из-за доступности Python-кода внешний вид графического приложения всегда можно изменить или дополнить. А весь интерфейс из Python-кода к фактической реализации GUI скрыт внутри модулей библиотеки Python.

Однако этим преимущества разработки GUI-приложений именно на Python не исчерпываются, так как Python предлагает:

  • независимость от платформы: графическое приложение, разработанное на Python в одной ОС (например, Linux) будет с большой степенью вероятности адекватно работать в любой другой среде (Windows, MacOS, Solaris, FreeBSD, …) или потребует для этого незначительных доработок;
  • GUI-приложения в основном являются диалоговыми, т.е. предназначенными для взаимодействия с пользователем, при этом скорость работы приложения определяется действиями пользователя, и здесь исчезает один из основных формальных недостатков Python — его замедленность по сравнению с C или C++;
  • из-за простоты интеграции Python с C/C++, визуальные компоненты проекта (GUI) могут быть написаны на Python с учётом скорости разработки (frontend), а внутренние процедуры для обработки данных — на C/C++ (backend).

В этой и последующей статьях мы обсудим различные мульти-платформенные технологии создания GUI-приложений, доступные для Python-программистов.


GUI-приложения

Основной целью данной статьи будет поверхностный обзор различных вариантов, доступных при выборе инструментария для разработки GUI-приложений. Так программист сможет определить, какой инструмент наиболее подходит для решения конкретной задачи. Подобная постановка задачи связана ещё и с тем, что для всех многочисленных инструментов для разработки GUI-приложений существуют (более или менее удачные и полные) руководства. Но практически отсутствуют материалы, в которых бы выполнялся сравнительный анализ разных подходов.

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

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

Такой подход называется событийно управляемым программированием (event driven programming). Все GUI приложения, независимо от используемой графической технологии, будут использовать этот общий шаблон.

Исходя из подобной сжатой формулировки, в дальнейшем нас будут интересовать только вопросы применимости, выбора, установки и начала работы с инструментом. Но иногда мы будем обращаться и к специфическим требованиям для определённых инструментов по оформлению функций обработчиков событий. Вопросы компоновки виджетов в конкретных средах рассматриваться не будут.

Примечание. Внешний вид одного и того же GUI-приложения может отличаться при запуске в разных средах (операционных системах, менеджерах рабочего стола, оконных менеджерах). Это обусловлено тем, что фактическую прорисовку виджетов обеспечивают не графические библиотеки, а оконный менеджер графической системы.


Tkinter

Tkinter является стандартным модулем Python и входит в состав его стандартной библиотеки. Модуль Tkinter позиционируется для быстрого написания GUI-приложений. Его описание доступно в встроенной справочной системе pydoc.

Примечание. Справочная система pydoc доступна только в операционных системах семейства UNIX (Linux и др.). Для обращения к ней используется команда:

$ pydoc -p8080

Значение опции -p определяет порт TCP, который можно переопределить. После этого любым Web-браузером можно подключиться к этой справочной системе, набрав в адресной строке браузера: http://localhost:8080. В реализации Python для ОС Windows есть своя справочная система, устанавливаемая вместе с Python.

Хотя модуль Tkinter считается входящим в состав библиотеки стандартных модулей Python, может потребоваться его отдельная инсталляция (или, как минимум, проверка его наличия), так как обычно Tkinter не устанавливается при установке Python. Кроме того существуют его различные версии специально для Python 2 и Python 3.

  • в .rpm дистрибутивах (Fedora и др.):
    # yum list tkinter.*
    ...
    Установленные пакеты
    tkinter.i686                                      2.7.3-7.2.fc17
    
    # yum install python3-tkinter.i686
    ...
    Установлено:
      python3-tkinter.i686 0:3.2.3-7.fc17
  • в .deb дистрибутивах (Debian и др.):
    $ aptitude search python-tk
    p python-tk  - Tkinter - написание Tk программ на Python
    p python-tk-dbg  - Tkinter - Writing Tk applications with Python (debug extension)
    p python-tksnack  - Sound extension to Tcl/Tk and Python/Tkinter - Python library
    # apt-get install python-tk
    …
    Настраивается пакет python-tk (2.7.3-1) …
    
    $ aptitude search python3-tk
    p python3-tk  - Tkinter - Writing Tk applications with Python 3.x
    p python3-tk-dbg  - Tkinter - Writing Tk applications with Python 3.x 
    (debug extension)
    # apt-get install python3-tk
    ...
    Настраивается пакет python3-tk (3.2.3-1) …

Как видно из примера, иногда могут возникнуть сложности из-за разных наименований пакетов в различных дистрибутивах, но эта проблема легко решается.

Примечание. Существует ещё одна особенность использования стандартного модуля Tkinter, так в версиях Python 2.X он должен записываться в написании Tkinter:

from Tkinter import Label

Но в версиях Python 3.X он должен записываться в написании tkinter, и та же строка будет выглядеть по-другому:

from tkinter import Label

Если же необходимо обеспечить совместимость между версиями, то строки импорта могут быть записаны так:


try:
    from tkinter import *
except ImportError:
    from Tkinter import *

В качестве иллюстрации будет использована не слишком сложная (но и не тривиальная) задача угадывания пользователем случайного числа, генерируемого программой. Вариант кода для Python 3, реализующего задачу при использовании Tkinter, в листинге 1 (см. файл gntm.py в архиве python_gui.tgz в разделе "Материалы для скачивания"):

Листинг 1. Оконное приложение, использующее Tkinter
#!/usr/bin/python3
# -*- coding: utf-8 -*-

from sys import argv
import random
import math
from tkinter import *  

val_range = 0    # диапазон числа
secret = 0       # угадываемое число
guesses = 0      # число попыток
limits = 0       # макс. число попыток

def new_game():
    global secret, guesses, limits
    msg[ 'text' ] = ' ' * 100 + \
        '\nНовая игра, диапазон: [ 0...{} )\n'.format( val_range )
    secret = random.randrange( 0,val_range )
    guesses = 0
    limits = int( math.ceil( math.log( val_range, 2 ) ) )
    
def input_guess( event ):
    global guesses
    if guesses < 0 :            # признак завершённой игры
        msg[ 'text' ] += 'Начните новую игру...\n'
        ent.delete( 0, END )
        return
    try :
        value = int( ent.get() )
    except ValueError:
        msg[ 'text' ] += 'Ошибка: значение должно быть целочисленным!\n'
        ent.delete( 0, END )
        return;
    ent.delete( 0, END )
    guesses += 1
    if value < secret :
         msg[ 'text' ] += '{} - это меньше ...\n'.format( value )
    elif value > secret :
        msg[ 'text' ] += '{} - это больше ...\n'.format( value )
    else :
        msg[ 'text' ] += 'Игрок выиграл!\n'
        guesses = -1             # признак завершённой игры
        return
    if guesses >= limits :        
        msg[ 'text' ] += 'Компьютер выиграл! Загадно было {}\n'.format( secret )
        guesses = -1             # признак завершённой игры
        return
        
root = Tk()
root.title( 'Угадай число!' )    # окно пиложения
root.geometry( '500x240' )
Label( root, text='Вводите следующее число...' ).pack( side=TOP )
ent = Entry( root, width=10 )    # поле ввода
ent.pack( side=TOP )
ent.focus() # избавить от необходимости выполнять щелчок мышью для фокуса
ent.bind( '<Return>', input_guess )
Button( root, text=' Новая игра ', command=new_game ).pack( side=BOTTOM )
msg = Message( root, bg='white', fg='black', width=400, borderwidth=0 )
msg.pack( side=TOP )             # окно результата

val_range = ( len( argv ) > 1 and int( argv[ 1 ] ) ) or 100 # параметр - диапазон
new_game()
root.mainloop()

Здесь с помощью менеджера компоновки Tkinter при вызове pack() в приложение было добавлено несколько виджетов: поле ввода, кнопка и текстовые поля вывода.

На рисунке 1 показан результат запуска данного приложения.

$ ./gntm.py 400
...
Рисунок 1. Пример GUI-приложения, основанного на библиотеке Tkinter

Руководство по использованию Tkinter изложено в 1-м томе книге Марка Лутца (см. раздел "Ресурсы"). Представленной информации будет вполне достаточно для квалифицированной работы с Tkinter.

Следует также иметь в виду некоторые ограничения этого способа построения графических приложений, так как Tkinter основан на инструментарии Tk, который поддерживает несколько устаревший вид виджетов. По умолчанию, он не поддерживает некоторые сложные виджеты, например, деревья или окна с закладками и др.


PyQt

Пакет (несколько различных модулей) PyQt являются интерфейсом из Python к графической системе Qt4. Для использования PyQt потребуется установить дополнительные модули Python.

Для Python 2:

$ aptitude search python-qt
p   ipython-qtconsole           - enhanced interactive Python shell - Qt console
p   python-qt4               - Python bindings for Qt4
p   python-qt4-dbg           - Python bindings for Qt4 (debug extensions)
p   python-qt4-dbus          - D-Bus Support for PyQt4
p   python-qt4-dbus-dbg      - D-Bus Support for PyQt4 (debug extensions)
p   python-qt4-dev           - Development files for PyQt4
p   python-qt4-doc           - документация и примеры для PyQt4
p   python-qt4-gl            - Python bindings for Qt4's OpenGL module
p   python-qt4-gl-dbg        - Python bindings for Qt4's OpenGL module (debug extension)
p   python-qt4-phonon        - Python bindings for Phonon
p   python-qt4-phonon-dbg    - Python bindings for Phonon (debug extensions)
p   python-qt4-sql           - интерфейс Python к модулю Qt4 SQL
p   python-qt4-sql-dbg       - Python bindings for PyQt4's SQL module (debug extension)

$ sudo apt-get install python-qt4 python-qt4-dev python-qt4-doc
...

Для Python 3:

$ aptitude search  python3-pyqt*
p   python3-pyqt4              - Python3 bindings for Qt4
p   python3-pyqt4-dbg          - Python3 bindings for Qt4 (debug extensions)
p   python3-pyqt4.phonon       - Python3 bindings for Phonon
p   python3-pyqt4.phonon-dbg   - Python3 bindings for Phonon (debug extensions)
p   python3-pyqt4.qsci         - Python 3 bindings for QScintilla 2
p   python3-pyqt4.qtopengl     - Python 3 bindings for Qt4's OpenGL module
p   python3-pyqt4.qtopengl-dbg - Python 3 bindings for Qt4's OpenGL module (debug...
p   python3-pyqt4.qtsq         - Python3 bindings for PyQt4's SQL module
p   python3-pyqt4.qtsql-dbg    - Python3 bindings for PyQt4's SQL module (debug...

# apt-get install python3-pyqt4
...

Далее будут использоваться простые примеры, которых, тем не менее, вполне достаточно для понимания логики приложения и начала работы с этими инструментами. Ниже в листинге 2 показано простейшее приложение, написанное с использованием PyQt (файл hw3pyqt.py в архиве python_gui.tgz ).

Листинг 2. Пример PyQt-приложения
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
from PyQt4.QtGui import *

# Каждое приложение должно создать объект QApplication
# sys.argv - список аргументов командной строки
application = QApplication(sys.argv)

# QWidget - базовый класс для всех объектов интерфейса пользователя;
# если использовать для виджета конструктор без родителя, такой виджет станет окном
widget = QWidget()

widget.resize(320, 240)                 # изменить размеры виджета
widget.setWindowTitle("Hello, World!")  # установить заголовок
widget.show()                           # отобразить окно на экране

sys.exit(application.exec_())           # запуск основного цикла приложения

В этом примере присутствуют все показанные ранее признаки и структура событийно- управляемого приложения, а главное отличие между листингами 1 и 2 исключительно внешнее и заключается в именах вызовов API, но сама логика построения приложения остаётся неизменной.

На рисунке 2 показан результат запуска этого приложения:

Рисунок 2. Пример GUI-приложения, основанного на библиотеке PyQt

Проект PyQt имеет параллельно развивающееся ответвление PySide, которое некоторые разработчики считают более удобным, чем оригинальный PyQt.


PyGTK

Проект PyGTK – это ещё один мульти-платформенный GUI инструмент, использующий библиотеки GTK+. В листинге 3 показан пример PyGTK-приложения (файл hw3gtk.py в архиве python_gui.tgz ), демонстрирующий что PyGTK также полагается на событийно-управляемый подход.

Листинг 3. Пример PyGTK-приложения
#!/usr/bin/env python
#-*- coding: UTF-8 -*-

import gtk

def button_clicked(button):
    print 'Hello World!'

def main():
    window = gtk.Window()
    window.set_default_size(240, 180)
    window.set_title('Hello World!')
    window.connect('destroy', lambda w: gtk.main_quit())

    button = gtk.Button('Press Me')
    button.connect('clicked', button_clicked)
    button.show()

    window.add(button)
    window.present()

    gtk.main()

if __name__ == '__main__':
    main()

На рисунке 3 показан результат запуска этого примера.

Рисунок 3. Пример GUI-приложения, основанного на библиотеке PyGTK

В разделе "Ресурсы" приведены ссылки на подробную документацию по PyGTK, в том числе и на русскоязычные материалы.

Начиная с 2012 года (с версии 2.8), обёртки объектов Glib были вынесены в отдельную библиотеку — PyGObject, которая должна будет полностью вытеснить PyGTK при использовании GTK+ версии 3:

$ aptitude search python3-gi
p   python3-gi       - Python 3 bindings for gobject-introspection libraries
p   python3-gi-cairo - Python 3 Cairo bindings for the GObject library
p   python3-gi-dbg   - Python 3 bindings for gobject-introspection libraries (debug ...

После установки пакета python3-gi можно воспроизвести предыдущий пример, но уже с использованием Python 3. В листинге 4 показан обновлённый вариант кода (см. файл hw4gtk.py из архива python_gui.tgz). В данном случае изменения носят скорее косметический характер, хотя иногда в ходе миграции из PyGTK в PyGObject могут возникнуть определённые проблемы.

Листинг 4. Пример PyGTK-приложения для Python 3
#!/usr/bin/python3
#-*- coding: UTF-8 -*-

from gi.repository import Gtk

def button_clicked(button):
    print( 'Hello World!' )

def main():
    window = Gtk.Window()
    window.set_default_size(240, 180)
    window.set_title('Hello World!')
    window.connect('destroy', lambda w: Gtk.main_quit())

    button = Gtk.Button('Press Me')
    button.connect('clicked', button_clicked)
    button.show()

    window.add(button)
    window.present()

   Gtk.main()

if __name__ == '__main__':
    main()

Исполнение этого примера в Python 3 создаст аналогичное окно.

$ python3 hw4gtk.py
Hello World!
Hello World!
Hello World!
...

Заключение

В этой статье был представлен краткий обзор нескольких инструментов для создания графических приложений, доступных к использованию из Python. Также мы описали общие принципы построения GUI-приложений (схема событийно управляемых приложений), независимо от того, каким инструментом будет реализована отрисовка виджетов.

Показаны простейшие примеры кода для различных инструментов. Вы можете их взять за основу для проверки готовности системы (установки и настройки всех требуемых компонентов), и в качестве стартового приложения для придания требуемой функциональности.

В следующей статье мы продолжим знакомство с технологиями, позволяющими создавать GUI-приложения в Python.


Загрузка

ОписаниеИмяРазмер
примеры GUI-приложенийpython_gui.tgz131KB

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


  • Bluemix

    Узнайте больше информации о платформе IBM Bluemix, создавайте приложения, используя готовые решения!

  • developerWorks Premium

    Эксклюзивные инструменты для построения вашего приложения. Узнать больше.

  • Библиотека документов

    Более трех тысяч статей, обзоров, руководств и других полезных материалов.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=959883
ArticleTitle=Тонкости использования языка Python: Часть 9. Разработка GUI-приложений
publish-date=01102014