I created a subclass of NSImageView
to capture mouseEntered
and mouseExited
events.
But only mouseUp
and mouseDown
events are getting called. How to capture the mouseEntered
and mouseExited
events in NSImageView
subclass?
Asked
Active
Viewed 1.3k times
39

Justin Boo
- 10,132
- 8
- 50
- 71

Ram
- 1,872
- 5
- 31
- 54
4 Answers
85
If You want to use mouseEntered:
and mouseExited:
You need to use NSTrackingArea
. Here is reference NSTrackingArea Class Reference.
Example:
//Add this to Your imageView subclass
-(void)mouseEntered:(NSEvent *)theEvent {
NSLog(@"Mouse entered");
}
-(void)mouseExited:(NSEvent *)theEvent
{
NSLog(@"Mouse exited");
}
-(void)updateTrackingAreas
{
[super updateTrackingAreas];
if(trackingArea != nil) {
[self removeTrackingArea:trackingArea];
[trackingArea release];
}
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}

Deadpikle
- 356
- 6
- 22

Justin Boo
- 10,132
- 8
- 50
- 71
-
17@ArtOfWarfare Or it is the reality of having a complex view hierarchy and not wanting to invoke potentially hundreds of thousands of methods when the user merely slides the pointer over a hunk of UI. This is the age old **Never poll, always pull.** – bbum Mar 20 '15 at 16:21
-
Bingoo, Worked like charm – Pete Apr 13 '15 at 09:34
-
5@Edward What? Pull vs. Poll? No; **Significantly** more relevant in 2016 than 1988. In 1988, devices were all powered from the wall. In 2016, the majority of devices are powered by a battery and *polling* is devastating to battery life. – bbum Apr 12 '16 at 19:35
-
1@bbum just realized you work at the mothership. I bow. – Edward Apr 12 '16 at 19:45
-
@Edward I've been at this ObjC thing for a long, long time. :) – bbum Apr 13 '16 at 19:43
-
2"Invoke hundereds and thousands of methods when the user merely slides the pointer"? What is there to invoke if no callback function is defined? C# has the exact same callback for all controls, and you don't have to setup weird insider snippets of code, buried inside tones of documentation. If you've defined a callback for a control it gets invoked, otherwise nothing. As simple as that. I don't get what's so different in OS X stack that makes this necessary. – Hashman May 06 '16 at 03:19
-
1Few things missing from this solution, see: http://stackoverflow.com/questions/8979639/mouseexited-isnt-called-when-mouse-leaves-trackingarea-while-scrolling – Elise van Looij Apr 23 '17 at 14:45
-
Why are we running this code everytime we updateTrackingAreas()? Would it be better to put in the init() of the NSImageView? – Ricardo Anjos Dec 14 '18 at 10:40
-
1@RicardoAnjos updateTrackingAreas is the appropriate place for this in general. For example, if this were somewhere earlier (e.g. in init) it wouldn't be properly recreated when the view was moved or resized. – clarkcox3 Dec 19 '18 at 22:12
13
Swift 4 version of Justin Boo's answer
override func updateTrackingAreas() {
super.updateTrackingAreas()
for trackingArea in self.trackingAreas {
self.removeTrackingArea(trackingArea)
}
let options: NSTrackingArea.Options = [.mouseEnteredAndExited, .activeAlways]
let trackingArea = NSTrackingArea(rect: self.bounds, options: options, owner: self, userInfo: nil)
self.addTrackingArea(trackingArea)
}
-
1Can/should we not edit existing answers to update them to the latest version of a language? – STO Sep 07 '18 at 09:11
11
Swift 3 Version of @Justin Boo's answer:
private var trackingArea: NSTrackingArea?
override func updateTrackingAreas() {
super.updateTrackingAreas()
if let trackingArea = self.trackingArea {
self.removeTrackingArea(trackingArea)
}
let options: NSTrackingAreaOptions = [.mouseEnteredAndExited, .activeAlways]
let trackingArea = NSTrackingArea(rect: self.bounds, options: options, owner: self, userInfo: nil)
self.addTrackingArea(trackingArea)
}

Nikolay Suvandzhiev
- 8,465
- 6
- 41
- 47
-
-
1@CharltonProvatas, you're right, it was a mistake. The official docs also say that it should be called. My answer has now been updated. – Nikolay Suvandzhiev Jan 02 '19 at 13:39
4
C# Xamarin version of Justin Boo's answer
public override void UpdateTrackingAreas ()
{
base.UpdateTrackingAreas ();
foreach (var item in TrackingAreas ()) {
RemoveTrackingArea (item);
}
var options = NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveAlways;
var trackingArea = new NSTrackingArea (this.Bounds, options, this, null);
AddTrackingArea (trackingArea);
}

Dominique
- 817
- 1
- 5
- 10