我希望用户可以通过按ESC键来关闭窗口,但我无法让它在这种特定情况下工作,点击ESC会触发错误声音(“你不能这样做”) macOS bloop)并没有任何反应。
我正在创建NSWindowController的子类,它本身创建一个NSViewController子类的实例并在视图中设置它。两个控制器都有自己的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)
强制视图控制器视图成为第一个响应者,但没有任何变化。
我也尝试将其添加到MyWindowController:
override func cancelOperation(_ sender: Any?) {
print("yeah, let's close!")
}
但是只有当用户首先点击窗口背景然后点击ESC时,它才会起作用,它仍然会发出错误声音。这实际上是让我觉得这个问题是关于第一个响应者在窗口的问题。
你将如何实现这一目标?当然,我知道用户已经可以使用CMD + W关闭窗口了,但是我真的很想解决这个问题。
请注意,代码示例在Swift中,但我也可以接受使用Objective-C的解释。
答案 0 :(得分:6)
cancelOperation
的文档解释了cancelOperation
应如何运作:
此方法绑定到Escape和Command-。 (期间)钥匙。关键窗口首先在视图层次结构中搜索其等效键为Escape或Command-的视图,无论输入哪个。如果这些视图都不处理等效键,则窗口会向第一个响应者发送
cancelOperation:
的默认操作消息,然后消息从响应者链向上传播。如果响应者链中的响应者没有实现
cancelOperation:
,则关键窗口在视图层次结构中搜索等效键为Escape的视图(请注意,如果原始密钥等效为Escape,则这可能是多余的)。如果没有找到这样的响应者,那么cancel:
动作消息将被发送到实现它的响应者链中的第一个响应者。
NSResponder
声明但未实现此方法。
NSWindow
实现cancelOperation:
,而下一个响应者(窗口控制器)未检查cancelOperation:
的实现。 cancel:
消息确实到达窗口控制器。实施
- (void)cancel:(id)sender
{
NSLog(@"cancel");
}
会奏效。 cancel:
消息不会从超类继承,因此自动完成功能不会建议它。
答案 1 :(得分:1)
当我需要这样的行为时,我通过重写NSWindow对象的keyDown来实现它。
即。如下所示:
- (void)keyDown:(NSEvent *)theEvent
{
int k = [theEvent keyCode];
if (k == kVK_Escape)
{
[self close];
return;
}
[super keyDown:theEvent];
}
答案 2 :(得分:1)
这在Xcode 10和Swift 4.2中对我有用:
@objc func cancel(_ sender: Any?) {
close()
}
我以前尝试过它,但是没有@objc
部分,它没有用。所以不要忽略它。