点击按钮而不升起窗口
-
19-09-2019 - |
题
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:
.