在Xcode中,视图或窗口以何种方式知道mouseDown外部的自身?

And*_*ang 4 macos xcode cocoa objective-c

我想设计一个类似于弹出窗口的面板:当鼠标向下移动时,它可能会自行消除或隐藏.

但我不知道如何实现这一目标.我所知道的是,一个视图可以处理-mouseDown,-mouseUp等等.但是当按下鼠标在其他地方?我不知道如何抓住这个事件.


进一步讨论Bavarious:

我实际上正在研究状态栏.我跟着有一个问题.我研究的示例代码.

正如示例代码所做的那样,我覆盖了前面描述的视图并使用状态栏项的-setView:方法进行设置.我工作中的大多数代码都与示例代码完全相同.以下是我认为与我的混淆相关的代码的一些部分(使用BTW,ARC):

...
@property (nonatomic) SEL disclickAction;     // Called when "dismissed"
@property (nonatomic) SEL action;             // Called when selected
@property (nonatomic, assign) id target;  
...


- (void)dealloc
{
    NSLog(@"%@ dealloc", self);
    [self invalidate];
    //[super dealloc];
}

- (void)mouseDown:(NSEvent *)theEvent
{
    [self setHighlighted:![self isHighlighted]];
    if (_target && _action &&
        [_target respondsToSelector:_action])
    {
        [NSApp sendAction:_action to:_target from:self];
    }
}

// Here is the code that Bavarious taught me:
- (void)setDisclickAction:(SEL)disclickAction
{
    _disclickAction = disclickAction;

    if (!_mouseEventMonitor)
    {
        if (_disclickAction)
        {
            self.mouseEventMonitor = [NSEvent
                           addLocalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask) 
                           handler:^NSEvent *(NSEvent *event) {
                if (event.window != self.window)
                {
                    [self actionDisclick:nil];
                }
                return event;
            }];

            [[NSNotificationCenter defaultCenter]
             addObserver:self
             selector:@selector(actionDisclick:)
             name:NSApplicationDidResignActiveNotification
             object:nil];
        }
    }
    else if (!_disclickAction)  // cancel operation
    {
        [NSEvent removeMonitor:_mouseEventMonitor];
        _mouseEventMonitor = nil;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的屏幕,例如(黄色卡通脸是我的状态栏项目):http: //oi43.tinypic.com/35cr1nb.jpg

将鼠标放在上方位置时:
A:mouseDown调用视图,然后通知鼠标按下事件的本地观察者.
B:通知鼠标停止事件的本地观察者.
C:通知辞职申请事件.
D:没有事件.鼠标停止事件的本地观察者都没有.这就是问题所在.

小智 9

AppKit负责将鼠标事件转发到发生这些事件的窗口/视图.如果您希望在其他位置捕获鼠标事件,可以使用本地事件监视器.

在应该实现此行为的类中,可能是拥有该面板的类,定义一个实例变量或声明的属性来保存事件监视器实例:

@property (nonatomic, strong) id mouseEventMonitor;
Run Code Online (Sandbox Code Playgroud)

显示面板时,添加鼠标事件监视器:

self.mouseEventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask) handler:^NSEvent *(NSEvent *event) {
    if (event.window != self.panelWindow)
        [self dismissPanel];

    return event;
}];
Run Code Online (Sandbox Code Playgroud)

关闭面板时,请删除鼠标事件监视器:

- (void)dismissPanel {
    if (self.mouseEventMonitor != nil) {
        [NSEvent removeMonitor:self.mouseEventMonitor];
        self.mouseEventMonitor = nil;
    }

    // …
}
Run Code Online (Sandbox Code Playgroud)

如果需要测试特定视图而不是包含面板的整个窗口,请使用-[NSView hitTest:]以检查鼠标位置(event.locationInWindow)是属于该视图还是属于其子视图.


编辑:如果用户在应用程序窗口外单击,则关闭面板,观察NSApplicationDidResignActiveNotification,每当应用程序重新启动其活动状态时发布该面板,这意味着某些其他应用程序已变为活动状态.当您显示面板时:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissPanel) name:NSApplicationDidResignActiveNotification object:nil];
Run Code Online (Sandbox Code Playgroud)

当你解雇小组时:

[[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidResignActiveNotification object:nil];
Run Code Online (Sandbox Code Playgroud)

编辑:要处理用户是否单击了菜单栏(NSApplicationDidResignActiveNotification由于应用程序仍处于活动状态而未发布)的情况,您还必须观察NSMenuDidBeginTrackingNotification主菜单发布的情况[NSApp mainMenu].当您显示面板时:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissPanel) name:NSMenuDidBeginTrackingNotification object:[NSApp mainMenu]];
Run Code Online (Sandbox Code Playgroud)

当你解雇小组时:

[[NSNotificationCenter defaultCenter] removeObserver:self name:NSMenuDidBeginTrackingNotification object:[NSApp mainMenu]];
Run Code Online (Sandbox Code Playgroud)