iTunes 迷你播放器(仅举一个示例)支持点击,其中使用播放/暂停和音量控件时应用程序不会显示在前面。

这是怎么做到的?

我一直在浏览苹果的文档,并有一些内容要继续,在 Cocoa 事件处理指南,事件调度 它指出:

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

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

我看过马特·加拉格尔的 通过重新创建 NSApplication 来揭开它的神秘面纱, ,不幸的是马特没有报道事件队列,所以除此之外,我很困惑。

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

编辑添加: 找到了一个帖子 劳埃德休息室 他在其中谈到了同样的问题并链接到一个帖子 CocoaBuilder,捕获第一个鼠标右键按下. 。我目前正在尝试那里提供的代码,经过一些摆弄并重新激活 [theEvent type] 的 NSLog,鼠标左键活动被捕获。

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

有帮助吗?

解决方案 2

这并不是我一直在寻找的答案,但目前它的效果足够好。通过子类化 NSView 并实现以下方法,该视图就可以充当按钮。

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

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

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

不需要其他任何东西,仅此而已。当然,这绕过了我想保留的所有 NSButton 优点,我必须设计然后负责绘制和更新按钮状态,但我很高兴得到答案。

其他提示

这可以通过以下方式完成 NSPanel 它被设置为在停用时不隐藏,并且仅在需要时才成为关键。这还假设您将使用的控件返回 YES-acceptsFirstMouse:; NSButton默认情况下会这样做。

您可以通过面板的 IB 关闭隐藏停用标志,但您需要发出 -setBecomesKeyOnlyIfNeeded:YES 向面板发送消息,以防止面板和应用程序在单击按钮时继续前进。

当应用程序处于活动状态时,可以使 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

你结帐了吗 acceptsFirstMouse:?任何 NSView 可以返回 YES 对此事件表示视图应该处理该事件而不是将窗口置于前台。据推测,通过拦截该事件,它不会用于将窗口带到前台,但我不能保证这一点。

显然,您需要对您想要覆盖此行为的任何控件进行子类化 acceptsFirstMouse:.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top