5

iTunes 迷你播放器(仅举一个例子)支持点击,当使用播放/暂停和音量控制时,应用程序不会被带到前面。

这是怎么做到的?

我一直在查看 Apple 的文档,并且在Cocoa Event-Handling Guide 中,Event Dispatch中指出:

一些事件,其中许多是由应用程序工具包(类型 NSAppKitDefined)定义的,与窗口或应用程序对象本身控制的操作有关。这些事件的示例是与激活、停用、隐藏和显示应用程序相关的事件。NSApp 在其调度例程的早期过滤掉这些事件并自行处理它们。

因此,根据我有限的理解(事件如何进入可可,应用程序)子类化 NSApplication 和覆盖 - (void)sendEvent:(NSEvent *)theEvent应该捕获每个鼠标和键盘事件,但是仍然会在单击时弹出窗口。因此,要么在 NSApplication 看到事件之前引发窗口,要么我错过了其他东西。

通过重新创建查看了 Matt Gallagher 的 Demystifying NSApplication,不幸的是,Matt 没有涵盖事件队列,所以除此之外,我很难过。

任何帮助将不胜感激,谢谢。

编辑添加:在Lloyd's Lounge找到一个帖子,其中他谈到了同样的问题,并链接到CocoaBuilder 上的帖子,先捕获鼠标右键。我目前正在尝试那里提供的代码,经过一番摆弄并重新激活 [theEvent 类型] 的 NSLog 后,鼠标左键活动被捕获。

现在,左键单击窗口将其向前移动会产生一系列事件类型,13, 1, 13它们是 NSAppKitDefined、NSLeftMouseDown 和 NSAppKitDefined。我可以过滤掉这些或找到它们的去向吗?

4

4 回答 4

3

这可以通过NSPanel设置为在停用时不隐藏并仅在需要时成为密钥来完成。这也假设您将使用的控件返回YES-acceptsFirstMouse:; NSButton默认情况下这样做。

您可以通过 IB 为面板关闭禁用时隐藏标志,但您需要向-setBecomesKeyOnlyIfNeeded:YES面板发出消息以防止它和应用程序在按钮单击时出现。

于 2009-09-30T20:30:29.423 回答
2

这不是我一直在寻找的答案,但现在它工作得很好。通过子类NSView化和实现以下方法,该视图可以充当按钮。

- (void)mouseDown:(NSEvent *)theEvent {
    [NSApp preventWindowOrdering];
//  [self setNeedsDisplay:YES];
}

- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent {
    return YES;
}

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent {
    return YES;
}

其他什么都不需要,就是这样。当然,这绕过了我想要保留的所有 NSButton 优点,我必须设计然后负责绘制和更新按钮状态,但我很高兴得到答案。

于 2009-10-23T14:20:39.867 回答
2

当应用程序处于活动状态时,可以使 NSButton 响应点击事件而不改变其行为:

界面(ClickThroughButton.h):

#import <AppKit/AppKit.h>

@interface ClickThroughButton : NSButton

@end

实现(ClickThroughButton.m):

#import "ClickThroughButton.h"

@implementation ClickThroughButton

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent {
    return ![NSApp isActive];    
}

- (void)mouseDown:(NSEvent *)theEvent {    
    if (![NSApp isActive]) {
        [NSApp preventWindowOrdering];        

        [self highlight:YES];

        NSEvent *mouseUpEvent = [[self window] nextEventMatchingMask:NSLeftMouseUpMask
                                                  untilDate:[NSDate distantFuture]
                                                     inMode:NSEventTrackingRunLoopMode
                                                    dequeue:YES];
        NSPoint mouseLocation = [self convertPoint:[mouseUpEvent locationInWindow] fromView:nil];
        BOOL mouseUpInside = [self mouse:mouseLocation inRect:[self bounds]];

        if (mouseUpInside) {
            if ([self target])
                [[self target] performSelector:[self action] withObject:self]; 
        }

        [self highlight:NO];            

    } else {
        [super mouseDown:theEvent];        
    }
}

@end
于 2011-11-16T18:04:19.687 回答
1

你检查了acceptsFirstMouse:吗?任何人NSView都可以返回YES到这个事件,说视图应该处理这个事件,而不是把窗口带到前台。据推测,通过拦截事件,它不会用于将窗口带到前台,但我不能保证这一点。

显然,您需要将任何想要具有此行为的控件子类化为 override acceptsFirstMouse:

于 2009-09-30T19:17:11.433 回答