window 的 IBAction 在 OS X 的 cocoa 中变得可见

IBAction for window becoming visible in cocoa for OS X

我有一个 window,里面有一个按钮。当我单击该按钮时,它会打开另一个 window(两个 windows 都在同一个 xib 文件中)。我通过将第一个 window 中的按钮绑定到第二个 window 中的 orderFront 来完成此操作。这按预期工作。 现在我需要一个回调函数 (IBAction),以便在第二个 window 可见时触发(根据第一个 window 中的设置对第二个 window 进行一些更改)。我在第二个 window 的控制器 class 中有占位符 IBAction,但我似乎找不到 window "becoming visible" 的触发器与其绑定。 奇怪的是,在任何地方(谷歌搜索)都没有关于 NSWindow 可见的回调函数。这些东西是通过在 .NET 和 Visual Studio 中单击来完成的(我正在从 .NET 移植代码)。我这样做是完全错误还是什么?

我会说是的,从标准 Cocoa 设计的角度来看,您尝试以错误的方式进行设计,原因有二。很抱歉回答太长,这里有很多概念层面的问题。

首先,当您想知道特定对象发生了特定事情时,target/action 机制不是 Cocoa 中的标准方法,除非 [=45] =] 是直接的用户操作,例如点击。连接按钮操作以显示 window 的方式很好;这是用户启动的(按下按钮),因此一个动作是合适的。但是要知道第二个 window 已经改变了状态(变得可见),使用 (1) 委托或 (2) 通知会更典型。这两个都有用;在 Apple 的文档中阅读它们(我相信 Google 会在这里帮助你)。例如,您可以将一个对象声明为您的第二个 window 的委托,然后它会在 window 成为键或主、更改屏幕、关闭等时接收消息。 – 您感兴趣的任何状态变化。

然而,这里还有第二个转折点。如果您查看 NSWindowDelegate 协议的文档,您会看到 windowShouldClose:windowWillClose: 之类的委托方法,但没有 windowDidOpen: 或 [=14] 之类的相应方法=].有一些委托方法可能适合您,具体取决于您在做什么,例如 windowDidBecomeKey:windowDidBecomeMain:,甚至 windowDidExpose:,但没有 windowDidOpen:或类似的。我认为,那是 Apple 向您发送的信息:您的代码真的不应该关心。所以你不应该使用 windowDidBecomeKey: 等,除非它们真正代表了你感兴趣的事件 - 听起来他们并不感兴趣。相反,您应该更深入地思考 Apple 通过不包含 windowDidOpen: 消息告诉您的内容。为什么他们会遗漏这么明显的代表信息??

这是我对此的回答。您的第二个 window 已经加载,因为它与第一个 window 在同一个笔尖中。无论它是否可见,在任何给定的时刻,都是一个明智的细节,避免做出假设是明智的,这就是我推测的 Apple 代表设计的原因。 window 可能会被 window 恢复自动显示;它可能会由于你的应用程序代码之外的某些东西而来来去去,比如 Exposé 或 Spaces 之类的技术,或者 Apple 下一步决定做什么;并且您可以使 window 在您的代码中的各个不同位置可见。在 window 变得可见之前,您不必担心这些细节,在最后一分钟设置 window 代码。如果 window 在 window 列表中,那么在大多数情况下,它当前是否可见不应该是您的代码所关心的; window 应该保持良好的状态,这样就可以很高兴地显示它,而无需在它变得可见之前进行最后一分钟的修复。根据 Apple 的设计,您的代码应该担心 window 首次从笔尖创建的那一刻,将其设置为正确的状态 - awakeFromNib 就是为了那个 - 以及当window 关闭(因为通常情况下,尽管并非总是如此,window 在关闭时不再存在,因此需要进行清理)——windowWillClose: 就是为了这个。在此期间,您的 window 应该保持良好状态。这样做的工作应该非常少,因为除非 window 实际上在屏幕上,否则所有绘图都将被抑制。

所以当你写下你想要的 "to make some changes to the second window based on settings in first window" 时,正确的设计可能是在第二个 window 中立即进行这些更改以响应第一个 window 中的任何更改] 发生。检测第一个 window 中的变化以及连接到任何用户界面变化的操作,并响应这些操作,更改第二个 window。然后,当显示第二个 window 时,您的代码甚至不需要知道。这是一个更简洁的设计;这意味着,例如,如果第一个 window 在第二个 window 显示后进一步更改,第二个 window 将自动对这些更改做出反应,而 "fix the second window up once just before it displays"设计不会实现这一点。

如果这似乎不适合您在应用程序中尝试执行的操作,那么您需要更具体地说明您要实现的目标。我会争辩说,根据 Cocoa、 的逻辑,如果 和 windows 都在同一个笔尖中,那么它通常是正确的设计。如果它对您来说似乎是错误的设计,那么这几乎可以肯定表明第二个 window 实际上不应该与第一个 window 在同一个笔尖中,并且一个新的笔尖应该为第二个 window 加载,导致第二个 window 在 nib 完成加载后由为第二个 window 加载 nib 的控制器配置。 (或者由第二个 window 的单独控制器,或者可能由第二个 window 本身在其 awakeFromNib 中;这里有很多选项,具体取决于您的架构。)

我会敦促你不要通过子类化NSWindow来解决这个问题,因为另一个答案已经提出(该答案现已删除,建议子类化并覆盖这样的方法作为 makeKeyAndOrderFront: 以便或多或少地破解 windowDidOpen: 类功能)。 Apple 出于某种原因遗漏了 windowDidOpen: 委托消息;如果这只是一个心不在焉的疏忽,它会在很多年前添加。 Cocoa 编程的关键是学会不跟苹果打架。 Cocoa 是一个设计得非常好的框架,总的来说(尽管有 类 是例外 :->),如果你学会顺应它而不是与之抗争,你的生活会容易得多最后。