我的问题

我正在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/

10-10 21:36