Перемещайте NSView, пока он не достигнет границы - PullRequest
4 голосов
/ 21 апреля 2011

В приложении на основе какао у меня есть холст для рисования, унаследованный от NSView, а также прямоугольник, также унаследованный от NSView.Перетаскивание прямоугольника внутри холста не проблема:

-(void)mouseDragged:(NSEvent *)theEvent {
  NSPoint myOrigin = self.frame.origin;

  [self setFrameOrigin:NSMakePoint(myOrigin.x + [theEvent deltaX], 
                                   myOrigin.y - [theEvent deltaY])];
}

Работает как шарм.Проблема, с которой я столкнулся сейчас: как я могу предотвратить перемещение прямоугольника за пределы холста?

Итак, прежде всего, я хотел бы исправить это только для левой границы, адаптируя другие края позже.Моя первая идея: «проверить, является ли x-origin прямоугольника отрицательным».Но: если он отрицательный, прямоугольник больше нельзя перемещать (естественно).Я решил это с перемещением прямоугольника к нулевому смещению в ветви else.Это работает, но ... некрасиво.

Так что я немного озадачен этим, какие-то намеки?Определенно решение действительно близко и легко.Это так просто, что я не могу понять это (как всегда с простыми решениями;).

С уважением

Macs

1 Ответ

5 голосов
/ 21 апреля 2011

Я бы предложил не использовать deltaX и deltaY; попробуйте использовать местоположение события в суперпредставлении . Вам понадобится ссылка на подпредставление.

// 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];
}

Вы бы сделали, по сути, ту же проверку границ в mouseUp:.

ОБНОВЛЕНИЕ: Вы также должны взглянуть на Руководство по программированию представления, которое проведет вас через создание перетаскиваемого представления: Создание пользовательского представления .


Пример кода, который должен быть полезен, хотя и не строго относится к вашему исходному вопросу:

В 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's 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

Как видите, класс Dot очень легок и использует для рисования более безликие пути. Superview может обрабатывать взаимодействие с пользователем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...