Почему именно wxPython

 Этим занятием мы с вами открываем серию видеоуроков по модулям языка Python.

Модули – это встроенные или сторонние разработки, которые существенно расширяют и упрощают функционал Python.

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

Конечно, все эти библиотеки кросс-платформенные и могут быть скомпилированы под любую известную ОС, например, Window, Linux или Mac OS. И первый – это, конечно, стандартный пакет Tkinter – оболочка над Tcl/tk, поставляемый вместе с Python. Однако, внешний вид интерфейса и богатство функционала оставляет желать лучшего. Другая известная библиотека Qt имеет несколько оболочек: PyQt, PySide и PySide2. Наиболее старая из них – это PyQt (которая продолжает развиваться) и распространяется по лицензии GPL, т.е. для свободного использования в некоммерческих целях. Поэтому позже и появились библиотеки PySide и PySide2, распространяемые по лицензии LGPL и их уже можно использовать в коммерческих приложениях. Следующая библиотека PyGTK – оболочка над GTK+. Основной ее недостаток в том, что под ОС Windows интерфейс выглядит несколько чужеродно, неестественно, особенно диалоги для работы с файлами. Под ОС Linux такой проблемы нет, там к интерфейсу на GTK пользователи уже привыкли. Наконец, wxPython – оболочка над библиотекой wxWidgets, написанной на С++. Почему выбор пал именно на нее? Здесь есть ряд важных, на мой взгляд, преимуществ:

  • в разных операционных системах отображается «родной» интерфейс, т.к. wxWidgets использует родной API ОС, а не имитирует свой;
  • небольшой размер в компилируемых приложениях;
  • большое разнообразие виджетов для создания интерфейса;
  • без проблем создаются запускаемые файлы конечного приложения с помощью cx_Freeze (или аналогов).

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

Далее, я буду рассказывать о порядке работы с wxPython (главный разработчик и идеолог этого пакета – Robin Dunn). И первое что нужно сделать – это установить его. Для этого нужно зайти в репозиторий

https://pypi.org

в поиске набрать wxPython и я здесь выбрал версию «wxPython 4.0.7.post2», которая использует функционал языка Python 3 (более младшие версии были написаны для Python 2). Чтобы ее установить, нужно выполнить команду:

pip install wxPython

(Если вы не знаете как устанавливать пакеты, то вот ссылка на это занятие).

Давайте проверим корректность установки пакета. Напишем вот такую простую программу для отображения оконного приложения:

import wx
 
app = wx.App()
 
frame = wx.Frame(None, title='Hello World!')
frame.Show()
 
app.MainLoop()

Если при запуске вы видите вот такое окно, значит wxPython был успешно установлен и готов к использованию.

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

В определенные моменты возникают различные события (красные точки) и они некоторое время выполняются (или, как говорят, обрабатываются). Эта обработка занимает некоторое время. То есть, с каждым событием связан определенный обработчик, попросту функция, которая и выполняет запрограммированные действия. Время работы функции – это фактически и есть время обработки события. После обработки событие пропадает и приложение переходит в режим ожидания следующего события. Когда оно возникает, снова выполняется его обработка, и, затем, оно также пропадает. Если в момент обработки события появляются другие события, то они помещаются в очередь и их обработка (в порядке следования) начнется после завершения текущего события. Наконец, при возникновении события WM_QUIT приложение завершает свою работу. Вот все эти операции по отслеживанию и обработке событий составляют главный цикл приложения, который реализуется вызовом метода:

app.MainLoop()

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

  • App – класс общего функционала приложения;
  • Frame – класс отдельного окна (их может быть несколько).

Соответственно, в программе мы должны создать экземпляр класса App:

app = wx.App()

и позже запускаем для него главный цикл обработки событий:

app.MainLoop()

До запуска, создаем одно главное окно приложения с помощью класса Frame:

wnd = wx.Frame(None, wx.ID_ANY, "Hello World!")

и отображаем его на экране:

wnd.Show()

В конструкторе класса Frame мы указываем три параметра:

  • parent – ссылка на родительское окно (если его нет, то указывается None, тогда окно становится главным окном приложения);
  • id – уникальный идентификатор виджета (указывая wx.ID_ANY мы говорим, чтобы он формировался автоматически);
  • title – заголовок окна.

Вот это простейшие действия, которые мы должны сделать для построения программы с графическим пользовательским интерфейсом (GUI) с помощью wxPython.

Конечно, конструктор класса Frame содержит и другие параметры, полный синтаксис следующий:

wx.Frame(parent, id=-1, title='', pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame")

Названия параметров говорят сами за себя, единственно, что следует подробнее расшифровать – это параметр DEFAULT_FRAME_STYLE, который состоит из набора следующих констант:

wx.DEFAULT_FRAME_STYLE = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN

Здесь вот эта вертикальная черта – операция побитового ИЛИ, с помощью которой и происходит объединение всех этих свойств. А сами свойства означают следующее:

  • wx.MINIMIZE_BOX – кнопка для свертывания окна;
  • wx.MAXIMIZE_BOX – кнопка для распахивания окна;
  • wx.CLOSE_BOX – кнопка закрытия окна;
  • wx.RESIZE_BORDER – делаем окно с изменяемым размером;
  • wx.SYSTEM_MENU – разрешаем системное меню;
  • wx.CAPTION – разрешаем заголовок у окна.

Давайте в качестве примера попробуем создать окно с другим набором свойств, например, так:

wnd = wx.Frame(None, wx.ID_ANY, "Hello World!", size=(200, 200))

или так:

wnd = wx.Frame(None, wx.ID_ANY, "Hello World!", size=(500, 200),
          style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)

Видите, мы здесь уже не можем минимизировать окно. Далее, уберем wx.CAPTION, получим окно без верхней рамки. Изменим положение окна:

wnd = wx.Frame(None, wx.ID_ANY, "Hello World!", size=(500, 200), pos = (100,0))

Или так:

wnd = wx.Frame(None, wx.ID_ANY, "Hello World!", size=(500, 200))
wnd.Centre()

Получим окно по центру. Также доступны такие полезные методы класса Frame:

  • Close() – закрывает окно;
  • Maximize() – распахивает окно на весь экран;
  • Move(x, y) – располагает окно со смещением x, y пикселей от верхнего левого угла экрана;
  • SetPosition( pt: wx.Point ) – помещает окно с начальной точкой pt, например, wnd.SetPosition( wx.Point(100, 500) );
  • SetSize(x, y, width, height) – устанавливает положение и размер окна.

Разумеется, есть много других методов класса Frame. Приводить их все и описывать смысла особого нет, т.к. это уже будет похоже на декларирование справочного материала. К тому же за более детальной информацией всегда можно обратиться к первоисточнику:

https://docs.wxpython.org

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

Видео по теме