3

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

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

4

3 回答 3

0

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

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

NSWindow 和 NSApplication 都定义了 nextEventMatchingMask:untilDate:inMode:dequeue: 方法,它允许对象从事件队列中检索特定类型的事件。

于 2013-10-22T11:22:43.950 回答
0

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

- (void)windowDidResignKey:(NSNotification *)notification

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

于 2013-10-22T11:09:59.500 回答
0

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

于 2017-09-16T01:09:50.283 回答