Dominik Seibold
Dominik Seibold

Reputation: 2469

mouseMoved not called

I have a subclassed NSView which is part of a .xib-file of a subclassed NSDocument, which gets alive by the default behaviour of NSDocumentController's openDocument: method. In this subclassed NSView I have implemented the methods awakeFromNib, in which the view's NSWindow setAcceptsMouseMovedEvents:YES method is called, and acceptsFirstMouse:, which returns YES. But my mouseMoved: method implementation of my subclassed NSView doesn't get called when I move the mouse over it. What might be the problem?

Upvotes: 21

Views: 15397

Answers (6)

andrewchan2022
andrewchan2022

Reputation: 5290

oc version:

    - (void)updateTrackingAreas {
        [self initTrackingArea];
    }
    
    -(void) initTrackingArea {
        NSTrackingAreaOptions options = (NSTrackingActiveAlways | NSTrackingInVisibleRect |
                                 NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved);
    
        NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:[self bounds]
                                                            options:options
                                                              owner:self
                                                           userInfo:nil];
        
        [self addTrackingArea:area];
    }

Upvotes: 1

user12829349
user12829349

Reputation:

Deshitified version of @jbouwman s answer:

override func updateTrackingAreas() {
    self.addTrackingArea(NSTrackingArea(rect: self.bounds, options: [.mouseEnteredAndExited, .mouseMoved, .activeInKeyWindow], owner: self, userInfo: nil))
}

Upvotes: 2

jbouwman
jbouwman

Reputation: 2117

As noted by others, an NSTrackingArea is a good solution, and an appropriate place to install the tracking area is NSView.updateTrackingAreas(). It isn't necessary to set the containing NSWindow's setAcceptsMouseMovedEvents property.

In Swift 3:

class CustomView : NSView {

    var trackingArea : NSTrackingArea?

    override func updateTrackingAreas() {
        if trackingArea != nil {
            self.removeTrackingArea(trackingArea!)
        }
        let options : NSTrackingAreaOptions =
            [.mouseEnteredAndExited, .mouseMoved, .activeInKeyWindow]
        trackingArea = NSTrackingArea(rect: self.bounds, options: options,
                                      owner: self, userInfo: nil)
        self.addTrackingArea(trackingArea!)
    }

    override func mouseMoved(with event: NSEvent) {
        Swift.print("Mouse moved: \(event)")
    }
}

Upvotes: 24

Kyle
Kyle

Reputation: 17677

Just incase anyone else runs into this. I ran into an issue where I was subclassing a subclass and was trying to add a tracking area to both classes (for two different reasons).

If you are doing something like this, you will need to make sure that your mouseMoved:, etc call into the super, or only one of your subclasses will receive the message.

- (void) mouseMoved: (NSEvent*) theEvent
{
    // Call the super event
    [super mouseMoved: theEvent];
}

Upvotes: 1

zeeple
zeeple

Reputation: 5607

Be sure to request the mouseMoved event is sent:

NSTrackingAreaOptions options = (NSTrackingActiveAlways | NSTrackingInVisibleRect |  
                         NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved);

NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:[self bounds]
                                                    options:options
                                                      owner:self
                                                   userInfo:nil];

Upvotes: 31

Michael
Michael

Reputation: 447

I haven't used mouseMoved: in a real project (I've just played around with it a little). As far as I can tell, mouseMoved: is only called when your view is the first responder and then not only while the mouse is over your view, but always when the mouse moves. You might be better off using an NSTrackingArea. Check the Cocoa Event Handling Guide for more information.

Upvotes: 13

Related Questions