Move the NSView around until it reaches the border

In a Cocoa app, I have a drawing canvas inherited from NSView, as well as a rectangle also inherited from NSView. Dragging a rectangle around the canvas is not a problem:

-(void)mouseDragged:(NSEvent *)theEvent { NSPoint myOrigin = self.frame.origin; [self setFrameOrigin:NSMakePoint(myOrigin.x + [theEvent deltaX], myOrigin.y - [theEvent deltaY])]; } 

It works like a charm. The problem I'm facing right now is: how can I prevent the rectangle from moving outside the canvas?

So, first of all, I would like to fix this only for the left border, then adapting the other edges. My first idea is to "check if the x-origin of the rectangle is negative." But: as soon as this is negative, the rectangle can no longer move around (naturally). I solved this by moving the rectangle to zero x-offset in the else branch. It works, but it's ... ugly.

So, I'm a little puzzled by this, any hints? Definitely, the solution is really close and easy. It is easy that I cannot figure it out (as always with easy solutions).

Hello

Macs

+4
source share
1 answer

I suggest not using deltaY and deltaY ; try using the location of the event in supervision. You will need a link to the preview.

 // In the superview - (void)mouseDragged:(NSEvent *)event { NSPoint mousePoint = [self convertPoint:[event locationInWindow] fromView:nil]; // Could also add the width of the moving rectangle to this check // to keep any part of it from going outside the superview mousePoint.x = MAX(0, MIN(mousePoint.x, self.bounds.size.width)); mousePoint.y = MAX(0, MIN(mousePoint.y, self.bounds.size.height)); // position is a custom ivar that indicates the center of the object; // you could also use frame.origin, but it looks nicer if objects are // dragged from their centers myMovingRectangle.position = mousePoint; [self setNeedsDisplay:YES]; } 

You would do the same bounds check in mouseUp:

UPDATE:. You should also take a look at the Programming Guide in a view in which you are prompted to create a drag-and-drop view: Create a Custom View .


Sample code that should be useful, although it has no strict relevance to your original question:

In DotView.m:

 - (void)drawRect:(NSRect)dirtyRect { // Ignoring dirtyRect for simplicity [[NSColor colorWithDeviceRed:0.85 green:0.8 blue:0.8 alpha:1] set]; NSRectFill([self bounds]); // Dot is the custom shape class that can draw itself; see below // dots is an NSMutableArray containing the shapes for (Dot *dot in dots) { [dot draw]; } } - (void)mouseDown:(NSEvent *)event { NSPoint mousePoint = [self convertPoint:[event locationInWindow] fromView:nil]; currMovingDot = [self clickedDotForPoint:mousePoint]; // Move the dot to the point to indicate that the user has // successfully "grabbed" it if( currMovingDot ) currMovingDot.position = mousePoint; [self setNeedsDisplay:YES]; } // -mouseDragged: already defined earlier in post - (void)mouseUp:(NSEvent *)event { if( !currMovingDot ) return; NSPoint mousePoint = [self convertPoint:[event locationInWindow] fromView:nil]; spot.x = MAX(0, MIN(mousePoint.x, self.bounds.size.width)); spot.y = MAX(0, MIN(mousePoint.y, self.bounds.size.height)); currMovingDot.position = mousePoint; currMovingDot = nil; [self setNeedsDisplay:YES]; } - (Dot *)clickedDotForPoint:(NSPoint)point { // DOT_NUCLEUS_RADIUS is the size of the // dot internal "handle" for( Dot *dot in dots ){ if( (abs(dot.position.x - point.x) <= DOT_NUCLEUS_RADIUS) && (abs(dot.position.y - point.y) <= DOT_NUCLEUS_RADIUS)) { return dot; } } return nil; } 

Dot.h

 #define DOT_NUCLEUS_RADIUS (5) @interface Dot : NSObject { NSPoint position; } @property (assign) NSPoint position; - (void)draw; @end 

Dot.m

 #import "Dot.h" @implementation Dot @synthesize position; - (void)draw { //!!!: Demo only: assume that focus is locked on a view. NSColor *clr = [NSColor colorWithDeviceRed:0.3 green:0.2 blue:0.8 alpha:1]; // Draw a nice border NSBezierPath *outerCirc; outerCirc = [NSBezierPath bezierPathWithOvalInRect: NSMakeRect(position.x - 23, position.y - 23, 46, 46)]; [clr set]; [outerCirc stroke]; [[clr colorWithAlphaComponent:0.7] set]; [outerCirc fill]; [clr set]; // Draw the "handle" NSRect nucleusRect = NSMakeRect(position.x - DOT_NUCLEUS_RADIUS, position.y - DOT_NUCLEUS_RADIUS, DOT_NUCLEUS_RADIUS * 2, DOT_NUCLEUS_RADIUS * 2); [[NSBezierPath bezierPathWithOvalInRect:nucleusRect] fill]; } @end 

As you can see, the Dot class is very lightweight and uses bezier paths for drawing. The supervisor can handle user interaction.

+5
source

All Articles