如何在Python / PyObjC中继承NSPanel?

时间:2013-02-26 22:40:41

标签: python pyobjc

我正在将一个Objective-C / Cocoa的小型库移植到Python / PyObjC中。 而且我对实施的方式感到困惑。

原始代码如下所示:

@implementation HUDWindow
- (id)initWithContentRect:(NSRect)contentRect 
                styleMask:(unsigned int)styleMask 
                  backing:(NSBackingStoreType)bufferingType 
                    defer:(BOOL)flag 
{
    if (self = [super initWithContentRect:contentRect 
                                styleMask:NSBorderlessWindowMask 
                                  backing:bufferingType 
                                    defer:flag]) {
        // initialize code here
             :
             :
             :
             :
             :
             :
        return self;
    }
}

在头文件中说HUDWindow类继承了NSPanel。 至于我阅读代码,初始化是这样的进展:

  1. HUDWindow的initContentRect会覆盖NSPanel的initContentRect。
  2. 在HUDWindow的initContentRect内部,调用NSPanel的initContentRect并将结果作为“self”。
  3. 首先,我编写这样的python代码。这是一个逐字翻译:

    class HUDWindow(NSPanel):
        def initWithContentRect_styleMask_backing_defer_(self, rect, style, buf, flag):
            self = NSPanel.initWithContentRect_styleMask_backing_defer_(
                rect, NSBorderlessWindowMask, buf, flag)
            # initialize code here
                 :
                 :
                 :
                 :
                 :
                 :
            return self
    

    它无效,因为self只是NSPanel的一个实例。我无法调用我从原始obj-c代码中移植的任何上瘾函数。

    所以我改变了我的代码:

    class HUDWindow(NSPanel):
        def initWithContentRect_styleMask_backing_defer_(self, rect, style, buf, flag):
            self.window = NSPanel.initWithContentRect_styleMask_backing_defer_(
                rect, NSBorderlessWindowMask, buf, flag)
            # initialize code here
                 :
                 :
                 :
                 :
                 :
                 :
            return self.window
    

    效果好一点。至少,我可以在这个初始化函数中调用其他函数。 但是在初始化函数之外,我无法调用从原始代码移植的其他函数。

    所以我试过这样:

    class HUDWindow(NSPanel):
        def initWithContentRect_styleMask_backing_defer_(self, rect, style, buf, flag):
            self.window = NSPanel.initWithContentRect_styleMask_backing_defer_(
                rect, NSBorderlessWindowMask, buf, flag)
            # initialize code here
                 :
                 :
                 :
                 :
                 :
                 :
             self.window.setTitle_ = self.setTitle_
             return self.window
    

    它不起作用。在制作实例后我无法覆盖或添加函数。

    现在我觉得我做错了。是否有任何常用的方法来继承像NSPanel或NPWindow这样的类?

1 个答案:

答案 0 :(得分:1)

您的第一个解决方案是在正确的道路上。在第二种情况下,您需要使用NSProxy或编写自己的显式委托,这很痛苦(第三种不是这样做的方式 - 您可以做类似的东西通过调配,但不要)。

然而,有一些问题。

首先,这段代码:

self = NSPanel.initWithContentRect_styleMask_backing_defer_(rect, NSBorderlessWindowMask, buf, flag)

...相当于这个ObjC代码:

self = [NSPanel initWithContentRect:rect 
                          styleMask:NSBorderlessWindowMask
                            backing:buf
                              defer:flag]

......当你想要的是:

self = [super initWithContentRect:rect 
                        styleMask:NSBorderlessWindowMask
                          backing:buf
                            defer:flag]

后者的PyObjC等价物是:

self = super().initWithContentRect_styleMask_backing_defer_(rect, NSBorderlessWindowMask, buf, flag)

或者,在2.x:

self = super(HUDWindow, self).initWithContentRect_styleMask_backing_defer_(rect, NSBorderlessWindowMask, buf, flag)

在ObjC中,super不是超类,而是一个特殊的魔术对象,它实际上是“自我作为超类的一个实例”。它几乎就像Python 3的super(),或者不那么神奇的Python 2 super,PyObjC做了额外的工作,意味着你可以忽略“差不多”。

你正在做的是(尝试)初始化NSPanel类对象(或者可能是PyObjC桥的类对象到NSPanel,我不确定哪个),或者甚至可能尝试将rect初始化为好像是NSPanel。无论你做什么,它都不可能做任何事情来初始化你的self实例。 (并将结果分配给self并不像在ObjC中那样在Python中执行相同的操作。它在PyObjC中通常仍然是惯用的样式,但不要被它误导;它唯一的作用就是如果你使用它初始化方法中再次self。无论如何,最好能够掩盖ObjC中的问题,而不是修复它......)因此,从这个方法返回后,你的self仍然是分配的但是在您调用任何内容之前的未初始化NSPanel实例。

本教程很早就在Two Phase Instantiation中解释了这一点。