【问题标题】:NSBorderlessWindow not responding to CMD-W/CMD-MNSBorderlessWindow 不响应 CMD-W/CMD-M
【发布时间】:2009-10-07 14:04:45
【问题描述】:

我有一个 NSWindow 的 NSBorderlessWindow 子类,它具有透明且不透明的背景(因此它的外观不是矩形)。当我单击它们时,我添加了我自己的按钮作为关闭和最小化按钮,但由于某种原因,窗口不会像正常的那样响应 CMD-W 或 CMD-M。我将我的 NSWindow 子类设置为返回 YES 到 canBecomeKeyWindow 和 canBecomeMainWindow。

当您创建新项目时,我的 NIB 中仍然包含所有标准菜单项 - 包括“窗口”菜单中的“最小化”项,并定义了默认的快捷方式 CMD-M。它连接到发送 performMiniaturize: 给第一响应者。但是,当应用程序运行时它没有启用,所以它似乎必须询问窗口是否可以最小化并且窗口说不或什么。 (我对 OSX/Cocoa 还是很陌生。)

我错过了什么?

另外,也许这是相关的,我的无边框窗口启用了阴影 - 但与普通的标题窗口不同,当我通过单击将窗口设置为活动/前窗口时,阴影不会改变。通常,以 OSX 为中心的窗口具有稍大/更暗的阴影以使其更加突出,但我的窗口从不改变阴影。就像我缺少一些东西来让操作系统将此窗口视为真实/普通/主窗口或其他东西,结果我失去了阴影变化和正常运行的 CMD-W/CMD-M。

【问题讨论】:

  • 我认为如果你将选择器从 -performMiniaturize: 更改为 -miniaturize: 你会得到你想要的。 -performMiniaturize:不仅将窗口发送到 Dock,它还会暂时突出显示小型化按钮。这可能就是让你束手无策的原因。
  • 您不应该使用 NS 前缀。这是 Apple 在 Foundation、AppKit 和 Core Data 中的类的前缀。如果 Apple 添加了 NSBorderlessWindow 类,即使是私有的,他们的类和你的类都会发生冲突。制作自己的前缀并使用它。
  • Peter:这个类没有命名为 NSBorderlessWindow,它是一个使用 NSBorderlessWindowMask 标志的 NSWindow。我承认这措辞很糟糕。 :)

标签: objective-c cocoa


【解决方案1】:

您缺少的是,当您制作无边框窗口时,您正在消除标准窗口附带的 FrameView,它实际上实现了 -keyDown: 方法来接收这些击键并缩小或关闭窗口。

NSWindow 本身实际上是一个相当轻量级的类,我们认为的大多数标准窗口行为都是由框架视图完成的。

【讨论】:

  • 而且 NSFrameView 是无证的,不是吗?啊!即使我在窗口中截获事件或按键来执行此操作,是什么控制窗口菜单栏项中的菜单项启用/禁用?那里一定有很多魔法。
  • 没有魔法,只是响应者链。检查 Apple 的文档以了解如何验证菜单项的描述。简而言之,对于每个菜单项,都会查询其目标以查看它是否响应菜单的操作选择器。如果目标是 firstResponder,那么它将遍历响应者链,寻找实现相关方法的任何东西。
  • 在这种情况下,不应该启用菜单项吗? NSWindow 本身响应 performMiniaturize: 这是菜单项(至少)连接到的。它不是第一响应者还是不在链中或其他什么?为什么不呢?我在我的 NSWindow 子类中添加了acceptsFirstResponder 并返回YES,但它仍然不起作用。
  • 更正,典型窗口中最上面的视图是 NSThemeFrame,而不是 NSFrameView。我刚刚对 Apple 的 Round Transparent Window 示例项目做了一个小实验,结果发现,如果你向它发送 -miniaturize: 消息,即使是无边框窗口也会缩小。主题框架通常是碰巧捕捉到 command-m 的击键并将该消息发送到窗口的响应者。您应该能够使用实现 -keyDown: 并将 -miniaturize: 发送到相关窗口的窗口委托来执行相同的操作。
【解决方案2】:

可能是您删除了“文件”>“关闭”菜单项吗?

默认情况下,它具有 Cmd-W 键盘快捷键,并连接到第一响应者中的 performClose 目标。

我们通过从 Interface Builder 的库面板中拖入标准文件菜单来解决此问题。

【讨论】:

    【解决方案3】:

    我首先尝试按照 NSResponder 的建议实现 keyDown:,但这并没有成功。

    我通过简单地为关闭和最小化创建自己的 IBAction 解决了这个问题。请注意,您要在 NSBorderlessWindow 上调用 close 和 miniaturize:,而不是 performClose: 或 performMiniaturize:。

    【讨论】:

      【解决方案4】:

      要添加到已接受的答案,这里是一些在窗口子类中实现 performClose: 和 performMiniaturize: 的代码。这样做意味着您根本不必修改主菜单。

      @interface Window : NSWindow
      @end
      @implementation Window
      - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item
      {
          if ([item action] == @selector(performClose:))
              return YES;
          else if ([item action] == @selector(performMiniaturize:))
              return YES;
          return [super validateUserInterfaceItem:item];
      }
      - (IBAction)performClose:(id)sender
      {
          [self close];
      }
      - (IBAction)performMiniaturize:(id)sender
      {
          [self miniaturize:sender];
      }
      @end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-11
        • 1970-01-01
        • 2018-04-27
        • 1970-01-01
        • 1970-01-01
        • 2017-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多