iTunes迷你播放器(仅举一个例子)支持点击,当使用播放/暂停和音量控制时,应用程序不会显示在前面。
这是怎么做到的?
我一直在查看Apple的文档,并在Cocoa Event-Handling Guide, Event Dispatch中指出了一些内容:
某些事件,其中许多是由Application Kit(类型NSAppKitDefined)定义的,与窗口或应用程序对象本身控制的操作有关。这些事件的示例是与激活,停用,隐藏和显示应用程序相关的事件。 NSApp在其调度例程的早期过滤掉这些事件并自行处理它们。
所以,从我有限的理解(How an Event Enters a Cocoa, Application)继承NSApplication和覆盖
- (void)sendEvent:(NSEvent *)theEvent
应该捕获每个鼠标和键盘事件,但仍然会在单击时引发窗口。因此,在NSApplication看到事件之前窗口会被提升,或者我错过了其他内容。
我看过Matt Gallagher的Demystifying NSApplication by recreating it,不幸的是Matt没有报道事件队列,所以除此之外,我很难过。
任何帮助都将不胜感激,谢谢。
已编辑添加:在Lloyd's Lounge找到了一个帖子,其中他谈到同一问题并链接到CocoaBuilder, capture first right mouse down的帖子。我正在尝试在那里提供的代码,在一些摆弄并重新激活[theEvent类型]的NSLog后,鼠标左键活动被捕获。
现在,左键单击窗口将其向前移动会生成一系列事件类型13, 1, 13
,这些类型又是NSAppKitDefined,NSLeftMouseDown和NSAppKitDefined。我可以过滤掉它们或找到它们的去向吗?
答案 0 :(得分:3)
这可以通过NSPanel
来完成,该YES
被设置为在停用时不隐藏,并且仅在需要时成为关键。这也假定您将使用的控件将-acceptsFirstMouse:
返回NSButton
; -setBecomesKeyOnlyIfNeeded:YES
默认情况下会这样做。
您可以通过IB为面板关闭隐藏在停用状态标记,但是您需要向面板发出{{1}}消息,以便在按钮点击时保持该应用程序不会出现。
答案 1 :(得分:2)
这不是我想要的答案,但是现在它的效果非常好。
通过继承NSView
并实现以下方法,该视图可以充当按钮。
- (void)mouseDown:(NSEvent *)theEvent {
[NSApp preventWindowOrdering];
// [self setNeedsDisplay:YES];
}
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent {
return YES;
}
- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent {
return YES;
}
不需要其他任何东西,就是这样。当然这绕过了我想要保留的所有NSButton优点,我必须设计然后处理绘制和更新按钮状态,但我很高兴得到答案。
答案 2 :(得分: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
答案 3 :(得分:1)
你签出了acceptsFirstMouse:
吗?任何NSView
都可以向此事件返回YES
,表示视图应该处理事件而不是将窗口置于前台。据推测,通过拦截事件,它不会被用来将窗口带到前台,但我无法保证这一点。
您显然需要将要使此行为的任何控件子类化以覆盖acceptsFirstMouse:
。