Знакомство с wxPython. Часть первая. Первые шаги

    Доброго времени суток!

    image

    Введение


    Когда-то я вам уже рассказывал о связке Ruby/Tk. Сегодня я собираюсь продолжить знакомство с «быстрыми интерфейсами». На этот раз я расскажу вам о wxPython, а писать мы будем на Python.
    На самом деле, wxPython является лишь обёрткой для библиотеки wxWidgets, который в свою очередь представляет графический тулкит, который позволяет писать кроссплатформенные приложения.


    Что же такое xWidgets


    wxWidgets (ранее известная как wxWindows) — это кросс-платформенная библиотека инструментов с открытым исходным кодом для разработки кроссплатформенных на уровне исходного кода приложений, в частности для построения графического интерфейса пользователя (GUI).
    Она разработана не только для того, чтобы создавать GUI. Она также имеет набор классов для работы с графическими изображениями, HTML, XML документами, архивами, файловыми системами, процессами, подсистемами печати, мультимедиа, сетями, классы для организации многопоточности, отладки, отправки дампов и множество других инструментов.

    Итак, приступим


    Что же, начнём. А начнём мы по порядку — напишем Hello, World, чтобы понять базовые принципы построения приложения с помощью wxPython. Вот он, пред вами , государь:

    import wx
    
    app = wx.App()
    wnd = wx.Frame(None, wx.ID_ANY, "I'm the title")
    wnd.Show(True)
    app.MainLoop()
    

    Вы можете скачать исходный код.

    Сначала давайте запустим приложение и посмотрим, что у нас получилось. Сказано — сделано.



    Разбор полётов


    Хорошо, теперь пора разобраться в том, что делает данный код. Овсянку, сэр!

    import wx
    

    Тут всё более, чем очевидно. Тут мы импортируем пакет для работы с wxPython.

    app = wx.App()
    

    Здесь происходит создание экземпляра нашей программы, которая впоследствии и будет запущена.

    wnd = wx.Frame(None, wx.ID_ANY, "I'm the title")
    

    Думаю, что здесь нам следует немного остановится и посмотреть на код Собственно, здесь мы создаём экземпляр нашей формы (в терминологии wxWidgets это окно).
    Давайте посмотрим на заданные параметры.
    1. Parent — наш первый параметр. В данный момент он указывает на то, что это главное окно нашей программы и оно не наследованно от какого-либо другого.
    2. Id — идентификатор, который представляет собой ничто иное, как порядковый номер окна. Здесь нам не обязательно проставлять номера вручную, достаточно лишь указать wx.ID_ANY, который сам обо всём позаботится.
    3. Title — без комментариев… Это заголовок нашего окна.

    wnd.Show(True)
    

    Здесь мы указываем на то, что наше окно должно стать видимым.

    app.MainLoop()
    

    И, наконец, запускаем нашу программу. Вот и всё…

    Начинаем строить


    Предполагается, что вы уже ознакомились с Classes Reference и знаете, какие элементы GUI доступны в wxPython. Я предлагаю нам взять и написать что-либо целостное и рабочее. Хорошо. Давайте с вами напишем миниатюрный текстовый редактор.

    Добавляем поле для ввода текста

    Как вы знаете, текстовое поле в wxPython представленно классом TextCtrl. По умолчанию, текстовое поле, которое мы создаём является однолинейным, т.е. запись текста будет производиться в одну строку.
    Давайте исправим это и добавим атрибут style со значением TE_MULTILINE к объекту TextCtrl. Код нашего первого текстового редактора будет выглядеть так:

    import wx
    
    class Window(wx.Frame):
    
    	def __init__(self, parent, title):
    		wx.Frame.__init__(self, parent, title = title, size = (300,250))
    		self.control = wx.TextCtrl(self, style = wx.TE_MULTILINE)
    		self.Show(True)
    
    app = wx.App()
    wnd = Window(None, "pyNote")
    app.MainLoop()
    

    Вы можете скачать исходный код.

    Давайте запустим нашу программу и убедимся, что всё работает.



    Примечание: совсем забыл. Хотел добавить, что я предпологаю, что вы знакомы с ООП в Python, т.к. объяснять, что такое self или class Window(wx.Frame) я не собираюсь.

    Официант, меню будьте добры

    Как-то суховато выглядит наш с вами редактор, да? Конечно, в нём нету даже меню. Давайте исправим положением и создадим меню. В этом нет ничего сложного.

    import wx
    
    class Window(wx.Frame):
    
    	def __init__(self, parent, title):
    		wx.Frame.__init__(self, parent, title = title, size = (300,250))
    		self.control = wx.TextCtrl(self, style = wx.TE_MULTILINE) # создаём текстовое поле
    		self.Show(True)
    
    		menu = wx.Menu() # создаём экземпляр меню
    		menu.Append(wx.ID_ABOUT,"About","Push the button to get an information about this application") # добавляем подпункты к меню
    		menu.Append(wx.ID_EXIT,"Exit","Push the button to leave this application") # а как ещё?
    		bar = wx.MenuBar() # создаём рабочую область для меню
    		bar.Append(menu,"File") # добавляем пункт меню
    		self.SetMenuBar(bar) # указываем, что это меню надо показать в нашей форме
    app = wx.App()
    wnd = Window(None, "pyNote")
    app.MainLoop()
    

    Вы можете скачать исходный код.

    А вот и наш редактор с меню:



    Обработка событий

    Но что это? Мы нажимаем «Exit», а программа не завершается. Что же, пора перейти к достаточно важному этапу — научить программу обрабатывать события. Добиться этого можно несколькими способами. Например, вот так:

    def __init__(self, parent, title):
         self.Bind(wx.EVT_MENU, self.OnAbout, aboutItem)
    

    Данное выражение означает, что если мы кликнем пункт «About», то наша программа вызовет функцию OnAbout.

    Хорошо, давайте объявим эту функцию. Выглядеть она будет так:

    def OnAbout(self, e):
            dlg = wx.MessageDialog(self, "This is a mini editor keeping your text","About pyNote", wx.OK) # создаём всплывашку
            dlg.ShowModal() # показываем окошко
    


    Вот и всё. Теперь, когда мы ткнём в «About», увидим вот такое сообщение:



    Полный код приводить не стану, а скажу лишь, что…
    Вы можете скачать исходный код.

    Монолог? Нет, диалог!

    Не будем забывать, что мы пишем какой-никакой текстовый редактор. Поэтому нам нужно организовать процесс открытия/закрытия файлов. На помощь приходит Чип и Дейл FileDialog. Для начала нам необходимо создать пункт «Open» в меню, по которму будет вызван диалог открытия файла (функция OnOpen).
    Теперь нам нужно создать экземпляр FileDialog с некоторыми параметрами. Сейчас всё увидите:

    import wx
    import os
    
    class Window(wx.Frame):
    
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title = title, size = (300,250))
            self.control = wx.TextCtrl(self, style = wx.TE_MULTILINE)
            self.Show(True)
    
            menu = wx.Menu()
            openItem = menu.Append(wx.ID_ANY, "Open", "Push the button to open the file")
            aboutItem = menu.Append(wx.ID_ABOUT,"About","Push the button to get an information about this application")
            exitItem = menu.Append(wx.ID_EXIT,"Exit","Push the button to leave this application")
            bar = wx.MenuBar()
            bar.Append(menu,"File")
            self.SetMenuBar(bar)
            self.Bind(wx.EVT_MENU, self.OnOpen, openItem)
            self.Bind(wx.EVT_MENU, self.OnAbout, aboutItem)
            self.Bind(wx.EVT_MENU, self.OnExit, exitItem)
    
        def OnAbout(self, e):
            aboutDlg = wx.MessageDialog(self, "This is a mini editor keeping your text","About pyNote", wx.OK)
            aboutDlg.ShowModal()
    
        def OnOpen(self, e):
            self.dirname = " "
            openDlg = wx.FileDialog(self, "Choose a file to open", self.dirname, " ", "*.*", wx.OPEN) # создаём диалог
            if openDlg.ShowModal() == wx.ID_OK: # при выборе файла
                    self.filename = openDlg.GetFilename() # ловим название файла
                    self.dirname = openDlg.GetDirectory() # и папку, в которой он находится
                    f = open(os.path.join(self.dirname,self.filename), "r") # открываем файл
                    self.control.SetValue(f.read()) # отображаем в текстовом поле
                    f.close()
                    wnd.SetTitle(self.filename + " - pyNote") # меняем заголовок окна
    
    app = wx.App()
    wnd = Window(None, "pyNote")
    app.MainLoop()
    

    Вы можете скачать исходный код.

    Вот и всё. Давайте запустим наше творение. И, внимание… Барабанная дробь… Нажимаем на «Open» и видим…



    И открываем файл…



    Заключение


    Вот и всё на данный момент. Сегодня мы познакомились с великолепным тулкитом под названием wxPython, который позволяет писать великолепные приложения с минимальными затратами сил.

    Что почитать


    wxWidgets — Википедия.
    Getting Started — wxPyWiki.
    Официальный сайт wxPython.
    wxPython on Zetcode.

    Продолжение следует!
    Метки:
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 59
    • +1
      Обязательно стоит сказать про GUI-редакторы, позволяющие очень сильно упростить проектирование всех элементов пользовательского интерфейса и сгенерировать python код. Например, wxGlade, VisualWx. Хотя скажу по опыту, эти редакторы в удобстве конечно уступают, например, тому же QtCreator.
      • +1
        Стоит. Это будет сделано немного позже.
        • +2
          Qt они уступают, что неудивительно. Сравни размеры сообществ и активность выхода новых версий Qt и wxWidgets.
          • 0
            Извините за мой вопрос, ибо пока нуб. А разве есть QtCreator для pyside? Я его запускаю, он мне предлагает сделать проект на C++.
            • +1
              Не скажу вам точно, ибо такими вещами не пользуюсь, но думаю, что нет и он заточен только под приложения, написанные на C++.
          • +6
            для wxPython есть гуи для автоматизации разработки, я использую wxFormBuilder, не идеал, но мне очень нравится и бесплатно, правда пишу на С++, но там можно генерить код и для питона
            • +1
              Не идеал, но лично я пользуюсь именно им. Больше всего по нраву пришёлся.
            • НЛО прилетело и опубликовало эту надпись здесь
              • 0
                В с++ных виджетах точно можно, правда с шаманством.
                • +1
                  Если использовать wxWidgets, то всё будет нормально. Как было отмечено, после небольшого танца с бубном.
                  • НЛО прилетело и опубликовало эту надпись здесь
                    • +1
                      Так и есть. Именно под Standalone.
                • +1
                  И че меня дернуло 3.2 поставить и начать учиться на нем?
                  • +1
                    Вы про Python?
                    • 0
                      угу
                      Столько раз уже споткнулся. Хорошо хоть pySerial заработал
                      • +3
                        Тоже стоял перед выбором несколько дней назад. Думал, или 2.7 или 3.1. Решил довериться 2.7. И вы знаете, не прогадал ведь.
                        • 0
                          эт точно
                          все скрипты под 2.7. Чаще всего работает скрипт 2to3, но не всегда, и с модулями, естественно сдохнешь его причесывать. Особенно если третий день только с языком знаком.
                        • +1
                          Всё-таки немного прогадал. Сегодня скачал Google App Engine и обнаружил, что он работает только с Python 2.5 :(
                    • +3
                      Расскажите, пожалуйста, как правильно написать прогресс-бар и не натолкнуться на GIL.
                      • 0
                        Через Thread и wx'овый Publisher?:)
                        • 0
                          Почитайте статью про потоки в wxPython, все достаточно просто. Пример прогресс бара показан здесь, только без потоков.
                          • 0
                            Я уже читал эту статью, но проблему она так и не помогла решить. Допустим, мне надо вызвать серию каких-то долгих действий, а на это время мне надо показать прогрессбар. Так вот, действия в треде вызываются нормально, но обновлять прогрессбар из треда нехорошо, так как действия могут быть разными по продолжительности и прогрессбар будет прыгать. Все события вида wx.PyTimer умирают, пока активны треды, так что обновлять прогресс по таймеру тоже не получается. Сейчас у меня работает небольшой велосипед, которые мне не нравится: используется multiprocessing, к которому в Process() ставится функция, вызывающая треды, процесс стартуется, а затем вызывается цикл по условию multiprocessing.Manager.Event.is_set() со sleep'ом внутри и обновлением прогресса.
                        • 0
                          Спасибо, все собираюсь начать изучать Wx. Меня интересует такие моменты: можно ли поставить фоновую картинку, убрать края у фрейма, если я в фотошопе нарисую красивую кнопку, я могу ее использовать?
                          • 0
                            Можно, фон — через wx.ClientDC()
                            dc = wx.ClientDC(self)
                            rect = self.GetUpdateRegion().GetBox()
                            dc.SetClippingRect(rect)
                            img = wx.Bitmap("image.jpg")
                            dc.DrawBitmap(img, 0, 0)


                            Края: style = wx.BORDER_NONE при создании фрейма

                            Кнопку c рисунком через wx.BitmapButton или wx.lib.platebtn.PlateButton

                            Прошу прощения, <code></code> не работают
                            • 0
                              Правильно ли я понимаю, что в tkinter такого сделать нельзя?
                              • 0
                                Не знаю, так как сам с Tkinter (в 2.6 она с большой буквы, в 3.0 с маленькой) не работал, wxPython к ней тоже не обращается. Полагаю, что фон всего фрейма можно будет сделать, подсунув Canvas, а вот остальное — вряд ли так просто, судя по краткому описанию.
                                • 0
                                  эх, кажется отсутствует сборка под 64 битный макось. Придется pyside изучать.
                                  • 0
                                    Я ошибся, есть оказывается версия под 64 битную макось, надо просто ставить девелоперскую версию cocoa
                            • +1
                              Достаточно использовать тег source с атрибутом lang = «python».
                              • 0
                                Он в предпросмотре не показывался, я и подумал, что не работает.
                                • +1
                                  import xz;
                                  
                                  class NoName:
                                  
                                       def __init__(self):
                                            print "Всё Python!";
                                  

                                  Всё Python. Всё работает, чего вы?
                                  • 0
                                    В предпросмотре не работает. Когда запостите — уже видно.
                                    import xz
                                    class aa:
                                    def __init__(self):
                                    print 'bb'

                                    • 0
                                      А нет, простите, я не прав. <source> а не <code>
                                      • +1
                                        Ну, а я про что вам и говорю. :)
                          • +1
                            Как актуально, сегодня как раз начал учить wxPython!
                            • +1
                              Буду рад, если эта серия статей вам поможет.
                            • 0
                              Спасибо, я вот тоже на днях GUI на нем делать начну.

                              А там в последнем листинге не должно быть еще строки «self.Bind(wx.EVT_MENU, self.OnOpen, openItem)» или чего-то подобного? я код не запускал, просто в глаза бросилось, что обработчик не ассоциирован с элементом меню.
                              • +1
                                Да, вы правы. Хабрапарсер съел код и не подавился. Приду на работу — внесу правку.
                                • +1
                                  Исправил. Ещё раз спасибо.
                                • 0
                                  Насколько кроссплатформенно это получается?
                                  Можно ли создать папку со всем необходимым для запуска на win и linux?
                                  • +1
                                    Программы на wxWidgets спокойно запускаются на Windows, Linux, и MacOS X.
                                    • 0
                                      Простите за занудство, но действительно ли можно скинуть «папочку на флешке» — чтоб она запустилась на компьютере пользователя (будь там Xp,7 или Убунта)?
                                      Подразумевается наличие exe (cmd) и *.sh — файла.
                                      Можете выложить например Helloworld (или чуть сложнее) — я б проверил?
                                      • +1
                                        Конечно можно. Тем более, что речь не об инсталяции, а о запуске. Т.е. мы в любом случае имеем портативное приложение.
                                        • +1
                                          Извините, промахнулся. ответил ниже.
                                    • +1
                                      Поделюсь ссылкой на самый лучший туториал, на мой взгляд, по которому сам изучал wxPython.
                                    • 0
                                      Одновременно с этим вы должны помнить, что exe вы сможете запустить на Linux и Mac OS X только лишь с помощью средств виртуализации. Если же хотите не танцевать с бубном лишний раз, нужно код скомпилировать в исполняемый файл на каждой платформе. Как-то так.
                                      • 0
                                        Пишу проект используя wxPython уже 4 месяца. Либа великолепная! Куча возможностей. Документация, правда, хромает на обе ноги (английская естественная, русской документации вообще вроде как нет, да и не надо :) ).
                                        • 0
                                          Проект опенсорсный или коммерческий?
                                          Насчёт библиотеки — поддерживаю. Прекрасная вещь.
                                          • 0
                                            Опенсорсный (по крайнем мере пока что я не планирую его продавать), моя дипломная тема — «Разработка приложения для оценки качества данных»
                                            • 0
                                              Довольно интересно. Можно ссылочку на ваше творение?
                                              • 0
                                                Пока что там только интерфейс и базовая оценка по нескольким параметрам. Если все равно интересно, подскажите ресурс куда выложить чтобы Вы смогли посмотреть.
                                                • 0
                                                  На любой файлообменник. На ifolder, например. Или же на мыло — krovatti@gmail.com.
                                        • 0
                                          Вторую часть ждать в 2013-ом? :)
                                          • 0
                                            Судя по всему)

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.