Перетаскивание прямоугольника в какао - PullRequest
6 голосов
/ 06 декабря 2011

Я рисую прямоугольник на пользовательском подклассе NSView, который затем можно перетаскивать в пределах границ вида:

enter image description here

Код для этого:

    // Get the starting location of the mouse down event.
NSPoint location = [self convertPoint: [event locationInWindow] fromView: nil];

// Break out if this is not within the bounds of the rect.
if (!NSPointInRect(location, [self boundsOfAllControlPoints])) {
    return;
}

while (YES) {

    // Begin modal mouse tracking, looking for mouse dragged and mouse up events
    NSEvent *trackingEvent = [[self window] nextEventMatchingMask:(NSLeftMouseDraggedMask | NSLeftMouseUpMask)];

    // Get tracking location and convert it to point in the view.
    NSPoint trackingLocation = [self convertPoint:[trackingEvent locationInWindow] fromView:nil];

    // Calculate the delta's of x and y compared to the previous point.
    long dX = location.x - trackingLocation.x;
    long dY = location.y - trackingLocation.y;

    // Update all points in the rect
    for (int i = 0; i < 4; i++) {
        NSPoint newPoint = NSMakePoint(points[i].x - dX, points[i].y - dY);
        points[i] = newPoint;
    }

    NSLog(@"Tracking location x: %f y: %f", trackingLocation.x, trackingLocation.y);

    // Set current location as previous location.
    location = trackingLocation;

    // Ask for a redraw.
    [self setNeedsDisplay:YES];

    // Stop mouse tracking if a mouse up is received.
    if ([trackingEvent type] == NSLeftMouseUp) {
        break;
    }

}

Я в основном ловлю событие нажатия мыши и проверяю, находится ли оно внутри перетаскиваемого прямоугольника.Если это так, я начинаю отслеживать движение мыши в trackingEvent.Я вычисляю дельту для координат x и y, создаю новые точки для перетаскиваемого прямоугольника и запрашиваю обновление отображения представлений.

Хотя это работает, оно выглядит немного «любительским», как во время перетаскивания,указатель мыши догонит перетаскиваемую фигуру и в конечном итоге пересечет ее границы.В других операциях перетаскивания указатель мыши будет зафиксирован на месте перетаскиваемого объекта от начала до конца операции перетаскивания.

Что вызывает этот эффект?

РЕДАКТИРОВАТЬ:

Я изменил свой подход после ответа Роба и принял метод трех методов:

- (void) mouseDown: (NSEvent*) event {

    // There was a mouse down event which might be in the thumbnail rect.

    [self setDragStartPoint: [self convertPoint: [event locationInWindow] fromView: nil]];

    // Indicate we have a valid start of a drag.
    if (NSPointInRect([self dragStartPoint], [self boundsOfAllControlPoints])) {
        [self setValidDrag: YES];
    }

}

- (void) mouseDragged: (NSEvent *) anEvent {

    // Return if a valid drag was not detected during a mouse down event.
    if (![self validDrag]) {
        return;
    }

    NSLog(@"Tracking a drag.");

    // Get tracking location and convert it to point in the view.
    NSPoint trackingLocation = [self convertPoint: [anEvent locationInWindow] fromView: nil];

    // Calculate the delta's of x and y compared to the previous point.
    long dX = [self dragStartPoint].x - trackingLocation.x;
    long dY = [self dragStartPoint].y - trackingLocation.y;

    // Update all points in the rect
    for (int i = 0; i < 4; i++) {
        NSPoint newPoint = NSMakePoint(points[i].x - dX, points[i].y - dY);
        points[i] = newPoint;
    }

    // Ask for a redraw.
    [self setNeedsDisplay:YES];

    NSLog(@"Tracking location x: %f y: %f", trackingLocation.x, trackingLocation.y);

    // Set current location as previous location.
    [self setDragStartPoint: trackingLocation];

    NSLog(@"Completed mouseDragged method. Allow for repaint.");

}

- (void) mouseUp: (NSEvent *) anEvent {

    // End the drag.
    [self setValidDrag: NO];
    [self setNeedsDisplay: YES];

}

Хотя эффект немного лучше, все еще есть заметная задержка спрямоугольник в итоге перетаскивается за направление движения указателя мыши.Это особенно заметно, когда я медленно двигаю мышь во время перетаскивания.

EDIT 2:

Понял.Проблема была с подсчетом дельт.Я использовал долго для этого, в то время как я должен использовать float.Отлично работает сейчас.

1 Ответ

10 голосов
/ 06 декабря 2011

Вы держитесь за цикл событий во время розыгрыша, что означает, что квадрат никогда не перерисовывается.Ваш звонок на setNeedsDisplay: ничего не рисует.Это просто помечает вид для перерисовки.Он не может перерисовать, пока эта процедура не вернется, чего нельзя делать, пока не отпущена кнопка мыши.

Чтение Обработка операций перетаскивания мышью для полного обсуждения того, как реализовать перетаскивание вКакао.Вам нужно либо вернуться из mouseDown: и переопределить mouseDragged: и mouseUp:, либо вам нужно самостоятельно прокачать цикл событий, чтобы цикл обработки мог обрабатываться.

Я склонен рекомендовать первый подход,хотя это требует нескольких методов.Прокачка цикла событий может привести к очень неожиданным ошибкам и должна использоваться с осторожностью.Наиболее распространенные ошибки в моем опыте связаны с задержкой срабатывания селекторов при прокачке цикла событий, в результате чего «лишний» код запускается в середине вашей процедуры перетаскивания.В некоторых случаях это может привести к повторному входу и тупику.(У меня было это случилось ....)

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