2011-12-05 2 views
6
내가 다음 뷰의 경계 내에서 드래그 할 수는 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; 
    } 

} 

기본적으로 나는 마우스 이벤트를 잡아서 그 위치가 드래그 가능한 rect 안에 있는지 확인합니다. 그렇다면 trackingEvent에서 마우스의 움직임을 추적하기 시작합니다. x와 y 좌표에 대한 델타 값을 계산하고, 드래그 가능한 rect에 대한 새로운 포인트를 만들고, 뷰 디스플레이의 새로 고침을 요청합니다.

효과가 있지만 드래그하는 동안 조금 "아마추어"처럼 보입니다. 마우스 포인터는 드래그되는 모양을 따라 잡을 것이고 결국 경계를 넘을 것입니다. 다른 드래그 작업에서는 끌기 작업의 시작부터 끝까지 드래그되는 객체의 위치에 마우스 포인터가 고정되어 표시됩니다.

이 효과의 원인은 무엇입니까?

편집 : 내가 롭의 대답은 다음과 나의 접근 방식을 변경하고 세 가지 방법의 접근 방식을 채택했습니다

: 효과가 약간 더 있지만

- (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]; 

} 

을 여전히 RECT와 눈에 띄는 지연있다 결국 마우스 포인터의 움직임 방향 뒤에서 드래그합니다. 드래그하는 동안 마우스를 천천히 움직이면 특히 눈에.니다.

편집 2 :

알아보기 문제는 델타 계산에있었습니다. 저는 플로트를 사용해야하는 동안 오랫동안 사용했습니다. 이제 잘됩니다.

+1

마우스를 끌기위한 코드를 공유해 주셔서 감사합니다. – Tommy

답변

9

그리는 동안 이벤트 루프를 잡고 있습니다. 즉, 사각형을 다시 그릴 수 없습니다. setNeedsDisplay:에 전화하면 아무 것도 그려지지 않습니다. 다시 그려지는 뷰에 플래그를 지정합니다. 이 루틴이 반환 될 때까지 다시 그리기를 할 수 없으며 마우스 단추를 놓을 때까지하지 않습니다.

코코아에서 드래그를 구현하는 방법에 대한 전체 설명은 Handling Mouse Dragging Operations을 참조하십시오. mouseDown:에서 돌아와 mouseDragged:mouseUp:을 다시 지정해야하거나 드로잉주기를 처리 할 수 ​​있도록 이벤트 루프를 직접 펌핑해야합니다.

여러 가지 방법이 필요하지만 첫 번째 방법을 권장하는 경향이 있습니다. 이벤트 루프를 펌핑하면 매우 놀라운 버그가 발생할 수 있으므로주의해서 사용해야합니다. 내 경험상 가장 일반적인 버그는 이벤트 루프를 펌프질 할 때 연기 된 선택기가 발사되어 끌기 루틴의 중간에 "여분"코드가 실행되는 것입니다. 어떤 경우에는 재진입과 교착 상태가 발생할 수 있습니다. (나는 이런 일이 있었어 ....)

+0

+1 - 언급 된 첫 번째 접근 방식에 확실하게 동의합니다. – bryanmac