如何通过单击外部关闭以弹出模式加载的 NSWindow?
我想处理鼠标事件,当光标位于具有焦点的模态窗口之外(但仍在应用程序内)。
当应用程序处于模态运行循环时,它不会响应任何其他事件(包括鼠标、键盘或窗口关闭事件),除非它们与窗口相关联。它也不执行任何与模态运行循环无关的任务(例如触发计时器)。
您可以使用nextEventMatchingMask:untilDate:inMode:dequeue:
方法。这将在模态循环中工作。
NSWindow 和 NSApplication 都定义了 nextEventMatchingMask:untilDate:inMode:dequeue: 方法,它允许对象从事件队列中检索特定类型的事件。
您可以实现以下委托方法NSWindow
来获取窗口失去焦点的通知。
- (void)windowDidResignKey:(NSNotification *)notification
并在内部检查,如果您的应用程序是最前面的应用程序。如果是,则相应地关闭。
如上所述,有必要重写 [NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] 方法。就我而言(插件),我必须使用从 NSApplication 派生的第 3 方未知类的现有实例。我不能只从中派生一个新类。因此我用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
方法。