创建自定义组件Toolkit通常只提供最常用的widget,比如按钮、文本widget、滚动条、滑块等,没有一个toolkit可以提供所有可能的widget。wxPython有很多组件,而且更多的组件是由客户端程序员创建的,我们可以通过两种方式创建自定义组件:一种是修改或增强现有的widgets,另一种是创建自定义组件。创建自定义组件有两种方法:一种是修改或增强现有组件,另一种是从头开始创建自定义组件。一个超链接组件第一个例子将创建一个超链接。超链接小部件将基于现有的wx.lib.stattext.GenStaticText小部件。#hyperlink.pyimportwxfromwx.lib.stattext导入GenStaticTextimportwebbrowserclassLink(GenStaticText):def__init__(self,*args,**kw):super(Link,self).__init__(*args,**kw)self.font1=wx.Font(11,wx.SWISS,wx.NORMAL,wx.BOLD,True,'Verdana')self.font2=wx.Font(11,wx.SWISS,wx.NORMAL,wx.BOLD,False,'Verdana')self.SetFont(self.font2)self.SetForegroundColour('#0000ff')self.Bind(wx.EVT_MOUSE_EVENTS,self.OnMouseEvent)self.Bind(wx.EVT_MOTION,self.OnMouseEvent)defSetUrl(self,url):self.url=urldefOnMouseEvent(self,e):ife.Moving():self.SetCursor(wx.Cursor(wx.CURSOR_HAND))self.SetFont(self.font1)elife.LeftUp():webbrowser.open_new(self.url)else:self.SetCursor(wx.NullCursor)self.SetFont(self.font2)e.Skip()class示例(wx.Frame):def__init__(self,*args,**kw):小号uper(例子,self).__init__(*args,**kw)self.InitUI()defInitUI(self):panel=wx.Panel(self)vbox=wx.BoxSizer(wx.VERTICAL)hbox=wx.BoxSizer(wx.HORIZONTAL)st=GenStaticText(panel,label='转到网站:')st.SetFont(wx.Font(11,wx.SWISS,wx.NORMAL,wx.BOLD,False,'Verdana'))hbox.Add(st,flag=wx.LEFT,border=20)link_wid=Link(panel,label='ZetCode')link_wid.SetUrl('http://www.zetcode.com')hbox.Add(link_wid,flag=wx.LEFT,border=20)vbox.Add(hbox,flag=wx.TOP,border=30)panel.SetSizer(vbox)self.SetTitle('超链接')self.Centre()defmain():app=wx.App()ex=Example(None)ex.Show()app.MainLoop()if__name__=='__main__':main()这个超级链接组是基于一个现有的组在这个例子中,我们不绘制任何东西,我们只是使用一个现有的组件,我们对其进行了一些修改。fromwx.lib.stattextimportGenStaticTextimportwebbrowser这里我们导入基本部件,我们从中获取超链接部件和网络浏览器模块。webbrowser模块是一个标准的Python模块。我们将使用它在我们的默认浏览器中打开链接。self.SetFont(self.font2)self.SetForegroundColour('#0000ff')创建超链接组件背后的想法很简单,我们继承自一个基本的wx.lib.stattext.GenStaticText小部件类。所以我们有一个文本小部件。然后我们对其进行一些修改。我们更改文本的字体和颜色。ife.Moving():self.SetCursor(wx.Cursor(wx.CURSOR_HAND))self.SetFont(self.font1)如果我们将鼠标指针悬停在链接上,它会将字体更改为下划线并同时设置The鼠标指针变为手形光标。elife.LeftUp():webbrowser.open_new(self.url)如果我们左键单击链接,它将在默认浏览器中打开链接。刻录小部件这是一个我们从头开始创建小部件的示例,我们在窗口底部放置一个wx.Panel,然后手动绘制整个小部件。如果您曾经刻录过CD或DVD,那么您一定见过这个小部件。#burning.pyimportwxclassBurning(wx.Panel):def__init__(self,parent):wx.Panel.__init__(self,parent,size=(-1,30),style=wx.SUNKEN_BORDER)self.parent=parent复制代码self.font=wx.Font(9,wx.FONTFAMILY_DEFAULT,wx.FONTSFAMILY_NORMAL,wx.FONTWEIGHT_NORMAL,False,'Courier10Pitch')self.Bind(wx.EVT_PAINT,self.OnPaint)self.Bind(wx.EVT_SIZE,self.OnSize)defOnPaint(self,e):num=range(75,700,75)dc=wx.PaintDC(self)dc.SetFont(self.font)w,h=self.GetSize()self.cw=self.parent.GetParent().cwstep=int(round(w/10.0))j=0直到=(w/750.0)*self.cwfull=(w/750.0)*700ifself.cw>=700:dc.SetPen(wx.Pen('#FFFFB8'))dc.SetBrush(wx.Brush('#FFFFB8'))dc.DrawRectangle(0,0,full,30)dc.SetPen(wx.Pen('#ffafaf'))dc.SetBrush(wx.Brush('#ffafaf'))dc.DrawRectangle(full,0,till-full,30)else:dc.SetPen(wx.Pen('#FFFFB8'))dc.SetBrush(wx.Brush('#FFFFB8'))dc.DrawRectangle(0,0,直到,30)dc.SetPen(wx.Pen('#5C5142'))foriinrange(step,10*step,step):dc.DrawLine(i,0,i,6)宽度,高度=dc.GetTextExtent(str(num[j]))dc.DrawText(str(num[j]),i-宽度/2,8)j=j+1defOnSize(self,e):self.Refresh()类示例(wx.Frame):def__init__(self,*args,**kwargs):super(Example,self).__init__(*args,**kwargs)self.InitUI()defInitUI(self):self.cw=75panel=wx.Panel(self)CenterPanel=wx.Panel(panel)self.sld=wx.Slider(CenterPanel,value=75,maxValue=750,size=(200,-1),style=wx.SL_LABELS)vbox=wx.BoxSizer(wx.VERTICAL)hbox=wx.BoxSizer(wx.HORIZONTAL)hbox2=wx.BoxSizer(wx.HORIZONTAL)hbox3=wx.BoxSizer(wx.HORIZONTAL)self.wid=Burning(panel)hbox.Add(self.wid,1,wx.EXPAND)hbox2.Add(CenterPanel,1,wx.EXPAND)hbox3.Add(self.sld,0,wx.LEFT|wx.TOP,35)CenterPanel.SetSizer(hbox3)vbox.Add(hbox2,1,wx.EXPAND)vbox.Add(hbox,0,wx.EXPAND)self.Bind(wx.EVT_SCROLL,self.OnScroll)panel.SetSizer(vbox)self.sld.SetFocus()self.SetTitle("Burningwidget")self.Centre()defOnScroll(self,e):self.cw=self.sld.GetValue()self.wid.Refresh()defmain():app=wx.App()ex=Example(None)ex.Show()app.MainLoop()if__name__=='__main__':main()这个小部件使用图形模式显示介质的总容量和我们可用的空间。该小部件由滑块控制。我们的自定义小部件的最小值为0,最大值为750。如果我们达到700,我们将开始以红色绘制。这通常表示过度刻录。w,h=self.GetSize()self.cw=self.parent.GetParent().cw...till=(w/750.0)*self.cwfull=(w/750.0)*700我们动态绘制小部件。窗口越大,燃烧的部分越大。反之亦然。这就是为什么我们必须计算wx.Panel的大小并在其上绘制自定义小部件的原因。till参数确定要绘制的总大小。该值来自滑块小部件。它是整个区域的一部分。完整参数决定了我们开始绘制红色的点。注意浮点运算的使用。这是为了达到更高的精度。实际绘图包括三个步骤。我们绘制黄色或红色和黄色矩形。然后我们绘制垂直线将零件分成几个部分。最后,我们绘制代表介质容量的数字。defOnSize(self,e):self.Refresh()每次调整窗口大小时我们都会刷新小部件。这将导致小部件重新绘制自身。defOnScroll(self,e):self.cw=self.sld.GetValue()self.wid.Refresh()如果我们滚动滑块,我们将获得实际值并将其保存在self.cw参数中。绘制燃烧小部件时使用此值。然后我们将重新绘制小部件。CPU小部件有一些系统应用程序可以测量系统资源,如温度、内存或CPU消耗。为了使应用程序更具吸引力,我们创建了专门的组件。以下是系统应用中常用的组件。#cpu.pyimportwxclassCPU(wx.Panel):def__init__(self,parent):wx.Panel.__init__(self,parent,size=(80,110))self.parent=parentself.SetBackgroundColour('#000000')self.Bind(wx.EVT_PAINT,self.OnPaint)defOnPaint(self,e):dc=wx.PaintDC(self)dc.SetDeviceOrigin(0,100)dc.SetAxisOrientation(True,True)pos=self.parent.GetParent().GetParent().selrect=pos/5foriinrange(1,21):如果i>rect:dc.SetBrush(wx.Brush('#075100'))dc.DrawRectangle(10,i*4,30,5)dc.DrawRectangle(41,i*4,30,5)其他:dc.SetBrush(wx.Brush('#36ff27'))dc.DrawRectangle(10,i*4,30,5)dc.DrawRectangle(41,i*4,30,5)class示例(wx.Frame):def__init__(self,*args,**kwargs):super(Example,self).__init__(*args,**kwargs)self.InitUI()defInitUI(self):self.sel=0panel=wx.Panel(self)centerPanel=wx.Panel(panel)self.cpu=CPU(centerPanel)hbox=wx.BoxSizer(wx.HORIZONTAL)self.slider=wx.Slider(面板,值=self.sel,maxValue=100,大小=(-1,100),style=wx.VERTICAL|wx.SL_INVERSE)self.slider.SetFocus()hbox.Add(centerPanel,0,wx.LEFT|wx.TOP,20)hbox.Add(self.slider,0,wx.LEFT|wx.TOP,30)self.Bind(wx.EVT_SCROLL,self.OnScroll)panel.SetSizer(hbox)self.SetTitle("CPU")self.Centre()defOnScroll(self,e):self.sel=e.GetInt()self.cpu.Refresh()defmain():app=wx.App()ex=Example(None)ex.Show()app.MainLoop()if__name__=='__main__':main()我们创建一个黑色面板,然后我们在这个面板上绘制小矩形。矩形的颜色取决于滑块的值。颜色可以是深绿色或亮绿色。dc.SetDeviceOrigin(0,100)dc.SetAxisOrientation(True,True)这里我们将默认的坐标系改为笛卡尔坐标系。这是为了使绘图更直观。pos=self.parent.GetParent().GetParent().selrect=pos/5这里我们得到sizer的值。每列有20个矩形。滑块有100个数字。Rectangle参数将滑块的值转换为一个以亮绿色绘制的矩形。foriinrange(1,21):如果i>rect:dc.SetBrush(wx.Brush('#075100'))dc.DrawRectangle(10,i*4,30,5)dc.DrawRectangle(41,i*4,30,5)其他:dc.SetBrush(wx.Brush('#36ff27'))dc.DrawRectangle(10,i*4,30,5)dc.DrawRectangle(41,i*4,30,5)这里我们绘制了40个矩形,每列20个。如果要绘制的矩形数大于转换后的矩形值,则绘制深绿色,否则绘制浅绿色。