1、继承的局限
wxPython是一个wxWidgets C++框架的封装。这种关系意味着在大多数wxPython对象里都是C++对象。由于这个,wxPython类的方法不能像普通Python对象一样重写。
通过如何创建一个自动添加自己子窗口到其布局器Sizer的类的例子,展示什么情况下类的子类可以重写方法。
2、示例说明
我们创建两个相似的类,用来自动添加自己子窗口到其布局器Sizer里。MyPanel继承于标准的Panel类,MyVirtualPanel则继承于PyPanel类。
#-*-coding: UTF-8 -*-
#------------------------------------------------------
#Purpose: nothing....
#Author: 阿Bin先生
#Created: 2017年5月21日
#------------------------------------------------------
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
super(MyPanel, self).__init__(parent)
sizer = wx.BoxSizer()
self.SetSizer(sizer)
def AddChild(self, child):
sizer = self.GetSizer()
sizer.Add(child, 0, wx.ALIGN_LEFT|wx.ALL, 8)
return super(MyPanel, self).AddChild(child)
class MyVirtualPanel(wx.PyPanel):
"""Class that automatically adds children
controls to sizer layout.
"""
def __init__(self, parent):
super(MyVirtualPanel, self).__init__(parent)
sizer = wx.BoxSizer()
self.SetSizer(sizer)
def AddChild(self, child):
sizer = self.GetSizer()
sizer.Add(child, 0, wx.ALIGN_LEFT|wx.ALL, 8)
return super(MyVirtualPanel, self).AddChild(child)
class MyFrame(wx.Frame):
def __init__(self, parent, *args, **kwargs):
super(MyFrame, self).__init__(parent, *args, **kwargs)
# Attributes
self.mypanel = MyPanel(self)
self.mypanel.SetBackgroundColour(wx.BLUE)
self.virtpanel = MyVirtualPanel(self)
self.virtpanel.SetBackgroundColour(wx.WHITE)
# Setup
self.__DoLayout()
def __DoLayout(self):
"""Layout the window"""
# Layout the controls using a sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.mypanel, 1, wx.EXPAND)
sizer.Add(self.virtpanel, 1, wx.EXPAND)
self.SetSizer(sizer)
# Create 3 children for the top panel
for x in range(3):
wx.Button(self.mypanel, label="MyPanel %d" % x)
# Create 3 children for the bottom panel
for x in range(3):
wx.Button(self.virtpanel, label="VirtPanel %d" % x)
self.SetInitialSize(size=(300, 200))
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, title="Virtualized Methods")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
if __name__ == "__main__":
app = MyApp(False)
app.MainLoop()
运行结果:
3、示例分析
示例中创建的Panel类都重写了AddChild方法,该方法希望每次在窗口有子窗口创建时被调用。AddChild方法是在类的C++部分里被调用,因此为了能够重写该方法 ,需要类能够提供重写C++类虚方法的访问。运行结果表明,Py开个头的类暴露了很多C++类虚方法,这些方法在Python子类里被重写后,绑定到对象C++层中,被框架调用时替代基类的实现。而MyPanel的AddChild 方法从来没有被调用。
如何判断类的方法是不是以虚函数形式暴露?
有个小技巧可以帮助判断。
import wx
for method in dir(wx.PyPanel):
if method.startswith('base_'):
print method
dir()里插入任何类,上面代码打印出所有虚方法,方法名以base_开头,这些方法不能在代码中直接使用。
运行结果:
4、总结
根据实际需求,决定是否继承以Py开个头的类。如果重写的方法,是在类的C++部分调用,则要考虑该方法是否以虚方法形式暴露出来。