Using Drag and Drop in Tables

OSXDEV

Jump to: navigation, 찾기

NSTableView 클래스는 비정형 프로토콜인 NSDraggingSource와 NSDraggingDestination 두가지 모두를 구현한다. 이 프로토콜이 대부분의 드래그 동작의 자세한 부분을 관리하며, 드래그 동작이 시작될때와 드래그 동작을 받을 때 테이블 뷰의 데이터 소스에 메세지를 보낸다. 테이블 뷰에서 드래그앤 드랍을 지원하기 위해 최소한으로 요구되는 단계는 다음과 같다


  1. 테이블 뷰의 registerForDraggedTypes: 메소드를 호출해서 테이블이 지원하는 데이터 타입을 지정한다.
  2. 데이터 소스에서 tableView:writeRowsWithINdexes:toPasteboard: 메소드를 구현해서 드래그 동작의 시작을 제어한다.
  3. 데이터 소스에서 tableView:validateDrop:proposedRow:proposedDropOperation: 메소드를 호출하여 드랍할 장소를 확인validate한다.
  4. 데이터 소스에서 tableView:acceptDrop:row:dropOperation: 메소드를 구현해서 드랍된 데이터를 처리한다.


데이터 소스 오브젝트에서 델리게이트 메소드를 구현하는 것은 NSTableView로 하여금 당신의 테이블이 드래그 앤 드랍을 지원할 것임을 알리는 게 되고, 드래그 또는 드랍 된 데이터를 이용해 무엇을 할 것인지를 알게 해 준다. 만약 데이터 소스에서 이들 델리게이트 메소드중 하나를 생략한다면, 테이블 뷰는 드랍된 데이터를 받아들이지 못하거나 드래그를 시작하지 못할 것이다(생략하는 메소드에 따라 다르다). 테이블 뷰에서의 다른 드래그앤 드랍 비헤비어 커스터마이제이션도 있지만 필수적인 것은 아니다.

이어지는 섹션에서는 기본적인 델리게이트 메소드들의 구현 법과 몇가지 특별한 커스터마이제이션에 대한 추가적인 정보를 제공한다. 드래그 앤 드랍이 동작하는 법에 대한 일반적인 정보를 알고 싶으면 Drag and Drop Programming Topics for Cocoa를 보라.

목차

[편집] 테이블 뷰 설정하기

테이블 뷰가 드래그 앤 드랍을 지원하도록 하는 첫번째 단계는 데이터 소스가 어떤 타입의 데이터를 이해하는 지를 알려주는 것이다. 이것은 registerForFraggedTypes: 메세지를 NSTableView오브젝트로 보내는 것으로 할 수 있다. 이 메소드는 당신의 데이터 소스가 이해하는 페이스트보드 타입의 배열을 받아들인다.테이블 안에서만 드래그 앤 드랍 동작을 지원하길 원한다면, 간단하기 커스텀 타입을 정의할 수 있다. 몇가지 다른 소스로부터 오는 데이터를 지원한다면, 몇가지 다른 타입들을 지정해야 할 것이다.


다음의 예제는 도뷰멘트의 awakeFromNib 메소드의 샘플 구현을 보여준다. 데이블 안에서만 드래그 앤 드랍을 지원하려 한다면, 데이블 데이터를 위한 커스텀 타입을 그냥 등록하면 된다. 다른 타입의 데이터를 받아들이기를 원한다면, 배열에 적당한 페이스트보드 타입을 더해야 할 것이다.


Listing 1 테이블이 지원하는 데이터 타입을 등록하기

#define MyPrivateTableViewDataType @"MyPrivateTableViewDataType"
- (void)awakeFromNib
{
   [myTableView registerForDraggedTypes:
                       [NSArray arrayWithObject:MyPrivateTableViewDataType] ];

   // Other initialization...
}

[편집] 드래그 동작 시작하기

드래그 동작이 시작되면, 테이블은 tableView:writeRowsWithIndexes:toPasteboard: 메세지를 데이터 소스로 보낸다. 이 메소드에서 당신이 구현해야 할 부분은 지정된 열에 있는 데이터를 제공되는 페이스트보드에 넣고 YES를 리턴하는 것이다. 만약, 어떤 이유에서, 드래그 동작이 계속 진행되는 것을 원치 않는다면, 메소드는 NO를 리턴해야 한다.

Note : Mac OS X v1.4 이전에는 tableView:writeRows:toPasteboard: 메세지를 보내서 드래그를 초기화 했다. Mac OS X v10.4이후부터는, 이 메소드는 deprecated 되었다.

다음 예제는 tableView:writeRowsWithIndexes:topasteboard: 델리게이트 메소드의 구현을 간단히 보여준다. 이 구현에서, 드래그 앤 드롭은 테이블 내부로 제한되었다고 가정하므로, 간단히 드래그되는 열의 번호를 페이스트보드로 복사한다.

- (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard
{
   // Copy the row numbers to the pasteboard.
   NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
   [pboard declareTypes:[NSArray arrayWithObject:MyPrivateTableViewDataType] owner:self];
   [pboard setData:data forType:MyPrivateTableViewDataType];
   return YES;
}

페이스트보드에 넣어야 할 데이터가 많거나, 다중 데이터 형식이 가능하다면, 보증 promises을 통해 데이터를 늦게lazily제공해야 할 것이다. 그러기 위해서, 페이스트보드 오브젝트에게 실제 데이터를 제공할 필요없이 어떤 타입을 지원할 것인지를 알려주면 된다, 페이스트보드 오브젝트는 나중에 실제 데이터가 필요하게 될 때 당신에게 통지할 것이다. 페이스트보드 보증을 준수하는 방법에 대한 정보는 NSPasteboard 클래스의 pasteboard:provideDataForType: 델리게이트 메소드 (Objective-C)나 pasteboardProvideDataForType 델리게이트 (Java) 메소드의 설명을 보라.

Mac OS X v10.4에서, 데이터 소스 오브젝트에 파일-보증된 드래그 동작을 다루는 것에 대한 지원이 추가되었다. 테이블 뷰에서 이 기능을 사용하려면, 먼저 tableView:writeRowsWithIndexes:toPasteboard:메소드 안에서 NSFilePormisePboardType 타입을 이용해서 페이스트보드로 가게 되는 데이터를 보증해줘야 한다. 목적지가 드랍된 파일 정보를 받아들이면, NSTableView는 파일을 제공하기 위해 데이터 소스의 tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes:메소드 호출을 한다. 당신이 이 메소드가 파일과 파일 이름(패쓰 정보는 제외하고) 을 가지는 배열을 만들도록 구현해야 한다

NSTableView 클래스는 기본적으로 로컬 드래그만 지원한다. 테이블 열을 어플리케이션 바깥으로 드래그하려고 하면, 테이블 뷰의 draggingSourceOperationMaskForLocal:메소드가 NSDragOperationNone을 리턴한다. Mac OS X v10.4 이상에서 어플리케이션간 드래그를 지원하려면, 테이블 뷰의 setDraggingSourceOperationMask:forLocal: 메소드를 호출해야 한다. (당신의 코드가 Mac OS X v10.4 이전 버전을 지원한다면, NSTableView를 서브클래스해야 하며 draggingSourceOPerationMaskForLocal:을 적당한 값을 리턴하도록 서브클래스 해야 한다.)


[편집] 드래그 동작 확인하기

드래그 동작이 테이블 뷰로 들어오면, 테이블 뷰는 데이터 소스로 tabeView:validateDrop:proposedRow:proposedDropOperation: 메세지를 보낸다. 이 메소드가 구현되지 않았거나 NSDragOperationNone을 리턴한다면, 드래그 동작은 허락되지 않는다.

tabeView:validateDrop:proposedRow:proposedDropOperation: 메소드의 끝의 두개 매개변수는 지정된 열의 삽입점과 삽입 비헤비어( NSTableViewDropOn 또는 NSTableViewDropAbove)를 포함하고 있다. 당신의 델리게이트 메소드 구현에서 setDropRow:dropOperation: 메세지를 테이블 뷰로 보냄으로서 이 값들을 오버라이드할 수 있다.

- (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op
{
   // Add code here to validate the drop
   NSLog(@"validate Drop");
   return NSDragOperationEvery;
}


[편집] 드랍 받아들이기

확인된 드래그 동작이 테이블 뷰에 드랍되면, 테이블 뷰는 tableView:acceptDrop:row:dropOperation:메세지를 데이터 소스로 보낸다. 이 메소드에 대한 데이터 소스의 구현은 드래깅 페이스트보드로부터 데이터( acceptDrop 매개변수로부터 얻어진다)를 사용하는 것이고 테이블을 업데이트 하기 위해 다른 매개변수들을 사용하는 것이다. 예를 들어, 드래그 동작 타입(역시 acceptDrop 매개변수로부터 얻어진다)이 NSDragOPerationMove였고 드래그가 테이블로부터 시작되었다면, 해당 열을 예전 위치에서 새로운 위치로 움직이고 싶다는 것이다.

- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info
           row:(int)row dropOperation:(NSTableViewDropOperation)operation
{
   NSPasteboard* pboard = [info draggingPasteboard];
   NSData* rowData = [pboard dataForType:MyPrivateTableViewDataType];
   NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData];
   int dragRow = [rowIndexes firstIndex];

   // Move the specified row to its new location...
}


[편집] 드래그 비헤비어 커스터마이즈 하기

테이블 뷰 안에서 커서를 수직으로 드래그 하는 것은 일정 범위의 열을 선택하거나 하나 이상의 열을 다른 곳으로 드래그를 시도하는 것으로 해석될 수 있다. NSTableView의 기본 비헤비어는 수직 드래그를 드래그 동작의 시작으로 해석하지만 NSTableView의 setVerticalMotionCanBeginDrag:메소드를 이용해 이 비헤비어를 바꿀 수 있다. 수평방향의 드래그는 항상 드래그 동작의 시작이다.


드래그 동작이 시작되면, 테이블 뷰는 드래그된 열을 나타내기 위해 이미지를 만든다. 기본 이미지는 그 열의 복사본이다. 다른 이미지를 원한다면, NSTableView를 서브클래스하고 dragImageForRows:event:dragImageOffset: 메소드를 오버라이드해서 당신만의 NSImage 오브젝트를 리턴하도록 해야 한다.


[편집] 백그라운드 드래그

테이블 뷰와 아웃라인 뷰는 어플리케이션이 백그라운드 상태일 때도 구성요소를 드래그 할 수 있게 한다. 이는 row/item 기반의 드래깅 API들을 사용하는 클라이언트 에게만 영향을 미친다. 그런 테이블로부터 드래그하는 것은 NSTableView의 드래깅 구현과 동일하다. 어플리케이션이 액티브 상태가 아닐 때 사용자가 테이블을 클릭하고 드래그 하면, 드래그 동작이 초기화된다. 사용자가 테이블을 그냥 클릭한다면, 당신의 어플리케이션은 액티브 상태가 될 것이고 현재 선택에는 아무런 변경이 없을 것이다.