Это занятие
будет немного похоже на справочный материал, так как мы будем рассматривать
примеры использования некоторых стандартных виджетов wxPython и построим вот
такой интерфейс:
В самом начале у
нас будет вот такая заготовка:
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, title):
super().__init__(parent, title=title, size=(600, 450))
app = wx.App()
frame = MyFrame(None, 'wxPython')
frame.Show()
app.MainLoop()
И в окно MyFrame будем постепенно
добавлять различные элементы управления. Начнем со статусной строки. Она
создается с помощью метода CreateStatusBar класса Frame:
self.sb = self.CreateStatusBar()
self.sb.SetStatusText("Текст в статусной строке")
Здесь метод SetStatusText
позволяет поместить текстовую информацию в статусную строку. Если теперь
запустить программу, то увидим окно со статусной строкой и текстом «Текст в
статусной строке».
Разумеется, это
простейший пример использования данного виджета. Полный набор методов и свойств
объекта wx.StatusBar можно найти на странице официальной документации:
docs.wxpython.org/wx.StatusBar.html
Далее, разместим
в окне панели и сайзер BoxSizer, который свяжем с этой панелью:
panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(vbox)
О том, что такое
сайзер и как ими пользоваться мы говорили на предыдущих занятиях.
wx.StaticText
Создадим
следующий виджет wx.StaticText, который отображает статический текст в заданной
позиции. Общий
конструктор этого класса, следующий:
StaticText(parent,
id=ID_ANY, label="", pos=DefaultPosition, size=DefaultSize, style=0,
name=StaticTextNameStr)
-
parent – родитель, на
котором размещается виджет;
-
id
– идентификатор
элемента;
-
label – текст,
отображаемый этим виджетом;
-
pos, size – позиция и
размер виджета (в пикселах);
-
style
– стилизация
элемента.
В нашем случае
мы его создадим так:
st = wx.StaticText(panel, label="Адрес: ")
и добавим в
сайзер BoxSizer, который
автоматически разместит его в нужной позиции нашего окна:
vbox.Add(st, flag=wx.ALL, border=10)
При запуске
программы увидим текст «Адрес: » в верхнем левом угле фрейма. Полная
документация данного виджета доступна на странице:
https://docs.wxpython.org/wx.StaticText.html
wx.TextCtrl
Далее разместим
текстовое поле ввода. Оно создается с помощью класса wx.TextCtrl и имеет такой
конструктор:
TextCtrl(parent,
id=ID_ANY, value="", pos=DefaultPosition, size=DefaultSize, style=0,
validator=DefaultValidator, name=TextCtrlNameStr)
Все параметры
здесь вам уже знакомы, поэтому перейдем сразу к примеру его использования. В
нашей программе мы его создадим так:
inp = wx.TextCtrl(panel, value="г. Москва")
и поместим
следующим элементом в BoxSizer:
vbox.Add(inp, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, border=10)
При запуске
программы увидим поле ввода с начальным текстом «г. Москва». Документацию по
этому виджету смотрите здесь:
docs.wxpython.org/wx.TextCtrl.html
wx.StaticLine
После текстового
поля ввода разместим горизонтальную черту (линию), которая создается с помощью
конструктора
StaticLine(parent,
id=ID_ANY, pos=DefaultPosition, size=DefaultSize, style=LI_HORIZONTAL,
name=StaticLineNameStr)
Опять же здесь
все параметры вполне очевидны и поместим ее следующим элементом в наш сайзер:
vbox.Add(wx.StaticLine(panel), flag=wx.EXPAND|wx.LEFT|wx.RIGHT, border=10)
Смотрите, мы
здесь в одной строке сразу создали StaticLine и поместили в BoxSizer. Так тоже можно
делать, если не предполагается дополнительной работы с виджетом. Ну а его
подробная документация доступна по адресу:
https://docs.wxpython.org/wx.StaticLine.html
wx.ToggleButton
Данный класс
представляет собой кнопки, которые можно переводить в нажатое положение и
возвращать в исходное (отжатое). Чтобы создать вот такую конфигурацию
расположения элементов, воспользуемся GridBagSizer. Но вначале
создадим кнопки-переключатели. Конструктор следующий:
ToggleButton(parent,
id=ID_ANY, label="", pos=DefaultPosition, size=DefaultSize, style=0,
val=DefaultValidator, name=CheckBoxNameStr)
В нашей
программе мы их создадим так:
rtb = wx.ToggleButton(panel, id = B_RED, label='red', pos=(20, 25))
gtb = wx.ToggleButton(panel, id = B_GREEN, label='green', pos=(20, 60))
btb = wx.ToggleButton(panel, id = B_BLUE, label='blue', pos=(20, 100))
А вначале
объявим эти уникальные id:
B_RED = 1
B_GREEN = 2
B_BLUE = 3
Затем, создадим
специальный объект
self.col = wx.Colour(0, 0, 0)
для работы с
цветом панели (ее фон будет меняться в зависимости от нажатых кнопок-переключателей).
И саму панель:
self.pn = wx.Panel(panel)
self.pn.SetBackgroundColour(self.col.GetAsString())
Мы здесь
вызываем метод SetBackgroundColour чтобы установить начальный фон у
панели. Теперь, все созданные виджеты следует добавить в GridBagSizer:
vb1 = wx.GridBagSizer(10, 10)
vb1.Add(rtb, (0, 0)); vb1.Add(gtb, (1, 0)); vb1.Add(btb, (2, 0))
vb1.Add(self.pn, (0, 1), (3, 1), flag=wx.EXPAND)
vb1.AddGrowableCol(1)
В конструкторе
этого сайзера мы указываем отступы между ячейками в 10 пикселей по вертикали и
горизонтали, затем в столбцы добавляем три кнопки-переключатели, а затем,
создаем еще одну ячейку, которая располагается в следующем столбце и охватывает
три ячейки по вертикали. Устанавливаем флаг wx.EXPAND, чтобы
растянуть ее на всю доступную ширину и высоту и еще устанавливаем proportion=1 для этого
второго столбца с помощью метода AddGrowableCol. О том как в деталях работает
этот сайзер мы с вами уже говорили на одном из предыдущих занятий.
Добавим эту
заготовку следующим элементом в BoxSizer:
vbox.Add(vb1, flag=wx.EXPAND|wx.ALL, border=10)
И при запуске
программы увидим такой результат:
Если пощелкать
по кнопкам, то они будут то нажиматься, то отжиматься. Далее, ниже добавим еще
горизонтальную разделительную линию:
vbox.Add(wx.StaticLine(panel), flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=10)
Давайте теперь
добавим функционал нашим кнопкам и свяжем с ними обработчик onToggle:
rtb.Bind(wx.EVT_TOGGLEBUTTON, self.onToggle)
gtb.Bind(wx.EVT_TOGGLEBUTTON, self.onToggle)
btb.Bind(wx.EVT_TOGGLEBUTTON, self.onToggle)
А сам метод
реализуем следующим образом:
def onToggle(self, e):
btn = e.GetEventObject()
val = 255 if btn.GetValue() else 0
id = btn.GetId()
r = self.col.Red()
g = self.col.Green()
b = self.col.Blue()
if id == B_RED:
self.col.Set(val, g, b)
elif id == B_BLUE:
self.col.Set(r, g, val)
elif id == B_GREEN:
self.col.Set(r, val, b)
self.pn.SetBackgroundColour(self.col)
self.pn.Refresh()
Здесь первой
строкой мы получаем ссылку на объект, от которого пришло событие, т.е. одну из
трех кнопок-переключаетлей. Затем, с помощью метода GetValue определяем:
нажата ли кнопка. Данный метод возвращает True, если кнопка
нажата и False в противном
случае. Используя тернарный условный оператор, переменной val присваивается
255 для нажатой кнопки и 0 для отжатой. Наконец, в переменной id сохраняет id текущей кнопки.
Следующими тремя
строчками получаем текущие значения r, g и b объекта wx.Colour и далее
проверяем: если нажата (или отжата) кнопка для красной компоненты, то меняем
этот цвет в нашем объекте. Аналогично для двух других цветов: синего и
зеленого. После этого панели применяем новый полученный цвет и обновляем ее
(перерисовываем) методом Refresh.
Если теперь
запустить программу и понажимать на наши кнопки, то фон панели будет меняться.
Подробную документацию по wx.ToggleButton смотрите на странице:
https://docs.wxpython.org/wx.ToggleButton.html
wx.StaticBox
Далее мы создадим
вот такой фрагмент интерфейса (см. рисунок ниже). И начнем с виджета StaticBox, который
представляет собой рамку с неким заголовком:
StaticBox(parent,
id=ID_ANY, label="", pos=DefaultPosition, size=DefaultSize, style=0,
name=StaticBoxNameStr)
Эту рамку (а
также радио-кнопки) мы разместим на отдельной панели:
pn2 = wx.Panel(panel)
wx.StaticBox(pn2, label="Ваш пол:", size=(150, 50))
Мы здесь
указываем заголовок «Ваш пол:» и размер рамки 150х50 пикселей.
Документацию по
виджету смотрите на странице:
docs.wxpython.org/wx.StaticBox.html
wx.RadioButton
Далее на панели pn2 разместим
радио-кнопки и укажем их положение так, чтобы они оказались внутри StaticBox:
rd1 = wx.RadioButton(pn2, label="Муж", pos=(10, 20), style=wx.RB_GROUP)
rd2 = wx.RadioButton(pn2, label="Жен", pos=(100, 20))
Здесь style=wx.RB_GROUP у первой кнопки
означает начало группы для RadioButton. Общий
синтаксис конструктора данного виджета, следующий:
RadioButton(parent,
id=ID_ANY, label="", pos=DefaultPosition, size=DefaultSize, style=0,
validator=DefaultValidator, name=RadioButtonNameStr)
После создания
кнопок, добавим панель pn2 со всеми элементами в горизонтальный BoxSizer:
vb2 = wx.BoxSizer(wx.HORIZONTAL)
vb2.Add(pn2)
Полная
документация по RadioButton доступна на странице:
https://docs.wxpython.org/wx.RadioButton.html
wx.CheckBox
Следующий
элемент, который мы разместим – это кнопка с флажком (CheckBox). Синтаксис ее конструктора такой:
CheckBox(parent,
id=ID_ANY, label="", pos=DefaultPosition, size=DefaultSize, style=0, validator=DefaultValidator,
name=CheckBoxNameStr)
Создадим этот
элемент и установим по умолчанию флажок:
agree = wx.CheckBox(panel, label="Согласен на обработку")
agree.SetValue(True)
Добавим этот
элемент в горизонтальный сайзер:
vb2.Add(agree, flag = wx.LEFT|wx.TOP, border=20)
Документация
виджета на странице:
docs.wxpython.org/wx.CheckBox.html
wx.ComboBox и wx.SpinCtrl
Следующий виджет
ComboBox представляет собой выпадающий список и может быть создан со следующими
параметрами:
ComboBox(parent,
id=ID_ANY, value="", pos=DefaultPosition, size=DefaultSize,
choices=[], style=0, validator=DefaultValidator, name=ComboBoxNameStr)
Здесь value – это начальное
выбранное значение списка, а choices – упорядоченный
список строк, которые и формируют данный список. Создадим его в нашей программе
следующим образом:
links = ["Телефон", "E-mail", "Skype"]
cb = wx.ComboBox(panel, pos=(50, 30), choices=links, style=wx.CB_READONLY)
cb.SetSelection(0)
Мы здесь сначала
объявили список из строк, затем вызвали конструктор класса ComboBox и через
параметр choices указали ссылку
на список. Также установили стиль CB_READONLY (только для
чтения), т.е. элементы выпадающего списка можно только выбирать, но не вводить
с клавиатуры. Последняя строчка определяет индекс выбранного элемента по
умолчанию: 0 – первая строка «Телефон».
Подробная
документация на странице:
https://docs.wxpython.org/wx.ComboBox.html
Следующий
элемент SpinCtrl создает текстовое поле для ввода чисел со стрелками вверх/вниз:
SpinCtrl(parent,
id=ID_ANY, value="", pos=DefaultPosition, size=DefaultSize,
style=SP_ARROW_KEYS, min=0, max=100, initial=0, name="wxSpinCtrl")
Параметры его
конструктора вполне очевидны и в программе мы его создадим так:
sc = wx.SpinCtrl(panel, value='0', min=-100, max=100)
то есть,
начальное значение будет равно 0, минимальное -100, максимальное +100.
Документация по виджету на странице:
https://docs.wxpython.org/wx.SpinCtrl.html
Добавим эти два
элемента в горизонтальный сайзер:
vb2.Add(cb, flag=wx.LEFT | wx.TOP, border=15)
vb2.Add(sc, flag=wx.LEFT | wx.TOP, border=15)
А, затем,
добавим его в горизонтальный BoxSizer:
vbox.Add(vb2, flag=wx.EXPAND | wx.ALL, border=10)
Запустим
программу и увидим вот такое окно:
wx.Gauge
Следующий
элемент прогресс бар определяется классом Gauge и имеет
следующий конструктор:
Gauge(parent,
id=ID_ANY, range=100, pos=DefaultPosition, size=DefaultSize,
style=GA_HORIZONTAL, validator=DefaultValidator, name=GaugeNameStr)
Здесь параметр range определяет
числовое значение, которое будет ассоциироваться с полной полосой (со 100%). Создадим
этот виджет следующим образом:
self.gauge = wx.Gauge(panel, range=100)
и добавим его в
следующую ячейку BoxSizer:
vbox.Add(self.gauge, flag=wx.EXPAND|wx.ALL, border=10)
Подробная
документация на странице:
https://docs.wxpython.org/wx.Gauge.html
wx.Button
Под прогресс
баром разместим две кнопки «Старт» и «Стоп», используя класс Button, который мы
уже много раз использовали. Синтаксис его конструктора следующий:
Button(parent,
id=ID_ANY, label="", pos=DefaultPosition, size=DefaultSize, style=0,
validator=DefaultValidator, name=ButtonNameStr)
Вызовем этот
конструктор в нашей программе со следующими параметрами:
bStart = wx.Button(panel, label="Старт")
bStop = wx.Button(panel, label="Стоп")
и разместим их в
нашем окне с центрированием по горизонтали:
hb3 = wx.BoxSizer()
hb3.AddMany([(bStart, 0, wx.LEFT|wx.RIGHT, 10), (bStop, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, 10)])
vbox.Add(hb3, flag=wx.ALIGN_CENTRE)
И ниже
горизонтальную разделительную линию:
vbox.Add(wx.StaticLine(panel), flag=wx.EXPAND|wx.LEFT|wx.RIGHT, border=10)
При запуске
программы увидим следующий результат:
Подробную
документацию по кнопкам смотрите на странице:
https://docs.wxpython.org/wx.Button.html
Давайте теперь
на эти кнопки повесим обработчики onStart и onStop, чтобы при нажатии на кнопку
«Старт» у нас заполнялась полоса прогресс бара:
bStart.Bind(wx.EVT_BUTTON, self.onStart)
bStop.Bind(wx.EVT_BUTTON, self.onStop)
Здесь нам
понадобится вспомогательный объект
self.timer = wx.Timer(self)
который через
заданный интервал времени будет вызывать связанный с ним метод OnTimer:
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
и в этом
обработчике будем увеличивать переменную:
self.count = 0
self.gauge.SetValue(self.count)
на единицу и
менять величину прогресс бара:
def OnTimer(self, e):
self.count = self.count + 1
self.gauge.SetValue(self.count)
if self.count >= 100:
self.timer.Stop()
Как только
дойдем до предельного значения 100, то таймер будет остановлен методом Stop.
Теперь все
готово для написания обработчиков onStart и onStop:
def onStop(self, e):
self.timer.Stop()
self.count = 0
def onStart(self, e):
if self.count > 100:
return
self.timer.Start(100)
Запускаем
программу и тестируем действие кнопок.
wx.Slider
Последний
виджет, который мы рассмотрим на данном занятии – это Slider, создающий
бегунок. Конструктор его класса следующий:
Slider(parent,
id=ID_ANY, value=0, minValue=0, maxValue=100, pos=DefaultPosition,
size=DefaultSize, style=SL_HORIZONTAL, validator=DefaultValidator,
name=SliderNameStr)
В нашем окне мы
его определим вот с такими параметрами:
sld = wx.Slider(panel, value=200, minValue=150, maxValue=500, style=wx.SL_HORIZONTAL)
Добавим его в
наш интерфейс:
vbox.Add(sld, flag=wx.EXPAND|wx.ALL, border=10)
И свяжем с ним
обработчик OnSliderScroll:
sld.Bind(wx.EVT_SCROLL, self.OnSliderScroll)
Через этот метод
мы будем отображать значение слайдера в статусной строке:
def OnSliderScroll(self, e):
val = e.GetEventObject().GetValue()
self.sb.SetStatusText("Slider: "+str(val))
Запускаем
программу и видим все наши виджеты и с некоторыми из них можем
взаимодействовать. Подробная документация по Slider доступна на
странице:
https://docs.wxpython.org/wx.Slider.html
Конечно, это
только некоторые, базовые виджеты wxPython. Полный их
список можно найти вот на этой странице
https://docs.wxpython.org/wx.Control.html
в разделе
«Субклассы» (Subclasses). Их принцип работы и взаимодействия с ними похож на
те, что мы рассмотрели на этом занятии. Поэтому, я думаю, их применение на
практике не вызовет у вас больших затружнений.