Сказ о wx.Python

    Здравствуй хабрхабр!

    В данной статье я хотел бы рассказать, сформулировать свои мысли по поводу такой замечательной библиотеки как wxPython. Под катом вы найдете небольшую теорию, описание форм, разбор свойств форм, различных контролов и всё что касается wxPython.
    Welcome to wxPython.


    the initial data



    Некоторая теория-вступление.

    1. wxPython in action (Russian) — русская версия книги (о её качестве и происхождении ничего сказать не могу, поскольку предпочитаю оригинал, а вот собственно и он — wxPython in action (English) — тут она стоит 54$ в бумажном виде (электронный вид, надеюсь, найдете сами). Общее мнение — книга отличная. Все подробно описано и написано. Конечно многие моменты не подробно расписаны, а кое-какие вещи лучше всего посмотреть в документации, но в общем и целом все примеры правдивы, рабочие. Книга отлично подойдет новичкам.

    2. wxPython 2.8 Application Development Cookbook. Данную книгу в русском варианте даже не пытался найти, ибо скорее всего её нет. Данная книга содержит в себе «рецепты» написания GUI форм, зачастую не тривиальны и не просты для разбора (хотя попытки разобраться каждую строчку в книге имеется. Читать довольно легко.

    3. python.su — отличный форум с хорошей базой топиков по различным темам. Не сочтите за рекламу, но он действительно хорош, жаль в последнее время не стабильно работает.

    4. habrahabr.ru — а вот тут меня ждало фиаско. На тот момент когда я смотрел, не было ни одной статьи по данной библиотеке. Только не давно промелькала маленькая статья основ (тех что в книжке написаны на первых страницах). Собственно уже тогда у меня зародилась идея по написанию данной статьи.

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

    1. wxPythom demos and docs. Это самый лучший пример любых контролов и форм написанных с использованием библиотеки wxpython. Там вы найдете примеры различных форм и контролов, списков, деревьев и различные их комбинации. Исходники этих всех примеров не богаты комментариями, поэтому даже хорошо что я её нашел потом уже, когда понимал что к чему, это очень сильно облегчало понимание того что происходит.

    2. wxFormBuilder — приложение-конструктор форм и контролов для wxPython ( и не только ). Данное приложение я обнаружил когда написал руками около 30 форм. Т.е. руками было написано все, от размеров формы, до использования различных типов сайзеров и их свойства. Тогда я смог просто экономить время, по скольку знал что и куда, как и почему. Данное приложение не обладает полным функционалом всей библиотеки, и это понятно, wx сложная и очень объемная библиотека, полное написание конструктора библиотеки займёт огромное количество времени, да и особой необходимости в этом нет. Кидаться и делать формы при помощи данного приложения сразу не стоит, тогда вы не уловите и 30% всего функционала библиотеки и ваш интерфейс ограничится тремя кнопками и двумя событиями.

    introduction



    Прежде чем начать углубляться в различные виды окошек и их свойства, необходимо усвоить несколько моментов, без которых будет сложно понять что и как должно быть:
    1. Все элементы должны находиться в сайзере. Сайзер (wx.Sizer) это некий невидимый элемент формы, который обозначает местоположение всех компонентов формы.
    2. Иерархия следующая: Форма (wx.Frame) на ней расположен сайзер, в сайзер добавлен контейнер — панель (wx.Panel), на панели добавлен еще один сайзер, и уже в данный сайзер добавляются все элементы формы.
    3. Неправильно добавлять компонент на панель, не добавляя его в сайзер ( а wxFormBuilder и не позволит вам этого).
    4. Свойства всех контролов можно не прописывать полностью. Допустим, если вам не важен размер поле для текстового ввода, то автоматически оно построится стандартным.

    basic elements



    В wx есть формы нескольких типов:
    wx.Dialog — диалоговое окно.
    wx.Frame — обычная форма представляющая собой окошко со стандартным функционалом (свернуть (wx.ICONIZE), максимизировать (wx.MAXIMIZE), закрыть (wx.Close)).

    Обычное представление wx.Frame в коде:
    wx.Frame.__init__ ( self, parent=None, id = wx.ID_ANY, title = u"NameWindow", pos = wx.DefaultPosition, size = wx.Size( int,int ), style = wx.CAPTION  )
    


    Данная строчка кода инициализирует форму и рисует её используя введенные свойства. К слову говоря:
    wx.Frame.__init__ (self, parent = None)
    

    Тоже нарисует форму, а все свойства форму будут стандартными.

    self и parent два обязательных параметра любой формы.

    Разберем инициализацию формы:
    self обозначает принадлежность к классу, parent — родитель этого окна. id — каждый элемент, окно имеет собственный id, чтобы обращаться или присваивать элементу действие, событие. Можно не заморачиваться с этим и ставить -1 или wx.ID_ANY — что формализует собой любой id (Каждый элемент должен иметь свой уникальный id, который можно использовать для обращения или для присваивания действий элементу; если это не требуется, то в качестве id можно задавать значение wx.ID_ANY, которое, фактически, равно -1.). title — заголовок окна, pos — расположение формы по координатам x и y на экране, size — размер формы в пикселях, style — стиль окна. Всевозможные стили вы можете посмотреть в документации. Отмечу несколько:
    wx.CAPTION — отображает верхний бар с заголовком, но без системного меню; wx.STAY_ON_TOP — оставаться поверх окон других приложений, хочется отметить одну деталь: в случае если несколько окон будут иметь данный стиль, на самом «топе» останется то окно, которое будет выше в родительской иерархии в приложении; wx.SYSTEM_MENU — на верхнем баре появляется кнопка «закрыть», но при этом она не активна;

    Отличия Dialog от Frame следующие:
    1. Dialog модальное окно, т.е. до тех пор, пока не выполнишь действия в этом окне, пользователь не сможет перейти в какое либо еще окно открытое
    этим приложением.
    2. Dialog окно содержит в себе уже панель, поэтому для диалогового окна необходим только сайзер и все элементы уже располагать на этом сайзере.
    3. Диалоговое окно может обойтись без дополнительных событий на кнопки (об этом позже).

    Обилие различных контролов, которыми обладает библиотека поражает воображение. Здесь есть всё, от кнопок до ноутбука с вкладками (их, причем, несколько видов).

    Рассказывать здесь обо всём подряд бессмысленно, это затянется на несколько месяцев, поэтому вкратце пробежимся по нескольким элементам, объяснив моменты, которые стандартные практически для всех контролов и элементов.

    Простейшие элементы показаны в следующем куске кода:

    class regexps ( wx.Frame ):
        def __init__( self, main, schema, table, connection ):
    		wx.Frame.__init__ ( self, parent=None, id = wx.ID_ANY, title = u"Data Quality -- Выбор и отладка регулярных выражений", 
                                pos = wx.DefaultPosition, size = wx.Size( 510,477 ), style = wx.CAPTION|wx.STAY_ON_TOP|wx.TAB_TRAVERSAL )	
            sizer1 = wx.BoxSizer( wx.HORIZONTAL )
            self.regexps_notebook = wx.Notebook( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
            self.dq_params_tab = wx.Panel( self.regexps_notebook, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
    

    Инициализация окошка типа wx.Frame, как видите все свойства присутсвуют. Некоторые из них отданы стандартным значениям. Здесь стоит обратить внимание на компоновку стилей. Мы получаем окошко с верхним баром, и системным меню в виде неактивной кнопки «Закрыть». Также, окно будет всегда активно (wx.STAY_ON_TOP). Объявление сайзера. Тип сайзера wx.BoxSizer — это коробка. Все эдементы выстраиваться друг за другом в линию либо по горизонтали, либо по вертикали (за это отвечает аргумент передаваемый сайзеру, в данном случае это wx.HORIZONTAL). Объявление ноутбука(панель с вкладками). Для начала ему дано имя: self.regexps_notebook, чтобы можно было образаться к нему из любого метода класса. Далее идет объявление компонента wx.Notebook со свойствами.Объявление панели, которая помещается на ноутбук. Заметьте, что панель помещаемая на ноутбук будет являться площадкой для всех вкладок. Также, помещение панели в роли вкладки ноутбка не требует отдельного сайзера (это противоречит тому что все элементы должны быть в сайзерах, т.е. это является исключением из этого правила)

            sizer2 = wx.BoxSizer( wx.VERTICAL )
            self.use_param_checkbox = wx.CheckBox( self.dq_params_tab, wx.ID_ANY, u"Использовать параметр", wx.DefaultPosition, 
                                                   wx.DefaultSize, 0 )
    

    Объявление второго сайзера. Минимальный размер сайзера. Добавляем новый компонент чекбокс. Добавляем его на панель self.dq_params_tab, т.е. на вкладку ноутбука.

            sizer2.Add( self.use_param_checkbox, 0, wx.ALL, 5 )
            self.params_quality_choices = [1,2,3,4,5,6,7,8,9,10]
            
            self.params_choice_pull = wx.Choice( self.dq_params_tab, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 
                                                 self.params_quality_choices, 0 )
    		# Обозначение индекс варианта, который будет выбран изначально после инициализации элемента wx.Choice.
            self.params_choice_pull.SetSelection( 0 )
            
    		# Добавлени на вкладку статической линии. 
            self.static_line = wx.StaticLine( self.dq_params_tab, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
    

    Важный момент. Добавление созданного чекбокса на сайзер, этот тот сайзер который лежит на панели (вкладке).Добавление имеют следующую структуру: sizer2 — созданный сайзер, Add — вызываем метод Добавления элемента, и аргументы метода Add: что добавляем(self.use_param_checkbox, wx.ALL — это параметр отображения, в данном случае элменет будет показан в весь размер, 0(это пропорциональность элемента и 5 (это размер бордюров элемента) Далее идет объявление выпадающего списка со значениями. Собственно self.params_quality_choices это список значений. Далее уже сам элемент wx.Choice, который тоже помещается на вкладку.


            sizer2.Add( self.static_line, 0, wx.EXPAND |wx.ALL, 5 )
            self.static_text = wx.StaticText( self.dq_params_tab, wx.ID_ANY, u"Ввод весового коэффициента", wx.DefaultPosition, 
                                              wx.DefaultSize, 0 )
            sizer2.Add( self.static_text, 0, wx.ALL, 5 )
            self.weights_txt = wx.TextCtrl( self.dq_params_tab, validator = WeightsValidator() )
            sizer2.Add( self.weights_txt, 0, wx.ALL, 5 )
    

    Вот тут у нас появилась дополнительная опция. wx.EXPAND — это означает что добавляемый элемент будет растягиваться по ширине, в завимимости это своего размера. Добавление текстового поля для ввода wx.TextCtrl. Здесь есть дополнительная опция validator. Об этом будет расказано в другом коде.

            self.dq_params_tab.SetSizer( sizer2 )
            self.dq_params_tab.Layout()
            sizer2.Fit( self.dq_params_tab )
    		
    		# Добавление вкладки на панель.
            self.regexps_notebook.AddPage( self.dq_params_tab, u"Параметры оценки", False )
            self.regexps_tab = wx.Panel( self.regexps_notebook, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
            sizer3 = wx.BoxSizer( wx.VERTICAL )
    

    Пришли к интересному моменту. После добавления всех элементов на сайзер (sizer2), который на панели (self.dq_params_tab), необходимо «расширить» сайзер на всю площадь панели и закрепить сайзер на панели.

    		regexps_listboxChoices = []
            self.regexps_listbox = wx.ListBox( self.regexps_tab, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 
                                               regexps_listboxChoices, wx.LB_HSCROLL|wx.LB_SINGLE )
            
    		# Объявление грида (wx.grid.Grid). Это каркас таблицы, как в mysql, oracle, sqlite and etc. В опциях указан размер, и наличие скроллов.
            self.check_grid = wx.grid.Grid( self.check_sql_tab, wx.ID_ANY, wx.DefaultPosition, wx.Size(480,407), wx.HSCROLL|wx.VSCROLL )
            
    		# Создание непосредственно грида, количества колонок и строк.
            # Grid
            self.check_grid.CreateGrid( 5, 5 )
    		
    		# Задание свойств грида.
            self.check_grid.EnableEditing( False )
            self.check_grid.EnableGridLines( True )
            self.check_grid.EnableDragGridSize( False )
            self.check_grid.SetMargins( 0, 0 )
            
    		# Задание свойств колонок
            # Columns
            self.check_grid.EnableDragColMove( False )
            self.check_grid.EnableDragColSize( False )
            self.check_grid.SetColLabelSize( 20 )
            self.check_grid.SetColLabelAlignment( wx.ALIGN_CENTRE, wx.ALIGN_CENTRE )
            
    		# Свойства строк.
            # Rows
            self.check_grid.AutoSizeRows( True )
            self.check_grid.EnableDragRowSize( True )
            self.check_grid.SetRowLabelSize( 40 )
            self.check_grid.SetRowLabelAlignment( wx.ALIGN_CENTRE, wx.ALIGN_CENTRE )
    

    Добавление листбокса (wx.ListBox). Опции wx.LB_HSCROLL|wx.LB_SINGLE говорят о наличии горизонтального скрола и о том, что выделять можно только один элемент в списке. Создание грида. Далее все в комментариях описано.

    Синтаксис отступлений немного не понятен, так как строки имеют большую длинную. Таков уж синтаксис библиотеки.

    В коде пропущены похожие конструкции и расположение элементов, но если запустить полный код всего модуля увидим мы следующее (если кого интересует полный код — пишите):


    1-ая вкладка

    2-ая вкладка

    3-тья вкладка.

    building list control



    Разобрав некоторые простейшие элементы перейдем к более сложным вещам.

    Лист контрол универсальный элемент и мы его видим очень часто в различных приложениях.

    Сейчас мы разберем код построения лист контрола для случайных данных.

    class main_stat(listmix.ColumnSorterMixin): 
        def __init__( self, rows, columns ):     
            data = []
    		self.columns = columns
    		self.rows = rows
            self.list = wx.ListCtrl(self.main.panelMainStat, 0,
                                     style=wx.LC_REPORT | wx.BORDER_NONE | wx.LC_EDIT_LABELS | wx.LC_SORT_ASCENDING | wx.LC_SINGLE_SEL)
    

    Объявление класса в качестве аргумента передаем компонент listmix'a для сортировки данных по колонкам. Далее происходит инициализация листконтрола в котором происходит всё самое сокровенное.
    Передаем в него наименование колонок (columns) и строки (rows). Длина списка со строками должна равняться длине списка с наименованием колонок. Обзываем листконтрол self.list и прописываем ему свойства.
    По поводу свойств: стиль wx.LC_REPORT — листконтрол в виде наименований колонок сверху, все данные под колонками, как таблица, некое подобие. Остальные стили итак понятны исходя из перевода с английского.

            for col, text in enumerate(self.columns):
                self.list.InsertColumn(col, text) 
            for item in rows:   
                info = '%s:(%s)' % (col, item)
                data.append(info)
                index = self.list.InsertStringItem(sys.maxint, item[0]) 
                for col, text in enumerate(item[1:]): 
                    self.list.SetStringItem(index, col+1, text) 
    

    Далее чутка хитрый алгоритм формирования данных. К wx это особого отношения не имеет, поэтому подробно раписывать не буду. Но смысл в том,
    что данные для лист контрола должны быть следующего вида:
    rows = { 1:(«data0», «data0.1», «data0.2»), 2:(«data1», «data1.0», «data1.1», «data1.2»),… }
    Приведенный выше алгоритм приводит случайные данные к такому виду.

            self.list.SetSize((900, 200))        
            self.list.SetColumnWidth(0, 120)   
            self.list.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list)
            self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightClick)
            self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
            self.itemDataMap = data
            listmix.ColumnSorterMixin.__init__(self, 3)
    

    Выставляем размер листконтрола, размер колонки и биндим события (об этом подробнее будет дальше). Далее идет не совсем рабочий кусок кода, поскольку
    self.itemDataMap должны равняться данным приведенным к виду как показано выше, на данные момент данные сразу заносятся в листконтрол, без сортировки.

        def getColumnText(self, index, col):
            item = self.list.GetItem(index, col)
            return item.GetText()
        
        def OnRightClick(self, event):
            index = self.list.GetFirstSelected()
    		print index
            
        def OnColClick(self, event):
            print ("OnColClick: %d\n" % event.GetColumn())
            event.Skip()
        
        def OnItemSelected(self, event):
            self.currentItem = event.m_itemIndex
            self.data = (self.getColumnText(self.currentItem, 1),
                                self.getColumnText(self.currentItem, 2),
                                self.getColumnText(self.currentItem, 3),
                                self.getColumnText(self.currentItem, 4))( True )
    


    Правый клик по строке с данными выведет нам порядковый номер этой строки. Метод OnColClick выдаст нам порядковый номер колонки. А при выделении строки с данными, нам в переменную
    self.data будет записан список с данными которые мы выделили ( как раз такие здесь, используется метод getColumnText, при помощи него мы вытаскиваем данные из каждой колонки.


    Пример построенного листконтрола.

    menu



    Теперь, давайте перейдем в неотъемлемой части любого приложения — меню.
            self.menubar = wx.MenuBar( 0 )
            self.BD = wx.Menu()
            self.m_menuItem1 = wx.MenuItem( self.BD, 1, u"Подключиться к базе", u'Выполнить подключение к базе данных', wx.ITEM_NORMAL )
            self.BD.AppendItem(self.m_menuItem1, )
            
            self.m_menuItem2 = wx.MenuItem( self.BD, 2, u"Выбрать таблицу\tCtrl+T", u'Выбрать схему и таблицу для оценки качества данных', wx.ITEM_NORMAL )
            self.BD.AppendItem( self.m_menuItem2 )
            
            self.m_menuItem3 = wx.MenuItem( self.BD, 3, u"Отключиться и выйти\tCtrl+Q", u'Отключиться от базы данных в выйти из приложения', wx.ITEM_NORMAL )
            self.BD.AppendItem( self.m_menuItem3 )	
    

    Объявление menubar. Менюбар это полоса где находится все пункты меню с выпадающими списками. self.BD = wx.Menu() — создание элемента меню, далее добавление
    пунктов меню в self.BD. Разберем подробней:
    self.m_menuItem1 = wx.MenuItem( self.BD, 1, u"Подключиться к базе", u'Выполнить подключение к базе данных', wx.ITEM_NORMAL )
    

    wx.MenuItem(в какое меню добавляем пункт меню, id, название\hotkey, текст-подсказка высвечиваемый в статусной строке (если она есть), тип пункта меню)
    После названия через \t (символ табуляции) идет хоткей, по нажатию на который пункт меню вызовется, если он активный. Обрабатывать дополнительно данное событие не надо.
    Типы пункта меню могут быть различными:
    wx.ITEM_RADIO — итем меню в видео радио-кнопки, wx.ITEM_CHECK — в виде чекбокса,
    Далее мы добавляем несколько пунктов меню по такой же схеме.

            self.statusbar = self.CreateStatusBar( 1, wx.ST_SIZEGRIP, wx.ID_ANY )
    		self.BD.Enable(2, False)
    		self.statusbar.SetStatusText(u'Это статусная строка, здесь будет информацию о текущем состоянии программы, а также подсказки по ходу работы с программой.')
    

    Создание статусной строки. И представляем один из пунктов меню неактивным. Активным его сделает аргумент True. Также мы добавляем текст в статусную строку сразу при инициализации класса.


    А вот и меню.

    event-driven environment



    Любой элемент, любая форма подвержены воздействию со стороны пользователя. При помощи библиотеки wxPython вы можете описать абсолютно любое действия пользователя, и не только пользователя, но и программы.
    Начнем с правил объявления событий. У нас есть кнопка:
    self.ok_btn = wx.Button( self.m_panel5, wx.ID_ANY, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 )
    

    И мы хотим чтобы по нажатию на кнопку программа складывала 2+2:
    self.ok_btn.Bind( wx.EVT_BUTTON, self.OnOk )
    # есть еще альтернативный синтаксис
    # self.Bind( wx.EVT_BUTTON, self.OnOk, self.ok_btn )
    def OnOk(self, event):
          a = 2+2
          print a
    

    Метод OnOk сработает на нажатие кнопки. Собственно это вся суть событий. Различия лишь в wx.EVT_BUTTON (в обрабатываемом событии) и элементе на который мы вешаем данное событие (в нашем случае это кнопка self.ok_btn.

    # 1
    self.Bind(wx.EVT_MENU, self.About, id=10)
    # 2
    self.Bind( wx.EVT_IDLE, self.OnInit )
    


    Событие №1 сработает на нажатие соответствующий пункт меню, а событие №2 при появлении простаивании формы (бездействии пользователя).

    validators



    Любое текстовое поле нуждается в проверке вводимых данных пользователем, дабы обезопасить его от ожидаемых ошибок. Для этого wx предлагает validators — самописные проверки. Самописные они, потому что встроенных проверок нет, каждый валидатор необходимо описывать.

    Вот пример с объяснениями:

    class Numbers(wx.PyValidator):
        def __init__(self):
            wx.PyValidator.__init__(self)
            self.Bind(wx.EVT_CHAR, self.OnChar)
    
        def Clone(self):
            return Numbers()
    
        def Validate(self, win):
            tc = self.GetWindow()
            val = tc.GetValue()
    
            for x in val:
                if x not in string.digits:
                    return False
    
            return True
    
    
        def OnChar(self, event):
            key = event.GetKeyCode()
            try:
                # 8 это код клавиши backspace
                if chr(key) in string.digits or chr(key) == '.' or key == 8:
                    event.Skip()
                else:
                    return False
            except ValueError, info:
                print chr(key)
                print info
            return     
    

    Создаем класс аргументом которого мы выдаем wx.PyValidator который говорит, о том что данный класс является валидатором.
    Метод OnChar описан событием self.Bind(wx.EVT_CHAR, self.OnChar), и будет исполнятся при вводе с клавиатуры символов. Командной key = event.GetKeyCode() мы ловим код каждого нажатия, а встроенная функция chr() переводит символ кода в обычное представление нажатой клавиши. string.digits содержит в себе список чисел от 0 до 9, также в классе string присутствуют практически все символы которые вводятся с клавиатуры, вплоть до hexdigits (к сожалению там есть даже asciiсимволы, но русский язык, на сколько я понял, туда не входит).

    Метод Validate.
    tc = self.GetWindow() определяет окно где находится текстовое поле, val введенное значение, далее цикл проверки. Данный валидатор не позволит пользователю нажать ни одну клавишу кроме цифр, точки и backspace. Кстати говоря, о backspace, wx описывает все клавиши, wx.WXK_Numpad0 например, а вот backspace там нет, есть всё, от F1 до Numlock, поэтому пришлось отследить значения клавиши.

    После написания валидатора необходимо определить текстовое поле и указать ему на валидатор, который ему соответствует.
    self.ip_ctrl = wx.TextCtrl( self.m_panel5, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 190,-1 ), 0, Numbers() )
    


    На этом собственно всё. Статья получилось очень объемной и немножко сумбурной. Всё потому что если начать описывать ВСЕ свойства и события которые могут быть привязаны, допустим, к wx.ListCtrl то статья получится даже больше чем эта. Если статья понравилась и есть смысл продолжать, то начну написание следующей, раскрывая другие элементы и фичи библиотеки, например wx.aui — это продвинутый notebook с вкладками, там есть где развернутся.

    Спасибо за внимание.

    ADDITION:
    Код
    class regexps ( wx.Frame ):

    def __init__( self, main, schema, table, connection ):

    wx.Frame.__init__ ( self, parent=None, id = wx.ID_ANY, ...)

    можно переписать более красиво через super:

    class regexps ( wx.Frame ):

    def __init__( self, main, schema, table, connection ):

    super (regexps, self).__init__ (parent=None, id = wx.ID_ANY, ...)

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

    Подробнее
    Реклама
    Комментарии 24
    • +3
      Пробовал, но мне не понравилось: Qt больше понравилась — более очевидно что-то делать, прозрачнее, быстрее.
      • +2
        По поводу дизайнера из всех мной перепробованных остановился на wxGlade. Правда, обычно я окно делаю дизайнером, потом удаляю весь его код, и, если нужно исправить окно, правлю код уже ручками.

        > Иерархия следующая: Форма (wx.Frame) на ней расположен сайзер, в сайзер добавлен контейнер — панель (wx.Panel), на панели добавлен еще один сайзер, и уже в данный сайзер добавляются все элементы формы.

        А зачем нужна промежуточная панель?

        Код
        class regexps ( wx.Frame ):
        def __init__( self, main, schema, table, connection ):
        wx.Frame.__init__ ( self, parent=None, id = wx.ID_ANY, ...)


        можно переписать более красиво через super:

        class regexps ( wx.Frame ):
        def __init__( self, main, schema, table, connection ):
        super (regexps, self).__init__ (parent=None, id = wx.ID_ANY, ...)


        В этом случае, если изменится базовый класс, то не нужно будет его исправлять еще и в конструкторе. Заодно параметр self в __init__ можно будет не передавать.
        • 0
          Промежуточная панель между формой и элементами?
          • 0
            А зачем она нужна, когда для расположения элементов все-равно используются сайзеры.
            • 0
              Ммм, без панели все ваши элементы будут на форме, на темном фоне. Попробуйте создать фрейм и на него положить элементы в сайзере, увидите что получится.
              • 0
                Странно, я часто так делаю, и фон вроде нормальный, серый.
        • 0
          А можно кратко описать преимущества и недостатки wxPython? Ну и сравнение с другими подобными библиотеками привести.
          • 0
            Красивее и сложнее. Это если совсем коротко.
            • +1
              wiki.wxwidgets.org/WxWidgets_Compared_To_Other_Toolkits
              По мне, wx сильно отдает MFC, собственно у них похожий подход.
              • +1
                Для меня главный плюс wx в том, что при его использовании под разные системы интерфейс выглядит как родной, потому что использует родное API. А то жутко раздражают, например, GTK-ые диалоги открытия файлов под виндой.
                • 0
                  GTK-ые диалоги открытия файлов под виндой
                  1.выглядят как родные(при использовании соотв.темы)
                  2. гораздо удобнее чем «родные»-например там есть закладки, командная строка и т.д.
                  • 0
                    1. Этим должны пользователи озадачиваться?

                    2. Я все-таки предпочитаю, чтобы под виндой программа выглядела виндовой, а под линуксом — линуксовой.
                    • 0
                      1. Установщик gtk рантайма.
                      • 0
                        Озадачиваться чем?
                        Диалог открытия файлов мало чем отличается от стандартного, при этом имеет несколько очень удобных добавлений.
                        Мне кажется это совсем не принципиальный момент.
                        GTK runtime под windows по умолчанию ставит тему, которая эмулирует вид/цвет окон windows.
                        Pygtk очень простая и гибкая библиотека, код получается намного компактнее, при этом набор виджетов намного меньше, чем для wxPython.Функционал скромнее.Это может служить некоторым плюсом для wx. Но сам wxPython довольно объёмен, и API довольно многословные и не очень питоновские.
                • 0
                  1. Этим должны пользователи озадачиваться?

                  2. Я все-таки предпочитаю, чтобы под виндой программа выглядела виндовой, а под линуксом — линуксовой.
                • 0
                  Думаю статью надо было начать с того, что такое wx.Python
                • +1
                  Продолжать статьи на эту тему или нет?
                  Есть еще такие элементы как дерево, popup окна, тул типы, rich text ctrl и еще много чего.
                  • 0
                    Конечно. Думаю, Ваш опыт будет полезен многим.
                  • 0
                    Разберем инициализацию формы:
                    self и parent мы уже разобрали. id — каждый элемент, окно имеет собственный id, чтобы обращаться к ней или присваивать ей действия, события, дополнительные элементы. Можно не заморачиваться с этим и ставить -1 или wx.ID_ANY — что формализует собой любой id (нет, id не берется случайно цифрой, это мнимый id).


                    Дальше читать пришлось себя заставлять. И где self и parent разобрали тоже не увидел.
                    • 0
                      Смысл, если есть официальный биндинг на Qt от Nokia, pyside? Его разрабатывает толпа народу, он есть под все платформы в виде удобный инсталляторов, он всегда синхронизирован с последней версией Qt.
                      • 0
                        Кроме того, есть PyQt которому уже больше десяти лет. Не менее прекрасен :)
                      • 0
                        Еще есть Boa Constructor — Python IDE — wxPython GUI Builder.
                        Проект довольно популярен, хотя последнее обновление от 2007-07-05.
                        Сам пользовал его для освоения wxPython на Windows и Ubuntu.
                        Все просто и удобно (для старта). Сейчас предпочитаю доделывать форму ручками.

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