|
Примеры событий, назначение id виджетам
wx.EVT_MOTION
Продолжаем тему
событий и давайте реализуем окно, в котором будем отображать текущие координаты
курсора мыши. Для этого в конструкторе класса MyFrame на событие EVT_MOTION
повесим обработчик onMove
class MyFrame(wx.Frame ):
def __init__(self, parent, title):
super().__init__(parent, title=title, size=(600,300))
self.x = wx.StaticText(self, label='x:', pos=(10, 10))
self.y = wx.StaticText(self, label='y:', pos=(10, 30))
self.Bind(wx.EVT_MOTION, self.OnMove)
Также в нем
объявлены два виджета в виде текстовых элементов, в которые мы и будем выводить
информацию о позиции. Сам обработчик будет следующим:
def OnMove(self, event):
x, y = event.GetPosition()
self.x.SetLabel('x: ' + str(x))
self.y.SetLabel('y: ' + str(y))
Запустим
программу и видим, что перемещая мышь, меняются значения ее координат в
текстовых виджетах.
wx.EVT_PAINT
Это событие
возникает при перерисовки окна или его отдельного элемента. В конструкторе
класса MyFrame назначим
обработчик этому событию:
self.Bind(wx.EVT_PAINT, self.OnPaint)
и ниже пропишем
сам метод:
def OnPaint(self, event):
print("событие EVT_PAINT")
dc = wx.PaintDC(self)
dc.DrawLine(0,0, 100, 100)
Смотрите, когда
элементы окна нуждаются в перерисовке, то возникает это событие и вызывается
обработчик onPaint. В нем мы
рисуем линию, которая гарантированно будет отображаться как бы мы ни перемещали
наше окно. Например, именно так осуществляют прорисовку элементов
пользовательского интерфейса, иначе бы он мог пропадать «стираться» в нашем
окне.
wx.EVT_SET_FOCUS, wx.EVT_KILL_FOCUS
Следующие два
события срабатывают в момент получения элементом фокуса и в момент его потери. Например,
создадим в нашем окне два текстовых поля ввода:
self.t1 = wx.TextCtrl(self)
self.t2 = wx.TextCtrl(self)
Разместим их в
сайзере BoxSizer с вертикальным
расположением:
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(t1, flag=wx.EXPAND | wx.ALL, border=10)
vbox.Add(t2, flag=wx.EXPAND | wx.ALL, border=10)
self.SetSizer(vbox)
И, далее, с
каждым виджетом свяжем два обработчика:
t1.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
t1.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
t2.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
t2.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
Сами обработчики
будут выглядеть так:
def OnSetFocus(self, event):
event.GetEventObject().SetBackgroundColour("#FFFFE5")
event.Skip()
def OnKillFocus(self, event):
event.GetEventObject().SetBackgroundColour("#fff")
event.Skip()
Смотрите, так
как мы незнаем из какого виджета они были вызваны, используется метод GetEventObject, который
возвращает связанный с событием объект, то есть, источник события. В нашем
случае это будет первое или второе поле ввода. Затем, мы устанавливаем у
объекта фон (светло-желтый) если элемент в фокусе и белый, если элемент не
имеет фокуса. Последними строчками вызывается метод Skip, который
распространяет соответствующее событие дальше, чтобы сам виджет мог его
корректно обработать. Запустим программу и увидим вот такой результат:
Поле ввода с
мигающим курсором подсвечивается светло-желтым, т.к. он в фокусе. Если выбрать
другое поле, то прежнее приобретет белый фон, а новый будет светло-желтым.
wx.EVT_KEY_DOWN, wx.EVT_KEY_UP
Данные события
срабатывают при нажатии и отпускании клавиши на клавиатуре. Давайте сначала
реализуем вот такой простой пример:
class MyFrame(wx.Frame ):
def __init__(self, parent, title):
super().__init__(parent, title=title, size=(600,300))
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
def OnKeyDown(self, e):
print("Нажали кнопку")
def OnKeyUp(self, e):
print("Отпустили кнопку")
Запустим и
видим, что при нажатии на кнопку возникают эти два события: сначала EVT_KEY_DOWN,
затем, EVT_KEY_UP.
Далее, сделаем
следующее. При нажатии на кнопку ESC будет появляться сообщение с вопросом:
хочет ли пользователь выйти из программы. Реализовать это можно следующим
образом:
def OnKeyDown(self, e):
key = e.GetKeyCode()
if key == wx.WXK_ESCAPE:
ret = wx.MessageBox('Вы дейстительно хотите выйти из программы?', 'Вопрос',
wx.YES_NO | wx.NO_DEFAULT, self)
if ret == wx.YES:
self.Close()
Порядок назначения id элементам интерфейса
Во второй части
занятия поговорим о порядке назначения id виджетам
интерфейса. Мы часто в программах писали так:
b1 = wx.Button(self, wx.ID_ANY, label="Кнопка 1")
b2 = wx.Button(self, wx.ID_ANY, label="Кнопка 2")
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(b1, flag=wx.EXPAND | wx.ALL, border=10)
vbox.Add(b2, flag=wx.EXPAND | wx.ALL, border=10)
self.SetSizer(vbox)
Вот эта
константа wx.ID_ANY в
действительности равна -1 и говорит wxPython, чтобы он
автоматически назначил id данному
элементу. То есть, вместо wx.ID_ANY, конечно, можно
просто записать -1, но лучше делать это через константу и если в будущих
версиях wxPython она будет
изменена, то не придется переписывать всю программу.
Так вот, все
автоматические id генерируются уникальными и отрицательными.
И мы в этом можем убедиться, если вызовем метод GetId для этих
кнопок:
print(b1.GetId(), b2.GetId(), sep="\n")
Благодаря этому,
можно задавать свои собственные id в области положительных чисел, не
опасаясь, что произойдет дублирование с уже существующими (автоматическими)
значениями. То есть, можно сделать, например, так:
И, затем,
использовать их при объявлении кнопок:
b1 = wx.Button(self, BUTTON1, label="Кнопка 1")
b2 = wx.Button(self, BUTTON2, label="Кнопка 2")
Теперь, при
запуске программы увидим значения этих констант в консоли. Но и это не лучший
способ создания собственных id. Обычно, мы полагаем, что они должны
быть уникальными и чтобы случайно не сделать дубли, лучше пользоваться
специальным методом wxPython:
wx.NewIdRef()
который
возвращает объект WindowIDRef с уникальным сгенерированным id. Этот метод
можно применять так. В глобальной области создаем две ссылки с уникальными id:
BUTTON1 = wx.NewIdRef()
BUTTON2 = wx.NewIdRef()
и, затем,
назначаем их нашим кнопкам:
b1 = wx.Button(self, BUTTON1.GetId(), label="Кнопка 1")
b2 = wx.Button(self, BUTTON2.GetId(), label="Кнопка 2")
Обратите
внимание, здесь мы вызываем метод GetId, чтобы из
объекта WindowIDRef получить число (id) и назначить их виджетам. Преимущество
использования BUTTON1 вместо wx.ID_ANY в том, что мы
можем разным виджетам через BUTTON1 присвоить одни и те же id. Например, если
пункт меню дублируется кнопкой на панели инструментов и вызывается один и тот
же обработчик, то им назначается одно и то же значение id.
Стандартные id
Модуль wxPython содержит
несколько стандартных (предопределенных) id, например,
ID_SAVE,
ID_OPEN, ID_NEW
и много других. Назначая
стандартные id виджетам wxPython добавляем им
соответствующие иконки и горячие клавиши:
b1 = wx.Button(self, wx.ID_SAVE, label="Кнопка 1")
Правда, это
работает преимущественно под ОС Linux. Под ОС Windows никакого
эффекта они не дают.
|