2

我的问题

我在 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,因此它可以在许多我可以使用 StaticText 的相同上下文中使用——例如,将它添加到 Sizer。但是,由于 PaddedStaticText 实际上不是 StaticText,我不能只在其中一个实例上调用 SetFont()。我必须制作自己的代理方法:

    def SetFont(self, *args, **kwargs):
        self.text.SetFont(*args, **kwargs)

当然,我必须为我希望可用的每个 StaticText 方法编写这样的存根。这种方法有效,但感觉一点也不优雅。我认为在 Python 中必须有更好的方法来做这样的事情。

解决方案二

基于this SO answer我写了这个简单的代理类:

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 继承,但这没有用(无论如何它是继承菱形的一个例子)。我怎样才能以恰到好处的方式实现我的 PaddedStaticText 类?我很感激关于我的任何一个解决方案想法的建议,或者解决问题的完全不同的东西。

4

1 回答 1

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))
于 2013-10-09T20:29:44.497 回答