How can a view or window know that mouseDown is beside itself in Xcode?

I want to create a panel that acts a bit like a popover: when the mouse goes beyond it, it can go away or hide.

But I have no idea how to achieve this. I know that a view can handle -mouseDown , -mouseUp , etc. But when is the mouse elsewhere? I do not know how to catch this event.


Further discussion with Bavarious :

I'm really doing research on the status bar . There is a question that I followed. And an example of the code I learned.

As an example of code, I overwrote the view described earlier and set it using the -setView: element. Most of my codes in my work are exactly the same as the sample code. Here are some pieces of code that I think are related to my confusion (BTW, ARC is used):

 ... @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; } } 

Here is my screen, for example (a yellow cartoon face is a state element): http://oi43.tinypic.com/35cr1nb.jpg

When holding the mouse in the positions above:
A: The mouseDown view is called, and then the local observer of the mouse down event is notified.
B: Notify the local observer of the mouse event.
C: Opt out of event notification.
D: There are no events. Neither a local mouse observer nor down. And that is the problem.

+4
source share
2 answers

AppKit takes care of forwarding mouse events to the window / view where these events occurred. If you want to catch mouse events elsewhere, you can use the local event monitor.

In a class that should implement this behavior, which probably belongs to the class to which the panel belongs, defines an instance variable or a declared property to store an instance of an event monitor:

 @property (nonatomic, strong) id mouseEventMonitor; 

When you show your panel, add a mouse event monitor:

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

When removing the panel, remove the mouse event monitor:

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

If you need to test a specific view instead of the entire window containing the panel, use -[NSView hitTest:] to check whether the mouse location ( event.locationInWindow ) event.locationInWindow to this view or to one of its subzones.


Edit:. To cancel the panel if the user clicks outside the application windows, observe the NSApplicationDidResignActiveNotification , which is published whenever the application resigns from its active state, which means that some other application has become active. When you show the panel:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissPanel) name:NSApplicationDidResignActiveNotification object:nil]; 

And when you remove the panel:

 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidResignActiveNotification object:nil]; 

Edit:. To handle the case if the user clicked the menu bar (which does not send NSApplicationDidResignActiveNotification , because the application is still active), you should also observe the NSMenuDidBeginTrackingNotification sent to the main menu, [NSApp mainMenu] . When you show the panel:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissPanel) name:NSMenuDidBeginTrackingNotification object:[NSApp mainMenu]]; 

And when you remove the panel:

 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMenuDidBeginTrackingNotification object:[NSApp mainMenu]]; 
+8
source

You can create a transparent or translucent background view, which is UIButton. You can place on it all the elements of the view. Add a handler to the button to handle closing or hiding the view. Something like that:

 - (id)init { self = [super init]; if(self) { [self createBackground]; [self createUIElements]; } return self; } - (void)createBackground { UIButton *backgroundButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; [backgroundButton addTarget:self forSelector:@selector(closeOrHide) forControlEvent:UIControlEventTouchUpInside]; [self addSubview:backgroundButton]; //If no-arc [backgroundButton release]; backgroundButton = nil } - (void)closeOrHide { //Do stuff } 
-2
source

Source: https://habr.com/ru/post/1484550/


All Articles