通过单击外部关闭以弹出窗口形式加载的 NSWindow?
我想处理鼠标事件,当光标在具有焦点的模态窗口之外(但仍在应用程序内)时。
您可以实现以下委托NSWindow
方法来获取窗口失去焦点的通知。
- (void)windowDidResignKey:(NSNotification *)notification
并在内部检查,您的应用程序是否是最前面的应用程序。如果是,则相应地关闭。
当应用程序处于模式运行循环中时,它不会响应任何 其他事件(包括鼠标、键盘或窗口关闭事件) 除非它们与窗口相关联。它也不执行 与 模式运行循环。
您可以使用nextEventMatchingMask:untilDate:inMode:dequeue:
方法。这将在模态循环中工作。
NSWindow和NSApplication都定义了该方法 nextEventMatchingMask:untilDate:inMode:dequeue:,它允许 对象,从事件队列中检索特定类型的事件。
如上所述,有必要重写 [NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] 方法。就我而言(插件),我必须使用从NSApplication派生的第三方未知类的现有实例。我不能只是从中衍生出一个新类。因此,我使用 method_exchangeImplementations
将上面的命名方法与我自己的实现交换
+ (void)hijack
{
Class appClass = [NSApplication class];
Method originalMethod = class_getInstanceMethod(appClass, @selector(nextEventMatchingMask:untilDate:inMode:dequeue:));
Method categoryMethod = class_getInstanceMethod(appClass, @selector(my_nextEventMatchingMask:untilDate:inMode:dequeue:));
method_exchangeImplementations(originalMethod, categoryMethod);
}
如下所示:
- (NSEvent *)my_nextEventMatchingMask:(NSUInteger)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag
{
NSEvent *event = [self my_nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:deqFlag];
NSEventType type = [event type]; // 0 if event is nil
if (type == NSLeftMouseDown || type == NSRightMouseDown)
{
if ([self modalWindow] != nil && [event window] != [self modalWindow])
{
[self stopModalWithCode:NSModalResponseCancel];
event = nil;
}
}
return event;
}
最后,模态窗口按如下方式调用:
[NSApplication hijack];
[NSApp runModalForWindow:window];
[NSApplication hijack];
显然,如果您可以覆盖NSApplication,则无需定义和调用hijack
方法。