gpt4 book ai didi

python - 如何在Python/PyObjC中继承NSPanel?

转载 作者:太空宇宙 更新时间:2023-11-03 19:04:28 25 4
gpt4 key购买 nike

我正在将 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”。

首先,我编写这样的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 这样的类?

最佳答案

您的第一个解决方案是正确的。在第二种情况下,您需要使用 NSProxy 或编写自己的显式委托(delegate),这是一种痛苦(而第三种方法不是这样做的方法 - 您可以 通过 swizzling 做类似的事情,但不要)。

但是,存在一些问题。

首先,这段代码:

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 不是父类(super class),而是一个特殊的魔法对象,它实际上是“作为父类(super class)实例的自身”。它几乎与 Python 3 的 super() 或不太神奇的 Python 2 super 完全相同,PyObjC 做了额外的工作,这意味着您可以忽略“几乎”。

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

这在本教程的早期部分 Two Phase Instantiation 中得到了大部分解释。 .

关于python - 如何在Python/PyObjC中继承NSPanel?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15100827/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com