Статьи

wxPython: руководство по работе с мастером

В этой статье мы рассмотрим Wizard-виджет wxPython. Нет, это не имеет ничего общего с Дамблдором или Гэндальфом. Вместо этого это тот диалог, который вы увидите при запуске установщика или настройке шаблона. Иногда вы даже увидите, как они используются для настройки слияния. В этом уроке мы рассмотрим два примера: один довольно простой, а другой немного более сложный. Давайте начнем!

Примечание: код в этой статье был адаптирован из демонстрационного приложения wxPython

Простой Мастер

Когда вам нужно использовать мастер в wxPython, вам нужно импортировать его особым образом. Вместо того, чтобы просто импортировать wx , вы должны будете сделать это: import wx.wizard . Также обратите внимание, что существует два основных типа страниц мастера: WizardPageSimple и PyWizardPage. Первый самый простой, поэтому мы будем использовать его в нашем простом примере. Вот код:

import wx
import wx.wizard as wiz
 
########################################################################
class TitledPage(wiz.WizardPageSimple):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self, parent, title):
        """Constructor"""
        wiz.WizardPageSimple.__init__(self, parent)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)
 
        title = wx.StaticText(self, -1, title)
        title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
        sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)
 
#----------------------------------------------------------------------
def main():
    """"""
    wizard = wx.wizard.Wizard(None, -1, "Simple Wizard")
    page1 = TitledPage(wizard, "Page 1")
    page2 = TitledPage(wizard, "Page 2")
    page3 = TitledPage(wizard, "Page 3")
    page4 = TitledPage(wizard, "Page 4")
 
    wx.wizard.WizardPageSimple.Chain(page1, page2)
    wx.wizard.WizardPageSimple.Chain(page2, page3)
    wx.wizard.WizardPageSimple.Chain(page3, page4)
    wizard.FitToPage(page1)
 
    wizard.RunWizard(page1)
 
    wizard.Destroy()
 
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    main()
    app.MainLoop()

Это довольно много кода. Давайте возьмем это на себя и посмотрим, сможем ли мы это выяснить. Прежде всего, мы импортируем wx и мастер, который мы переименуем в «wiz», чтобы сэкономить на нажатиях клавиш. Затем мы создаем класс TitledPage, который подклассов WizardPageSimple . Этот класс будет основой для всех страниц нашего мастера. Он в основном просто определяет страницу с центрированным заголовком 18-точечным шрифтом со строкой внизу.

В основной функции мы находим настоящее мясо. Здесь мы создаем мастер, используя следующий синтаксис: wx.wizard.Wizard (Нет, -1, «Простой мастер») . Это дает мастеру родителя None, идентификатор и название. Затем мы создаем четыре страницы, которые являются экземплярами класса TitledPage, о котором мы упоминали ранее. Наконец, мы используем wx.wizard.WizardPageSimple.Chain, чтобы связать страницы вместе. Это позволяет нам использовать пару автоматически сгенерированных кнопок для перемещения по страницам вперед и назад. Последняя пара строк кода запустит мастер и, когда пользователь закончит, уничтожит мастер. Довольно просто, правда? Теперь давайте перейдем к более сложному примеру.

Использование PyWizardPage

В этом разделе мы создадим подкласс PyWizardPage . У нас также будет подкласс WizardPageSimple, чтобы мы могли смешивать и сочетать их, чтобы создать серию разных страниц. Давайте просто перейдем к коду, чтобы вы могли убедиться в этом сами!

import images
import wx
import wx.wizard as wiz
 
########################################################################
class TitledPage(wiz.WizardPageSimple):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self, parent, title):
        """Constructor"""
        wiz.WizardPageSimple.__init__(self, parent)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer = sizer
        self.SetSizer(sizer)
 
        title = wx.StaticText(self, -1, title)
        title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
        sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)
 
########################################################################
class UseAltBitmapPage(wiz.PyWizardPage):
 
    #----------------------------------------------------------------------
    def __init__(self, parent, title):
        wiz.PyWizardPage.__init__(self, parent)
        self.next = self.prev = None
        self.sizer = wx.BoxSizer(wx.VERTICAL)
 
        title = wx.StaticText(self, label=title)
        title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
        self.sizer.Add(title)
 
        self.sizer.Add(wx.StaticText(self, -1, "This page uses a different bitmap"),
                       0, wx.ALL, 5)
        self.sizer.Layout()
 
    #----------------------------------------------------------------------
    def SetNext(self, next):
        self.next = next
 
    #----------------------------------------------------------------------
    def SetPrev(self, prev):
        self.prev = prev
 
    #----------------------------------------------------------------------
    def GetNext(self):
        return self.next
 
    #----------------------------------------------------------------------
    def GetPrev(self):
        return self.prev
 
    #----------------------------------------------------------------------
    def GetBitmap(self):
        # You usually wouldn't need to override this method
        # since you can set a non-default bitmap in the
        # wxWizardPageSimple constructor, but if you need to
        # dynamically change the bitmap based on the
        # contents of the wizard, or need to also change the
        # next/prev order then it can be done by overriding
        # GetBitmap.
        return images.WizTest2.GetBitmap()
 
#----------------------------------------------------------------------
def main():
    """"""
    wizard = wiz.Wizard(None, -1, "Dynamic Wizard",
                        images.WizTest1.GetBitmap())
    page1 = TitledPage(wizard, "Page 1")
    page2 = TitledPage(wizard, "Page 2")
    page3 = TitledPage(wizard, "Page 3")
    page4 = UseAltBitmapPage(wizard, "Page 4")
    page5 = TitledPage(wizard, "Page 5")
 
    wizard.FitToPage(page1)
    page5.sizer.Add(wx.StaticText(page5, -1, "\nThis is the last page."))
 
    # Set the initial order of the pages
    page1.SetNext(page2)
    page2.SetPrev(page1)
    page2.SetNext(page3)
    page3.SetPrev(page2)
    page3.SetNext(page4)
    page4.SetPrev(page3)
    page4.SetNext(page5)
    page5.SetPrev(page4)
 
    wizard.GetPageAreaSizer().Add(page1)
    wizard.RunWizard(page1)
    wizard.Destroy()
 
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    main()
    app.MainLoop()

Этот код начинается так же, как и предыдущий код. В этом примере мы также импортируем модуль изображений, который содержит пару объектов PyEmbeddedImage, которые мы будем использовать, чтобы продемонстрировать, как добавлять растровые изображения на нашу страницу мастера. В любом случае, первый класс точно такой же, как и предыдущий. Затем мы создаем класс UseAltBitmapPage, который является подклассом PyWizardPage . Мы должны переопределить несколько методов, чтобы заставить его работать правильно, но они довольно очевидны. Эта страница будет использоваться только для изменения растрового изображения одной страницы.

В основной функции мы создаем мастера немного иначе, чем мы делали ранее:

wizard = wiz.Wizard(None, -1, "Dynamic Wizard", images.WizTest1.GetBitmap())

Как видите, этот метод позволяет нам добавить растровое изображение, которое появится вдоль левой стороны страниц мастера. В любом случае, после этого мы создаем пять страниц, четыре из которых являются экземплярами TitledPage, а одна — экземпляром UseAltBitmapPage . Мы подгоняем мастера к первой странице и затем видим что-то странное:

page5.sizer.Add(wx.StaticText(page5, -1, "\nThis is the last page."))

Что это делает? Ну, это глупый способ добавить виджет на страницу. Чтобы сообщить пользователю, что он достиг последней страницы, мы добавляем к нему экземпляр StaticText, который явно сообщает, что он достиг конца. Следующие несколько строк устанавливают порядок страниц, используя SetNext и SetPrev . Хотя эти методы дают вам более детальный контроль над порядком страниц, они не так удобны, как метод WizardPageSimple.Chain . Последние несколько строк кода такие же, как в предыдущем примере.

Дополнительный совет: как пометить кнопки волшебника

При создании этой статьи кто-то спросил, как изменить метки кнопок мастера в официальном списке рассылки wxPython . Поэтому для полноты картины мы примем решение Робина Данна и покажем, как изменить метки как предыдущей, так и следующей кнопки.

prev_btn = self.FindWindowById(wx.ID_BACKWARD)
prev_btn.SetLabel("Foo")
next_btn = self.FindWindowById(wx.ID_FORWARD)
next_btn.SetLabel("Bar")

Завершение

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

Дальнейшее чтение

Исходный код

Источник: http://www.blog.pythonlibrary.org/2011/01/27/wxpython-a-wizard-tutorial/