- Вся документация подробно на https://docs.wxpython.org
Другие функции для объектов Фрейма / Окна:
- Close() - закрывает окно
- Maximize() - разворачивает полностью
- Move(x, y) - сдвигает со смещением x,y пикселей от верхнего левого угла экрана или от предыдущего значения
- SetPosition(pt:wx.Point) - помещает окно с начальной точкой pt, пример wnd.SetPosition(wx.Point(100,500))
- SetSize(x, y, width, height) - устанавливает и позицию, и размер окна одной командой
Структура GUI-App'а: виджеты + Лэйауты.
Layouts - схемы расположения элементов-виджетов.
Panel -> Sizers - структурные элементы лэйаутов.
Сайзеры бывают BoxSizer, GridSizer, FlexGridSizer, GridBagSizer
Внутри одного сайзера могут располагаться и другие сайзеры.
Пример других виджетов на фрейме: MenuBar, ToolBar, StatusBar.
- PopupWindow - специальный оконный класс для создания popup-меню, списков combobox и других вспомогательных виджетов подобного рода
- ScrolledWindow - используется для создания окна с прокручиваемым содержимым
- Frame - используется для создания стандартного окна в большинстве случаев работаем с ним
- MDIParentFrame (Multiple Document Interface) - класс, содержащий дочерние оконные классы например, Photoshop со множеством открытых документов)
- MDIChildFrame - создает дочернее окно внутри MDIParentFrame
- Dialog - создает диалоговое окно
Имеются еще сложносоставные(специализированные) панели:
- ScrolledWindow - контейнер с прокручиваемым содержимым
- SplitterWindow - контейнер с разделительной полосой, которую можно перемещать, изменяя размеры соответствующих содержимых
- Notebook - используется для создания tab-интерфейса (панели со вкладками)
I - ДИНАМИЧЕСКИЕ
- Button - обычная кнопка
- BitmapButton - кнопка с картинкой
- ToggleButton - кнопка-переключатель
- SpinButton - стрелочки вверх-вниз
- RadioButton - радио-кнопка (кружочек с точкой)
- CheckBox - чекбокс (флажок)
- TextCtrl - текстовое поле ввода
- SpinCtrl - текстовое поле ввода со стрелочками вверх-вниз
- ComboBox - выпадающий список с возможностью ввода значения
- Choice - выпадающий список только с возможностью выбора из предложенных
- Slider - бегунок
- ScrollBar - скроллинг
- Grid - таблица (наподобие Excel)
- RadioBox - контейнер для Радио-кнопок
- ListBox - список
II - СТАТИЧЕСКИЕ
- StaticBitmap - для статических изображений
- StaticBox - квадратная рамка
- Gauge - прогресс-бар
- StaticText - простой (неизменяемый) текст
- StaticLine - линия
Для создания меню используются три основных класса:
- MenuBar - для создания панели меню
- Menu - для создания вкладки меню
- MenuItem - для создания отдельного пункта внутри вкладки
Для связки назначенных на окне пунктов с их обработчиками существует метод Bind:
Bind(event, handler, source=None), где:
- event - тип события, связанный с определенным интерфейсным объектом
- handler - ссылка на функцию-обработчик
- source - источник, генерирующий событие
Какие пункты меню существуют в wxPython (ключик: kind):
- ITEM_NORMAL - обычный, как текст
- ITEM_SEPARATOR - разделитель
- ITEM_CHECK - пункт с флажком (чекбокс)
- ITEM_RADIO - пункт с возможностью перебора
Для формирования конт. меню нам нужно научить реагировать на правый клик мыши при Bind'инге.
Контекстное меню правильно будет описать отдельным классом вне класса MyFrame. Например, class AppContextMenu(wx.Menu).
Контекстное меню описывается как обычная вкладка меню для группы айтемов.
Какие еще бывают ивенты, кроме описанного в примере EVT_RIGHT_DOWN (правого клика мыши): https://docs.wxpython.org/wx.Event.html
Последовательность создания тулбара(панели инструментов):
- self.CreateToolBar() - создание "пустого" тулбара
- .AddTool() - добавление инструмента на тулбаре
- .Realize() - воплощение(отрисовка) тулбара со всеми инструментами
И далее не забудем забиндить каждый пункт тулбара на свою функцию-обработчик (ч/з .Bind)
Доп. инфа по тулбарам в оф.документации https://docs.wxpython.org/wx.ToolBar.html
Сайзеры - разновидности виджетов. Бывают нескольких видов - BoxSizer, GridSizer, FlexGridSizer, GridBagSizer
Наиболее применимый сайзер, BoxSizer - это аналог BoxLayout в Kivy или PyQt5, Лучшая практика - размещать в конечном итоге сайзеры на панели (мастер-лэйауте), а панель единственную на главном фрейме. Панель - аналог main layout'а в указанных выше GUI-фреймворках. Описывается панель примерно как: panel = wx.Panel(self), потом img1 и img2 натягиваются на панель, и в завершении пишется panel.SetSizer(vbox), т.е. устанавливаем сайзер не на фрейм, а на предварительно созданную панель (см. код видео 5_1)
GridSizer позволяет создавать двухмерную сетку ячеек с одинаковой шириной и высотой.
Синтаксис:
wx.GridSizer(rows=1, cols=0, vgap=0, hgap=0)- rows - число строк (отсчет начинается с 1)
- cols - число столбцов (отсчет идет с 0)
- vgap - интервал между ячейками по вертикали
- hgap - интервал между ячейкми по горизонтали
FlexGridSizer работает аналогично GridSizer'у, но ширина ячеек у мего м.б. разная.
Синтаксис и пример:
flexbox = wx.FlexGridSizer(4, 2, 10, 10)
flexbox.AddMany([
(wx.StaticText(panel, label='ФИО:')),
(wx.TextCtrl(panel), wx.ID_ANY, wx.EXPAND),
(wx.StaticText(panel, label='email:')),
(wx.TextCtrl(panel), wx.ID_ANY, wx.EXPAND),
(wx.StaticText(panel, label='Адрес:')),
(wx.TextCtrl(panel), wx.ID_ANY, wx.EXPAND),
(wx.StaticText(panel, label='О себе:')),
(wx.TextCtrl(panel, style=wx.NB_MULTILINE), wx.ID_ANY, wx.EXPAND),
])
panel.SetSizer(flexbox)
flexbox.AddGrowableCol(1, proportion=1) # делается, чтобы поля ввода по опр. столбцы растягивались по ширине
flexbox.AddGrowableRow(3, proportion=1) # первый параметр - номер строкиGridBagSizer наиболее гибкий сайзер, он динамически создает таблички из ячеек, у кот-х м.быть разные размеры.
Синтаксис:
wx.GridBagSizer(vgap, hgap)где параметры - расстояния между ячейками в px, по вертикали и горизонтали, а затем вызывается метод:
Add(self, item, pos, span=wx.DefaultSpan, flag=0, border=0, userData=None), где pos=(row, col)
Пример:
gbagbox = wx.GridBagSizer(5, 5)
lbl = wx.StaticText(panel, label = 'Email:')
gbagbox.Add(lbl, pos=(0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5) # (0, 0) # первая ячейка
txt_box = wx.TextCtrl(panel)
gbagbox.Add(txt_box, pos=(1, 0), span=(1, 5), flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)
# где span(1, 5) означает, что эта 1 строка будет охватывать 5 столбцов
btn1 = wx.Button(panel, label='Восстановить', size=(120, 28))
btn2 = wx.Button(panel, label='Отмена', size=(90, 28))
gbagbox.Add(btn1, pos=(3, 3)) # 4-я строка и 4-й столбец
gbagbox.Add(btn2, pos=(3, 4), flag=wx.RIGHT | wx.BOTTOM, border=10)
gbagbox.AddGrowableCol(col=1) # при этом интерфейс будет растягиваться по максимумуДля каждого События(event'а) имеется свой заготовленный по умолчанию id:
- wx.EVT_BUTTON - соб., генерируемое вилджетом wx.Button
- wx.EVT_MENU - соб., генерируемое меню
- wx.EVT_TEXT - соб., генерируемое wx.TextCtrl
- wx.EVT_TOOL - соб., генерируемое toolbox (тулбаром)
- wx.EVT_MOVE - соб., генерируемое при перемещении окна
- wx.EVT_PAINT - соб. для перерисовки элемента (обычно окна)
- wx.EVT_KEY_DOWN - соб. при нажатии на клавишу
- wx.EVT_KEY_UP - соб. при отпускании клавиши
Синтаксис Bind для связки метода класса и какого-либо события:
объект.Bind(<тип события>, <метод>)
По умолчанию события рапространяются к родительским объектам с детей (такой концепт) однако есть еще такие basic events, при которых не распространяются по родительским объектам например: wx.EVT_CLOSE - действуют только для этого виджета
Обратный метод - Unbind(self, event, source=None, id=wx.ID_ANY, id2=wx.ID_ANY, handler=None)
Он сбрасывает(отвязывает) какой-либо обработчик от объекта; пример:
panel.Unbind(wx.EVT_BUTTON)событие EVT_MOTION - передвижение мыши; событие EVT_PAINT - когда наше окно нуждается в перерисовке по возникшей логической необходимости
Прочие события, на которые можно Bind'ить обработчики:
- wx.EVT_SET_FOCUS, wx.EVT_KILL_FOCUS
1-е событие обработается когда эл-т(виджет) получает фокус (мыши), 2-е событие -// когда эл-т теряет фокус (мыши)
В обработчике пишем что-то вроде такого:
event.GetEventObject().SetBackGroundColour('#FFFFE5')^^^^^^^^^^^^^^^^^ обращаем внимание на первый метод, выцепляющий элемент-источник события. А следом целесообразно записать строку event.Skip() для правильной отработки.
- wx.EVT_KEY_DOWN, wx.EVT_KEY_UP возникают при нажатии и отпускании (any) клавиши на клавиатуре
Пример того, как определить клавишу в обработчике:
def on_key_down(self, event):
key = event.GetKeyCode()
if key == wx.WXK_ESCAPE:
wx.MessageBox('Вы нажали клавишу Escape')
else:
wx.MessageBox('Вы нажали не ту клавишу')В кач-ве константы мы ранее могла задавать id по умолчанию как константу wx.ID_ANY (по дефолту оно = -1), однако это означает, что сам wxPython динамически раздает айдишки этим виджетам. Фишка в том, что раздает он их отрицательными. Для назначения собственных ID мы можем пользоваться положительным промежутком числового ряда, например,
BUTTON1 = 1
BUTTON2 = 2
либо генератором уникальных ID:
BUTTON1 = wx.NewIdRef() # он будет создавать объект константы к которому обратимся по .GetId()На практике при создании виджета такая запись:
btn1 = wx.Button(self, BUTTON1.GetId(), label='Кнопка 1') # где сгенерируемые ID тоже будут отрицательнымиПреимущество предзаданных и т.обр. описанных констант в том, что мы можем разным виджетам присваивать одни и те же ID. Если пункт меню дублируется кнопкой на панели инструментов, то можно им задать один и тот же ID со ссылкой на константу, и закрепить общий обработчик(handler) чтобы избежать дублирований кода.
wx.ID_SAVE, wx.ID_OPEN, wx.ID.NEW - такие стандартные ID для виджетов хороши тем, что wxPython уже имеет для них стандартные иконки и горячие клавиши. Особенно это актуально для запуска в ОС семейства *nix.
Все диалоговые окна наследуются от общего родительского класса Dialog:
wx.Dialog(parent, id=ID_ANY, title="", pos=DefaultPosition, size=DefaultSize,
style=DEFAULT_DIALOG_STYLE, name=DialogNameStr)где:
- parent - ссылка на родительское окно (или значение None)
- id - идентификатор диалогового окна
- title - заголовок окна
- pos, size - позиция и размер окна
- style - стилизация окна
Значения констант для параметра style:
- wx.CAPTION - разрешает заголовок окна
- wx.DEFAULT_DIALOG_STYLE - комбинация констант wx.CAPTION, wx.CLOSE_BOX и wx.SYSTEM_MENU
- wz.RESIZE_BORDER - разрешает изменять размеры окна, по умолчанию выключено
- wx.SYSTEM_MENU - для отображения системного меню
- wx.CLOSE_BOX - для отображения кнопки закрытия (с крестиком)
- wx.MAXIMIZE_BOX - для возможности распахивания окна на max
- wx.MINIMIZE_BOX - для возможности свертывания окна
- wx.STAY_ON_TOP - для отображения окна поверх всех остальных
А при записи style=0 вообще все элементы при отображении будут выключены
модальное перекрывает управление интерфейсом на себя, пока оно открыто. После его закрытия dlg.EndModal() цикл обработки события завершается и становится доступен ост. интерфейс Если dlg.Show(), то dlg.Destroy() далее не будет нужен, но интерфейс будет доступен при переключении с окна и таких (немодальных) окон можно будет создать несколько экз.
Самый правильный способ создания и отработки Модального диалогового окна:
def on_dialog(self, event):
with MyDialog(self, title='Мой модальный диалог...") as dlg:
res = dlg.ShowModal()В случае оборота в менеджер контекста мы избавимся от необходимости применения Destroy, т.к. в wxPython эта обертка уже подразумеват авто-завершение с Destroy'ем.
Процесс рисования осуществляется ч/з т.н. контекст устройства (device context или DC).
В нашей библиотеке 6 разновидностей DC:
- wx.MemoryDC - контекст памяти (рисование в объекте Bitmap, расположенный в памяти устройства)
- wx.PrinterDC - контекст принтера (для OC Windows и Mac)
- wx.ScreenDC - контекст экрана устройства (рисование на экране без привязки к окну)
- wx.ClientDC, wx.PaintDC - рисование в клиентской области окна (внутри окна)
- wx.WindowDC - рисование во всем окне.
Рисование разной толщиной и цветом:
wx.Pen(wx.Colour=(colour), width=1, style=wx.SOLID)style'и такие:
- wx.SOLID - сплошная линия
- wx.DOT - линия из точек
- wx.LONG_DASH - линия из длинных отрезков
- wx.SHORT_DASH - пунктир
- wx.DOT_DASH - черточка-точка
- wx.TRANSPARENT - прозрачная линия
ЦВЕТ (wx.COLOUR) определяется как строка с шестью символами после номера #RRGGBB или же явным названием стандартного цвета типа 'LIGHT BLUE' согласно справочника: https://docs.wxpython.org/wx.ColourDatabase.html
Дополнительные параметры для рисования линий Pen'ом:
- join - способ сопряжения линий в точке соединения
- cap - способ прорисовки конца линии
Чтобы назначить эти параметры, используют следующие методы - Pen.SetJoin() и Pen.SetCat()
-
wx.JOIN_MITER - обычное сопряжение (по умолчанию)
-
wx.JOIN_BEVEL - создание фаски
-
wx.JOIN_ROUND - создание скругления;
-
wx.CAP_ROUND - скругленный конец линии (по умолчанию)
-
wx.CAP_PROJECTING - продолжает линию за граничную точка на величину ее толщины
-
wx.CAP_BUTT - рисует линию до конечной точки ровно, не переходя ее.
Еще есть варианты заливки рисуемых фигур при помощи класса Brush (Кисть):
Brush(colour, style=BRUSHSTYLE{wx.SOLID})style'и заливки такие:
- wx.SOLID - сплошная заливка
- wx.BDIAGONEL_HATCH - диагональная штриховка
- wx.CROSSDIAG_HATCH - диагональная штриховка крест-накрест
- wx.FDIAGONAL_HATCH - обратная диагональная штриховка
- wx.CROSS_HATCH - штриховка сеточкой
- wx.HORIZONTAL_HATCH - горизонтальная штриховка
- wx.VERTICAL_HATCH - вертикальная штриховка
- wx.TRANSPARENT - прозрачная заливка
для этого нужно предв. создать свое png изображение в квадратной ячейке в которой будет образец заливки, файл напр., filling_patter.png, затем строчка вида:
dc.SetBrush(wx.Brush(wx.Bitmap('filling_patter.png')))По сути, т.обр. можно формировать заливку заднего фона окна в виде различных тайловых обоев.
GradientFillLinear(self, rect, initialColour, destColour, nDirection=RIGHT)- rect - прямоугольная область заливки
- initialColour - начальный цвет заливки
- destColour - конечный цвет заливки
- nDirection - направление перехода(градиента)
Пример гр.заливки:
dc.GradientFillLinear((10, 280, 660, 65), '#cc0000', '#4E4EF4', wx.EAST)