wxPython 学习笔记之一
今天在读 wxPython 的 doc, 里面有个 demo.py 打开后是所有 demo 以及示例源码的大本营。这个程序做的非常有特色,在边看示例的时候可以看其中的源代码,还可以随时呼叫一个 demo,我才大致看了一两个文件,写一些笔记记录与此。(因为之前也没学过任何 python 下的 gui 编程,所以有些内容难免显得比较初级)。
1. 树型结构的完美表达方式。
首先点击界面左边的树根,右侧 panel 里面可以查看源码,这个就是该 demo 程序的主程序。首先我看到的是定义了一个:
_treeList = [...(...里面很多层嵌套内容就不写了...)...]
格式的东西,而其中的文字表明正是 demo 程序左侧的树状目录。在这里我们可以看到 python 的威力!利用 [] 和 () 这两种记号,结合使用列表和元组的数据结构就方便的定义了一个树型结构。这种写法其实感觉上和 javascript 里的数组以及对象的简略定义方法类似。
至于这个树是如何展现的,我打算在后面再回过头来研究。
2. 自定义 Logger 的机制
往下看我们就能看到一个
注释里也说明了,这里展示了如何实现一个自定义的 logger.
我们看到,这个自定义 logger 的构造器中除了 self 是必须的之外,引入了两个参数。textCtrl 是你要把 logger 写入到的那个文本控件, logTime 则是日志时间,这个有默认参数,可以不指定。
然后我们重写 DoLogString 方法,把日志文本写入到 textCtrl 这个文本框里去就 OK 了。整个代码也是非常的简单!
下面的代码有点长,暂时看不太懂,先不管它。。
然后我开始点击到树状列表中的 /Frames and Dialogs/Dialog 节点,来学学基本的对话框是如何用的。
试了几下 demo 后看源代码。我们看到这个文件里大概可以分为几个部分:
大致看一遍就能理解, TestDialog 是继承自 wx.Dialog 的一个自定义对话框类。
该类的实例,将会在我们点击 Demo 那个面板上的 "Create and Show a custom Dialog" 面板后被创建,并显示出来。
TestPanel 是继承自 wx.Panel 的一个类,可以推测这里是创建了一个自定义的面板类。为什么要创建面板?因为这个东东是要能够别嵌入到主窗体里的 demo 选项卡里去的。这段代码后面我们就会看到。
TestDialog 的代码没什么意思,大致上就是和 C# winform 里面 designer 生成的代码很类似:创建控件,添加控件到容器里面,等等。不过不同的是,wxPython 里面我们可以看到,控件都是加到一个叫做 sizer 的东东里面去的,估计是让 sizer 来专门控制其尺寸方位调节之类的。(这个是我猜测的)。
然后值得注意的是最后这段代码:
最终再把 sizer 加到 Dialog 容器中,并让它进行一定的调整(其具体内容先不深究了)。
TestPanel 上面虽然只摆了一个 button,但是我觉得从中可以学到不少。代码如下:
首先我注意到其构造器里面,有一个 log 参数,这个联想到前面分析的就可以知道,是要从这里实现 logger 的依赖注入。
另外看到的是如何处理 button 的事件。(顺便学会事件处理了,嘿嘿)
第三点,模态对话框返回值如何判断。(用 wx.ID_OK 这个常数来判断)
好了,再来看一下 runTest 函数。
我们看到这里创建了 TestPanel 的实例,并且返回了。返回给谁了?
很明显可以猜到,一定是给主窗体这个调用者了。
然后我回到树根的代码里看看。找到这么一段:
这里看到其代码的意思是调用某个模块(module)的 runTest 方法,如果失败了则替换显示为一个错误信息的面板之类的,先不管它。
而且我们现在也可以猜到, runTest 方法应该是每个 demo 节点对应的模块里都会实现的一个方法,类似于接口规定的一样。(不过我这里还没找到相关接口的机制)
好了,我也累了,先学到这里。。。下次继续:)
1. 树型结构的完美表达方式。
首先点击界面左边的树根,右侧 panel 里面可以查看源码,这个就是该 demo 程序的主程序。首先我看到的是定义了一个:
_treeList = [...(...里面很多层嵌套内容就不写了...)...]
格式的东西,而其中的文字表明正是 demo 程序左侧的树状目录。在这里我们可以看到 python 的威力!利用 [] 和 () 这两种记号,结合使用列表和元组的数据结构就方便的定义了一个树型结构。这种写法其实感觉上和 javascript 里的数组以及对象的简略定义方法类似。
至于这个树是如何展现的,我打算在后面再回过头来研究。
2. 自定义 Logger 的机制
往下看我们就能看到一个
class MyLog(wx.PyLog):
def __init__(self, textCtrl, logTime=0):
wx.PyLog.__init__(self)
self.tc = textCtrl
self.logTime = logTime
def DoLogString(self, message, timeStamp):
#print message, timeStamp
#if self.logTime:
# message = time.strftime("%X", time.localtime(timeStamp)) + \
# ": " + message
if self.tc:
self.tc.AppendText(message + '\n')
def __init__(self, textCtrl, logTime=0):
wx.PyLog.__init__(self)
self.tc = textCtrl
self.logTime = logTime
def DoLogString(self, message, timeStamp):
#print message, timeStamp
#if self.logTime:
# message = time.strftime("%X", time.localtime(timeStamp)) + \
# ": " + message
if self.tc:
self.tc.AppendText(message + '\n')
注释里也说明了,这里展示了如何实现一个自定义的 logger.
我们看到,这个自定义 logger 的构造器中除了 self 是必须的之外,引入了两个参数。textCtrl 是你要把 logger 写入到的那个文本控件, logTime 则是日志时间,这个有默认参数,可以不指定。
然后我们重写 DoLogString 方法,把日志文本写入到 textCtrl 这个文本框里去就 OK 了。整个代码也是非常的简单!
下面的代码有点长,暂时看不太懂,先不管它。。
然后我开始点击到树状列表中的 /Frames and Dialogs/Dialog 节点,来学学基本的对话框是如何用的。
试了几下 demo 后看源代码。我们看到这个文件里大概可以分为几个部分:
class TestDialog(wx.Dialog):
class TestPanel(wx.Panel):
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
class TestPanel(wx.Panel):
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
大致看一遍就能理解, TestDialog 是继承自 wx.Dialog 的一个自定义对话框类。
该类的实例,将会在我们点击 Demo 那个面板上的 "Create and Show a custom Dialog" 面板后被创建,并显示出来。
TestPanel 是继承自 wx.Panel 的一个类,可以推测这里是创建了一个自定义的面板类。为什么要创建面板?因为这个东东是要能够别嵌入到主窗体里的 demo 选项卡里去的。这段代码后面我们就会看到。
TestDialog 的代码没什么意思,大致上就是和 C# winform 里面 designer 生成的代码很类似:创建控件,添加控件到容器里面,等等。不过不同的是,wxPython 里面我们可以看到,控件都是加到一个叫做 sizer 的东东里面去的,估计是让 sizer 来专门控制其尺寸方位调节之类的。(这个是我猜测的)。
然后值得注意的是最后这段代码:
self.SetSizer(sizer)
sizer.Fit(self)
sizer.Fit(self)
最终再把 sizer 加到 Dialog 容器中,并让它进行一定的调整(其具体内容先不深究了)。
TestPanel 上面虽然只摆了一个 button,但是我觉得从中可以学到不少。代码如下:
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show a custom Dialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
dlg = TestDialog(self, -1, "This is a Dialog", size=(350, 200),
#style = wxCAPTION | wxSYSTEM_MENU | wxTHICK_FRAME
style = wx.DEFAULT_DIALOG_STYLE
)
dlg.CenterOnScreen()
# this does not return until the dialog is closed.
val = dlg.ShowModal()
if val == wx.ID_OK:
self.log.WriteText("You pressed OK\n")
else:
self.log.WriteText("You pressed Cancel\n")
dlg.Destroy()
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show a custom Dialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
dlg = TestDialog(self, -1, "This is a Dialog", size=(350, 200),
#style = wxCAPTION | wxSYSTEM_MENU | wxTHICK_FRAME
style = wx.DEFAULT_DIALOG_STYLE
)
dlg.CenterOnScreen()
# this does not return until the dialog is closed.
val = dlg.ShowModal()
if val == wx.ID_OK:
self.log.WriteText("You pressed OK\n")
else:
self.log.WriteText("You pressed Cancel\n")
dlg.Destroy()
首先我注意到其构造器里面,有一个 log 参数,这个联想到前面分析的就可以知道,是要从这里实现 logger 的依赖注入。
另外看到的是如何处理 button 的事件。(顺便学会事件处理了,嘿嘿)
第三点,模态对话框返回值如何判断。(用 wx.ID_OK 这个常数来判断)
好了,再来看一下 runTest 函数。
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
win = TestPanel(nb, log)
return win
我们看到这里创建了 TestPanel 的实例,并且返回了。返回给谁了?
很明显可以猜到,一定是给主窗体这个调用者了。
然后我回到树根的代码里看看。找到这么一段:
try:
self.demoPage = module.runTest(self, self.nb, self)
except:
self.demoPage = DemoErrorPanel(self.nb, self.codePage,
DemoError(sys.exc_info()), self)
self.demoPage = module.runTest(self, self.nb, self)
except:
self.demoPage = DemoErrorPanel(self.nb, self.codePage,
DemoError(sys.exc_info()), self)
这里看到其代码的意思是调用某个模块(module)的 runTest 方法,如果失败了则替换显示为一个错误信息的面板之类的,先不管它。
而且我们现在也可以猜到, runTest 方法应该是每个 demo 节点对应的模块里都会实现的一个方法,类似于接口规定的一样。(不过我这里还没找到相关接口的机制)
好了,我也累了,先学到这里。。。下次继续:)