Whats the correct way to calculate point in view that mouse was clicked

1.7k views Asked by At

I have a custom subclass of NSView in my app. I would like to know the exact point in the view, relative to it's origin, that was clicked with the mouse. (i.e. Not relative to the Window origin, but relative to the custom-view origin).

I have always used this, which has worked perfectly:

-(void)mouseDown:(NSEvent *)theEvent
{
    NSPoint screenPoint = [NSEvent mouseLocation];
    NSPoint windowPoint = [[self window] convertScreenToBase:screenPoint];
    NSPoint point = [self convertPoint:windowPoint fromView:nil];

    _pointInView = point;

    [self setNeedsDisplay:YES];
}

But now I get a warning that convertScreenToBase is deprecated and to use convertRectFromScreen instead. However I cannot get the same results from convertRectFromScreen, and anyway, I'm interested in a point, not a rect!

What should I use as the correct replacement for the deprecated code above? Thanks in advance!

4

There are 4 answers

1
Kenny On BEST ANSWER

I found the solution:

NSPoint screenPoint = [NSEvent mouseLocation];
NSRect screenRect = CGRectMake(screenPoint.x, screenPoint.y, 1.0, 1.0);
NSRect baseRect = [self.window convertRectFromScreen:screenRect];
_pointInView = [self convertPoint:baseRect.origin fromView:nil];
0
Ken Thomases On

This line from your code:

    NSPoint screenPoint = [NSEvent mouseLocation];

gets the location of the mouse cursor out of sync with the event stream. It's not the position of the event you're currently handling, which was a short time in the past; it's the position of the cursor right now, which means you're potentially skipping past some important stuff. You should almost always use the position in sync with the event stream.

To do that, use the theEvent parameter that your method receives. NSEvent has a locationInWindow property, which has already been translated to the coordinates of the window which receives it. That eliminates the need for you to convert it.

    NSPoint windowPoint = [theEvent locationInWindow];    

Your code to convert the window location to the view's coordinate system is fine.

4
mangerlahn On

I have made a sample project with a window and tested the 'old' and new scenario. The result is the same in both cases.

You have to make one additional step: Create a simple rect with the screenPoint as origin. Then use the origin of the new, returned rect.

Here is the new code:

-(void)mouseDown:(NSEvent *)theEvent
{
    NSPoint screenPoint = [NSEvent mouseLocation];
    NSRect rect = [[self window] convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 0, 0)];

    NSPoint windowPoint = rect.origin;
    NSPoint point = [self convertPoint:windowPoint fromView:nil];

    _pointInView = point;

    [self setNeedsDisplay:YES];
}

I hope I was able to help you!

0
Honghao Z On

Simply use convert(_:from:) can be inaccurate, this can happen when event's window and view's window are not the same. Please check my answer in another question for a more robust way.

https://stackoverflow.com/a/69784415/3164091