我在Python中使用wxWidgets库(通过wxPython包装器)。我正在尝试实现一个类PaddedStaticText,它的行为与WX StaticText类相同,但每侧都有一个用户可配置的填充。理想情况下,PaddedStaticText将成为StaticText的替代品。那种尖叫“子类”,对吧?不幸的是,我认为如果我要将StaticText子类化,我必须基本上重新实现它的所有绘图程序,而且我没有WX的专业知识来做到这一点。
我想出的解决方案是实现一个具有StaticText属性的类,该类可以放在几个Sizer中以实现填充:
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,所以它可以在许多相同的上下文中使用,我可以使用静态文本 - 例如将它添加到Sizer中。但是,由于PaddedStaticText实际上不是静态文本,因此我无法在其中一个实例上调用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的鸭子类型:即使PaddedStaticText可以在每次调用StaticText方法时都能正确响应,所有wxPython都关心的是它继承自Proxy而不是来自wx.Window。
从那里我简单地介绍了使用PaddedStaticText继承Proxy和wx.Window,但是这不起作用(无论如何它都是继承钻石的一个例子)。如何以Just Works的方式实现我的PaddedStaticText类?我很欣赏有关我的解决方案想法的建议,或者解决问题的完全不同的建议。
答案 0 :(得分:1)
我要做的是:
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))