我的问题
我正在Python(通过wxPython包装器)中使用wxWidgets库。我正在尝试实现一个与WX StaticText类相同的类,但其两面都有用户可配置的填充,该类的行为与WX StaticText类相同。理想情况下,PaddedStaticText将替代StaticText。那种尖叫是“子类”,对吗?不幸的是,我认为如果要继承StaticText,就必须基本上重新实现其所有绘制例程,而我没有WX专业知识。
解决方案一
我想到的解决方案是实现一个具有StaticText属性的类,该类将放置在几个Sizers中以实现填充:
class PaddedStaticText(wx.Window):
def __init__(self, parent, label='', padding=(0, 0, 0, 0), **kwargs):
wx.Window.__init__(self, parent)
self.text = wx.StaticText(self, label=label, **kwargs)
inner_sizer = wx.BoxSizer(wx.VERTICAL)
inner_sizer.Add((0, padding[0]))
inner_sizer.Add(self.text, proportion=1, flag=wx.EXPAND)
inner_sizer.Add((0, padding[2]))
outer_sizer = wx.BoxSizer(wx.HORIZONTAL)
outer_sizer.Add((padding[3], 0))
outer_sizer.Add(inner_sizer, proportion=1, flag=wx.EXPAND)
outer_sizer.Add((padding[1], 0))
self.SetSizer(outer_sizer)
该类继承自wx.Window,因此可以在许多本可以使用StaticText的上下文中使用(例如,将其添加到Sizer中)。不过,由于PaddedStaticText实际上不是StaticText,所以我不能只在其中一个实例上调用SetFont()。我必须制定自己的代理方法:
def SetFont(self, *args, **kwargs):
self.text.SetFont(*args, **kwargs)
当然,我必须为每个希望使用的StaticText方法编写这样的存根。这种方法有效,但一点都不优雅。我认为在Python中必须有更好的方法来执行类似的操作。
解决方案二
基于this SO answer,我编写了这个简单的Proxy类:
class Proxy(object):
def __init__(self, underlying_object):
self._underlying_object = underlying_object
def __getattribute__(self, name):
obj = object.__getattribute__(self, '_underlying_object')
return object.__getattribute__(obj, name)
然后我可以将PaddedStaticText表示为Proxy的子类,并将
underlying_object
设置为StaticText实例。不幸的是,当我尝试将新的PaddedStaticText实例添加到Sizer时,WX陷入僵局。因为它是C ++库的包装器,所以我猜WX并不真正尊重Python的鸭子类型:尽管无论何时调用StaticText方法,PappedStaticText都可以正确响应,但所有wxPython关心的是它继承自Proxy而不是从wx.Window。在那儿,我简要地介绍了如何使PaddedStaticText从Proxy和wx.Window继承,但这没有用(无论如何,这是一个继承菱形的示例)。如何以一种可以正常工作的方式实现我的PaddedStaticText类?对于我的解决方案构想或解决问题的完全不同的建议,我将不胜感激。
最佳答案
我会做的是:
class PaddedStaticText(wx.Window):
def __init__(...):
self.text = ...
...
def __getattr__(self, name):
'''delegate missing attributes to text'''
return getattr(self.text, name)
它通过故障转移将基本继承方法扩展到委派(仅在没有其他作用的情况下调用
__getattr__
)。可以使事情接近wxwindows的期望,并减少了魔力,但仍然可以访问
SetFont
之类的东西。或者,如果要使用
.text
(而不是.__text
),则可以使用:foo = PaddedStaticText(...)
foo.text.SetFont(...)
但您将无法替换现有的StaticText实例。
[编辑]已经晚了,所以明天我可能会改善,但是如果您需要使用
__getattribute__
,那么我建议您明确说明想要的方法。它的类型更多,但是以我的经验,使用python进行全自动代理通常会以令人讨厌的方式使您惊讶。所以像这样:def __getattribute__(self, name):
if name in ('SetFont', ...):
return getattr(self.text, name)
else:
return super(...).__getattribute__(self, name)
或(可能更快,但每个实例消耗更多的内存):
def __init__(...):
self.text = ...
for name in ('SetFont', ...):
setattr(self, name, getattr(self.text, name))
关于python - 实现代理对象,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19278411/