如何通过单击外部来关闭以弹出方式加载的NSWindow?

时间:2013-10-22 10:39:19

标签: objective-c cocoa

如何通过点击外部来关闭以弹出方式加载的NSWindow?

我想处理鼠标事件,当光标位于具有焦点的模态窗口之外时(但仍在应用程序内)。

3 个答案:

答案 0 :(得分:0)

您可以实现NSWindow的以下委托方法,以获取窗口失去焦点的通知。

- (void)windowDidResignKey:(NSNotification *)notification

在内部检查,如果您的应用程序是最前面的应用程序。如果是,则相应关闭。

答案 1 :(得分:0)

  

虽然应用程序处于模态运行循环中,但它不会响应任何应用程序   其他事件(包括鼠标,键盘或窗口关闭事件)   除非它们与窗口相关联。它也不会执行   任何与之无关的任务(如射击计时器)   模态运行循环。

您可以使用nextEventMatchingMask:untilDate:inMode:dequeue:方法。这可以在模态循环中使用。

  

NSWindow和NSApplication都定义了该方法   nextEventMatchingMask:untilDate:inMode:dequeue:,它允许一个   object用于从事件队列中检索特定类型的事件。

答案 2 :(得分:0)

如上所述,有必要覆盖[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方法。