Для работы с графическим интерфейсом вообще :
Меньше значит больше
Работа с графическим интерфейсом (даже в продуктивных рамках) примерно такая же увлекательная и продуктивная, как рисование Эйфелевой башни зубной щеткой. Перейти на минимальный дизайн.
Избегайте государства, как чума
Вы помещаете состояние в графический интерфейс или в модель? Если вы поместите его в графический интерфейс, вы будете путаться с избыточными и непоследовательными путями кода. Если вы поместите это в модель, вы рискуете слишком сложной системой, которая не синхронизируется, когда ваш графический интерфейс не обновляется из модели. Оба сосут.
WxPython
Если вы хотите изучить wxPython, вот несколько ловушек, которые я заметил:
Учебник
Использовать этот урок - http://wiki.wxpython.org/AnotherTutorial
Это лучший, который я нашел.
Но не забывайте переключать номера строк для простоты вставки.
События
События немного похожи на исключения, и они используются, чтобы сделать вещи интерактивными.
В программе vanilla python вы пишете что-то вроде:
def doit(i):
print 'Doing i = ',i
for i in range(10):
doit()
print 'Results = ',result
В графическом интерфейсе вы делаете что-то вроде:
def doit(event):
print 'An event',event,'just happened!'
event.Skip()
import wx
app = wx.App()
frame = wx.Frame(None, -1, 'The title goes here')
frame.Bind(wx.EVT_KEY_DOWN, doit)
frame.Show()
app.MainLoop()
Каждый раз, когда пользователь нажимает клавишу, событие вызывается. Поскольку frame
привязано к событию (frame.Bind(wx.EVT_KEY_DOWN, doit)
), функция doit
будет вызываться с событием в качестве аргумента.
Печать в stderr не слишком горячая в графическом интерфейсе, но doit также может вызвать диалог или сделать все, что вы захотите.
Также вы можете создавать свои собственные события, используя таймеры.
Приложения, рамки, окна, панели и размеры
У всего есть родитель. Если событие возникает, и потомок не пропускает его (используя event.Skip()
), тогда родитель также должен будет обработать событие. Это аналогично исключениям, поднимаемым до функций более высокого уровня.
A wx.App
аналогично основной функции.
wx.Window
на самом деле не используется. Материал наследуется от него, и у него есть все методы для определения размера и макета, но вам не нужно это знать.
wx.Frame
- это плавающая рамка, как и главное окно в Firefox. Вы будете иметь основной кадр в базовом приложении. Если вы хотите редактировать несколько файлов, то у вас может быть больше. У wx.Frame обычно не бывает родителей.
wx.Panel
является частью родительского окна. Вы можете иметь несколько панелей внутри рамки. Панель может иметь wx.Frame
в качестве родительского элемента или дочернего элемента другой панели.
wx.Sizers
используются для автоматического размещения панелей внутри фреймов (или других панелей).
Код:
def doit1(event):
print 'event 1 happened'
def doit2(event):
print 'event 2 happened'
import wx
app = wx.App()
frame = wx.Frame(None, -1, 'The title goes here')
panel_1 = wx.Panel(frame,-1,style=wx.SIMPLE_BORDER)
panel_2 = wx.Panel(frame,-1,style=wx.SIMPLE_BORDER)
panel_1.Bind(wx.EVT_KEY_DOWN, doit1)
panel_2.Bind(wx.EVT_KEY_DOWN, doit2)
panel_1.SetBackgroundColour(wx.BLACK)
panel_2.SetBackgroundColour(wx.RED)
box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(panel_1,1,wx.EXPAND)
box.Add(panel_2,1,wx.EXPAND)
frame.SetSizer(box)
frame.Show()
app.MainLoop()
Я был действительно плох, и не использовал практики ООП. Просто помните, что даже если вы ненавидите ОО в большинстве случаев, программирование с помощью графического интерфейса - это то место, где ООП действительно сияет.
MCV
Я не получаю MCV. Я не думаю, что вам нужен MCV. Я думаю, что MW (модель-виджет) рамки в порядке.
Например - 2 кадра, которые редактируют один и тот же фрагмент текста:
class Model(object):
def __init__(self):
self.value = 'Enter a value'
self.listeners = []
def Add_listener(self,listener):
self.listeners.append(listener)
def Set(self,new_value):
self.value = new_value
for listener in self.listeners:
listener.Update(self.value)
import wx
app = wx.App()
class CVFrame(wx.Frame):
def __init__(self, parent, id, title, model):
wx.Frame.__init__(self, parent, id, title, size = (100,100))
self.button = wx.Button(self, -1, 'Set model value')
self.textctrl = wx.TextCtrl(self, -1,model.value)
self.button.Bind(wx.EVT_BUTTON,self.OnSet)
self.model = model
model.Add_listener(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.button,0,wx.EXPAND)
sizer.Add(self.textctrl,1,wx.EXPAND)
self.SetSize((300,100))
self.SetSizer(sizer)
self.Center()
self.Show()
def OnSet(self,event):
self.model.Set(self.textctrl.GetValue())
def Update(self,value):
self.textctrl.SetValue(value)
model = Model()
frame1 = CVFrame(None, -1, 'Frame 1',model)
frame2 = CVFrame(None, -1, 'Frame 2',model)
app.MainLoop()
wxPython имеет среду слушателя-подписчика, которая является лучшей версией модели, которую я только что набросал (она использует слабые ссылки, поэтому удаленные слушатели не торчат и т. Д.), Но это должно помочь вам получить идея.