macos - 如何通过按 ESC 键关闭窗口(NSWindowController)?

标签 macos cocoa first-responder nsviewcontroller nswindowcontroller

问题

我希望用户能够通过按 ESC 键来关闭窗口,但在这种特定情况下我无法让它工作,按 ESC 会触发错误声音(“不,你不能这样做” macOS bloop)并且没有任何反应。

上下文

我正在创建 NSWindowController 的子类,它本身创建 NSViewController 子类的实例并将其设置在 View 中。两个 Controller 都有自己的 xib 文件。

NSWindowController:

final class MyWindowController: NSWindowController, NSWindowDelegate {

    @IBOutlet weak var targetView: MainView!

    let myVC: MyViewController!
    var params: SomeParams!

    override func windowDidLoad() {
        super.windowDidLoad()
        myVC = MyViewController(someParams: params)
        myVC.view.setFrameSize(targetView.frame.size)
        myVC.view.setBoundsSize(targetView.bounds.size)
        targetView.addSubview(myVC.view)
    }

    override var windowNibName: String! {
        return "MyWindowController"
    }

    convenience init(someParams params: SomeType) {
        self.init(window: nil)
        self.params = params
    }

}

NSViewController:

final class MyViewController: NSViewController {

    convenience init(someParams params: SomeType) {
        // do stuff with the params
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // configure stuff for the window
    }

}

我尝试过的

假设我的问题是 MyWindowController NSWindow 是 .initialFirstResponder 当我想要 targetView (一个 NSTableView )成为第一个响应者 - 我猜这样我就可以使用 keyDown 并将关闭命令从那里发送到窗口。但这似乎并不是最佳选择。

我尝试通过在 MyWindowController 的 windowDidLoad 中使用 window?.makeFirstResponder(theView) 来强制 View Controller View 成为第一响应者,但没有任何变化。

我还尝试将其添加到 MyWindowController:

override func cancelOperation(_ sender: Any?) {
    print("yeah, let's close!")
}

但这仅适用于如果用户首先单击窗口背景然后按 ESC,并且无论如何它仍然会发出错误声音。这实际上让我认为问题在于第一响应者在窗口上。

问题

你将如何实现这一目标?当然,我知道用户已经可以使用 CMD+W 关闭窗口,但我还是很想解决这个问题。

请注意,代码示例是用 Swift 编写的,但我也可以接受使用 Objective-C 的解释。

最佳答案

cancelOperation 的文档解释了 cancelOperation 应该如何工作:

This method is bound to the Escape and Command-. (period) keys. The key window first searches the view hierarchy for a view whose key equivalent is Escape or Command-., whichever was entered. If none of these views handles the key equivalent, the window sends a default action message of cancelOperation: to the first responder and from there the message travels up the responder chain.

If no responder in the responder chain implements cancelOperation:, the key window searches the view hierarchy for a view whose key equivalent is Escape (note that this may be redundant if the original key equivalent was Escape). If no such responder is found, then a cancel: action message is sent to the first responder in the responder chain that implements it.

NSResponder declares but does not implement this method.

NSWindow 实现了 cancelOperation: 并且下一个响应者(窗口 Controller )不会检查 cancelOperation: 的实现。 cancel: 消息确实到达窗口 Controller 。实现

- (void)cancel:(id)sender
{
    NSLog(@"cancel");
}

会起作用的。 cancel: 消息不是从父类(super class)继承的,因此自动补全不建议这样做。

关于macos - 如何通过按 ESC 键关闭窗口(NSWindowController)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42393336/

相关文章:

objective-c - FirstResponder 丢失重做 :

c# - 等效于 c# 中的 python decode(string-escape)

objective-c - 核心数据获取请求不返回不同的结果

打印字符串后 xCode 控制台输出为空

cocoa - 处理Webview中的超时

cocoa - NSOutlineView(源列表)ARC 的 EXC_BAD_ACCESS 错误

objective-c - UIPopoverController 取得控制权,不会放手

ios - 点击 UIKeyboard 时触发 hitTest

macos - Emacs 24 : Unable to find theme file for `solarized-dark.

php - Laravel 6.4.1 SQLSTATE [HY000] [2002]连接被拒绝