前一段时间用Python开发了一个教育类的PC桌面应用,边学边开发,现在陆续的将开发过程中学到的一些东西分享记录下来,项目使用了wxPython框架。
wxPython的官网: https://www.wxpython.org/
wxPython各种控件用法官方手册 : http://xoomer.virgilio.it/infinity77/wxPython/widgets.html
wx库不是Python自带的库文件,需要首先在官网下载并安装,windows可以在官网下载exe安装文件,Ubuntu和Mac可以使用pip install进行安装,也可以使用源码安装方式安装。
安装成功之后,使用import wx 来测试安装成功与否,在进行wxPython编程中,也需要使用import wx 首先导入wxPython的库引用。
下面是第一个用wxPython构建的界面窗口:
【效果】
【代码实现】
#coding=utf-8
"""
程序的主入口
"""
import wx
class FirseFrame(wx.Frame):
def __init__(self, parent=None, id=-1, title='', pos=wx.DefaultPosition, size=wx.DefaultSize, style= wx.DEFAULT_FRAME_STYLE):
"""
wx.Frame() 构造函数参数说明 :
wx.Frame.__init__(self, Window parent, int id=-1, String title=EmptyString,
Point pos=DefaultPosition, Size size=DefaultSize,
long style=DEFAULT_FRAME_STYLE, String name=FrameNameStr) -> Frame
"""
wx.Frame.__init__(self, parent, id, title, pos, size, style)
self.InitUI()
pass
def InitUI(self):
self.SetBackgroundColour('#ffffff')
"""
wx.StaticText()构造函数参数说明 :
__init__(self, Window parent, int id=-1, String label=EmptyString,
Point pos=DefaultPosition, Size size=DefaultSize,
long style=0, String name=StaticTextNameStr) -> StaticText
"""
content = wx.StaticText(self, -1, u'这是第一个窗口', pos=(20, 20))
content.SetForegroundColour('#000000')
pass
class MainApp(wx.App):
def OnInit(self):
self.frame = FirseFrame(id=-1, title=u'第一个窗口', pos=(10, 10), size=(230, 230))
self.frame.Show()
return True
def main():
app = MainApp()
app.MainLoop()
if __name__ == "__main__":
main()
【说明】
if __name__ == "__main__":
main()
上面的代码是Python程序的主入口,在一个项目中有且只有一个,一个Python程序开始运行的时候,会找到这个入口,并从此开始运行。
class MainApp(wx.App):
def OnInit(self):
self.frame = FirseFrame(id=-1, title=u'第一个窗口', pos=(10, 10), size=(230, 230))
self.frame.Show()
return True
wx.App是wxPython中一个App对象,在一个wxPython中有且只有一个,MainApp类继承了wx.App类MainApp类被实例化之后,调用wx.App对象的MainLoop()方法便开始了一个wxPython进程。
关于编码错误的问题,上面程序中,汉字字符串前面加了一个u,表示该段字符串的编码/解码方式是unicode的方式,如果项目运行Unicode编码错误,可以在程序开始的地方加上下面一段代码:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
(1)wx.Frame
Frame可以看做是wxPython提供的控件绘制的窗口,我们可以将控件绘制在Frame上,便于管理。
在wxPython的源码中可以看到wxFrame的构造函数为:
"""
wx.Frame() 构造函数参数说明 :
__init__(self, Window parent, int id=-1, String title=EmptyString,
Point pos=DefaultPosition, Size size=DefaultSize,
long style=DEFAULT_FRAME_STYLE, String name=FrameNameStr) -> Frame
"""
【说明】
pos是Frame在屏幕上显示的位置, size为Frame窗口初始化绘制的大小
style是Frame显示的属性,常用的style样式说明:
style=wx.CAPTION : 在Frame上增加一个标题栏 :
style=wx.CLOSE_BOX : 在Frame上显示关闭框:
style=wx.MAXIMIZE_BOX : 在Frame上显示最大化框
style=wx.MINIMIZE_BOX : 在Frame上显示最小化框
style=wx.RESIZE_BORDER : 给Frame添加一个用户可以自己改变Frame大小的边框
style=wx.DEFAULT_FRAME_STYLE : 默认的Frame样式:
可以看到默认样式包含了所有的常见样式(包括,标题,icon,最小化,最大化,可拖拽大小边框,关闭),那么要是我们想在默认样式的基础上出去某个样式,可以:
style = wx.DEFAULT_FRAME_STYLE^(wx.RESIZE_BORDER|wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX|wx.CLOSE_BOX)
上面的样式在默认样式的基础上,去除了 拖拽改变Frame大小属性,去除了最大化,去除了最小化,去除了关闭。
效果如下:
当然要是只去除一个样式,e.g. 去除最大化:
style = wx.DEFAULT_FRAME_STYLE^wx.MAXIMIZE_BOX
self.frame = FirseFrame(id=-1, title=u'第一个窗口', pos=(10, 10), size=(230, 230), style=style)
效果:
pos是一个Frame显示在屏幕上的位置坐标,size是Frame初始化的大小,那么要是我们希望我们的Frame在初始化之后显示在屏幕的中间,可以首先获得屏幕的大小,然后动态规定pos的值:
class MainApp(wx.App):
def OnInit(self):
style = wx.DEFAULT_FRAME_STYLE^wx.MAXIMIZE_BOX
# wx.DisplaySize()获得一个元组, e.g. (1440, 780) 表示当前设备屏幕的长宽
windowSize = wx.DisplaySize()
newPos = (windowSize[0] / 2, windowSize[1] / 2)
self.frame = FirseFrame(id=-1, title=u'第一个窗口', pos=newPos, size=(230, 230), style=style)
self.frame.Show()
return True
上面的代码通过wx.DisplaySize()获得了设备屏幕的大小,动态制定了Frame显示的坐标,使得Frame左上角位于屏幕的中心位置,这是一种方法,其实wxPython提供了一种自带的接口:
只修改wxFrame类:
class FirseFrame(wx.Frame):
def __init__(self, parent=None, id=-1, title='', pos=wx.DefaultSize, size=wx.DefaultSize, style= wx.DEFAULT_FRAME_STYLE):
wx.Frame.__init__(self, parent, id, title, pos, size, style)
self.InitUI()
pass
def InitUI(self):
self.SetBackgroundColour('#ffffff')
"""
wx.StaticText()构造函数参数说明 :
__init__(self, Window parent, int id=-1, String label=EmptyString,
Point pos=DefaultPosition, Size size=DefaultSize,
long style=0, String name=StaticTextNameStr) -> StaticText
"""
content = wx.StaticText(self, -1, u'这是第一个窗口', pos=(20, 20))
content.SetForegroundColour('#000000')
self.Center()
pass
在FirseFrame(wx.Frame)的InitUI()函数的最后调用了 self.Center() 函数,告诉系统将该Frame显示在屏幕的中间,系统会将Frame的中心放在设备屏幕的中心位置,
同样的,要是想让Frame在初始化之后,最大化,一种方法就是将Frame的size设置为wx.DisplaySize(),和self.Center()相同,可以通过调用self.Maximize(True)来实现:
self.Maximize(True)
(2)wx.Panel
Panel可以看做是一个碎片化的Frame,当有一部分的控件需要同时处理,比如同时隐藏,同时显示的时候,可以将这些控件的parent Window写成同一个Panel,这样方便于整体的操作。
"""
__init__(self, Window parent, int id=-1, Point pos=DefaultPosition,
Size size=DefaultSize, long style=wxTAB_TRAVERSAL|wxNO_BORDER,
String name=PanelNameStr) -> Panel
"""
(3)一种wxPython项目架构
当我们有多个Frame界面需要来回的跳转,而Frame的显示是在MainApp(wx.App)类中实现的,那么就需要在MainApp(wx.App)这个类中实现一个Frame跳转的接口,通过这个接口来完成多Frame的跳转。
【说明】
FrameManager中,维护了一个字典,key=type,value=Frame,首次显示Frame的时候,创建该Frame,并将其缓存在字典中,再次显示该Frame的时候,直接从字典中获取得到gaiFrame,并通过Frame中自定义的方法UpdateDataAndUI(self, newData)接口,更新Frame的数据和显示状态。
源码和更多说明请查看:
wxPython实现Frame之间的跳转/更新的一种方法