Drag-Drop의 정리


                                                       글: 박후선(OSOLGIL)
                                           softech<골뱅이>ppp.kornet21.net

델파이 헬프와 별반 다를것이 없지만  그것만으로도 일반적인 드랙-드롭에 대한
내용을 파악하기에는 무리가 없는 것 같아 정리해 봅니다. 델파이 버전이  4까지
올라온 시점에서 그다지 이용되지 않던 해묵은, 그러나 지원되면 유용한  기능들
을 어플리케이션에 도입해 봅시다.

○ 드래깅의 시작

모든 컨트롤에는 사용자가 컴퍼넌트의 드래깅을 시작했을 때 그것의 응답을 처리
하는 방법을 지정하는  DragMode 프로퍼티가 있다. 만약 DragMode가 dmAutomatic
이라면 컨트롤 위에 커서를 놓고 마우스 버튼을 누르면 자동으로 드래깅이  시작
된다. DragMode를 dmAutomatic로 설정하면 하면 일반적인 마우스의 작동을  방해
할 수 있기 때문에 DragMode를 디폴트값인 dmManual로 처리하는 방법을 선호하는
사람들이 많다. dmManual 상태에서는 OnMouseDown 이벤트에서 수동으로 드래깅을
시작 시켜 줘야 한다.

컨트롤의  드래깅을  수동으로  시작시키려면,  BeginDrag  메쏘드를  호출한다.
BeginDrag 메쏘드는 Immediate라는  Boolean형 인자를 받는다.  만약 이  인자에
True를 주면  드래깅이 곧바로 시작된다. 이것은 DragMode를 dmAutomatic으로 주
었을 때와 유사한 동작이다. 반대로 False를 주면 사용자가 마우스 포인터를  약
간 움직이기 전에는 드래깅이 발생하지 않는다. 즉, BeginDrag(False)를 하면 마
우스의 클릭이 발생할 뿐 드래깅 작업은 일어나지 않는다. 수동으로 드래깅을 지
원하려면 이 방법이 좋다. 마우스의 기본적인 작동을 막지 않을 뿐 더러 드래깅
을 함께 지원할 수 있기 때문이다.

앞서 말했듯이, 수동으로 드래깅을 지원할  경우, OnMouseDown 이벤트 핸들러를
이용한다. 아래의 예는 왼쪽 버튼을 눌렀을 때만 BeginDrag을 호출하는 파일  리
스트 박스의 OnMouseDown 이벤트의 예이다.

procedure TFMForm.FileListBox1MouseDown(Sender: TObject;

 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 if Button = mbLeft then  { 왼쪽버튼을 눌렀을 때만 드랙시작 }
   with Sender as TFileListBox do  { Sender를 TFileListBox로 취급 }
     begin
       if ItemAtPos(Point(X, Y), True) >= 0 then {아이템이 이곳에 있는가?}
         BeginDrag(False);  { 있다면 드랙을 시작한다. }
   end;
end;

위의 코드로 드래깅이 시작되기는 했지만 아직 아무곳에도 해당 컨트롤을 드롭할
수 없다. 드롭을 위해서는 드롭을 받아들이는 컨트롤이 필요하다.

○ 드랙된 아이템을 받아들이기

사용자가 무엇인가를 컨트롤 위로 드랙  했을 때 컨트롤의 OnDragOver  이벤트가
발생한다. 이 이벤트를 통해 컨트롤이 해당 아이템을 받아들일 수 있는지, 즉 그
아이템이 드롭될 수 있는지를 지정한다. 만약 컨트롤이 해당 아이템을  받아들일
수 있다면 델파이는 마우스 포인터를 변경시킨다. OnDragOver 이벤트 핸들러에는
var 인자인 Accept가 주어진다. 만약 아이템이 해당 컨트롤에서 받아들여 질  수
있는 것이라면 이 값을 True로 주고 그렇지 않은 경우 False를 주면 된다.

OnDragOver 이벤트핸들러에서 Accept 인자를 True로 지정하면 어플리케이션에 해
당 아이템이 컨트롤에 받아들여질 수  있음을 알린다. 만약 사용자가 그  컨트롤
위에서 드롭을 하면 어플리케이션은 곧바로  해당 컨트롤에 드랙-드롭 이벤트를
발생시킨다. 반대로 Accept가 False인 경우 해당 컨트롤 위에서는 드롭이 발생하
지 않는다.

드랙-오버 이벤트는 드래깅의 원본 오브젝트와  마우스의 현재 위치등의 몇가지
인자를 가지고 있다. 여러분은 인자로 주어지는 이런 정보들을 토대로 해당 아이
템의 드롭을 받아들일 것인지 아닌지를 결정할 수 있다. 아래는 디렉토리 트리뷰
의 OnDragOver 이벤트 핸들러의 예로 Source가 파일리스트박스일 때만 드롭을 허
용한다.

procedure TFMForm.DirectoryOutline1DragOver(Sender, Source: TObject; X,

 Y: Integer; State: TDragState; var Accept: Boolean);
begin
 if Source is TFileListBox then
   Accept := True;
 else
   Accept := False;
end;

○ 아이템을 드롭하기

컨트롤이 드랙된 아이템을 받아들일 수 있다고 알려주는 것만으로는 드랙-드롭을
지원할 수 없다. 아이템의 드롭을 처리할 코드를 작성해야 한다. 컨트롤이  아이
템을 받아들일 수 있다면 마우스의 포인터 형태가 변해서 사용자에게 그것이  드
롭될 수 있음을 알려준다. 사용자가 드롭을 시키면 OnDragDrop 이벤트가  발생한
다. 드롭의 처리는 이 이벤트 핸들러 안에서 이루어진다. OnDragOver와 마찬가지
로 OnDragDrop에도 몇가지 중요한 인자들이 주어지는데 이것을 토대로 하여 드롭
처리에 필요한 각종 정보를 얻을 수 있으며 그것을 어떻게 처리해야  하는지등을
참고할 수 있다.

아래는 파일 리스트 박스로부터 발생한 드랙을 디렉토리 트리뷰에서 드롭하는 예
로 현재 열려진 디렉토리에 해당 파일을 옮긴다.

procedure TFMForm.DirectoryOutline1DragDrop(Sender, Source: TObject; X,

 Y: Integer);
begin
 if Source is TFileListBox then
   with DirectoryOutline1 do
     ConfirmChange('Move', FileList.FileName,
       Items[GetItem(X, Y)].FullPath);
end;

Source는 드랙된 컴퍼넌트이며 DragDrop에서 해당 컴퍼넌트와 관련된 처리를  하
기 위해서는 꼭 이용해야 되는 인자다.

○ 드랙 작용의 편집

드래깅 작용이 끝나면 그것이 드롭되던  되지 않던 델파이는 end-drag  이벤트를
드랙을 시작한 컨트롤에 전달한다. 따라서  자신에게서 드랙되어 나간 아이템에
대한 응답처리를 위해서는  자신의 OnEndDrag 이벤트  핸들러를 이용하면  된다.
OnEndDrag 이벤트에서 가장 중요한 인자로는  Target이 있다. 이 인자는  드롭을
받아들인 컨트롤을 가리킨다. 드롭이 받아들여지지 않았다면 이 값은 당연히 nil
이다. 또한 X, Y 인자를 통해 컨트롤의 어느 부분에 드롭 되었는가를 확인할 수
있다.

아래의 예는 파일리스트 박스가 자신에게서 드랙되어 나간 아이템의 드롭에 대한
마무리를 OnEndDrag에서 처리하는 예이다. 파일 목록을 재정렬하는 것이  아래예
의 목적이다. 파일이 옮겨진 상태이므로 Update를 호출해 목록에서 그  아이템을
사라지게 해야 한다.

procedure TFMForm.FileList1EndDrag(Sender, Target: TObject; X, Y: Integer);

begin
 if Target <> nil then FileList1.Update;
end;

○ TDragObject를 이용한 자신만의 드래깅

오브젝트의 드랙과 드롭 방법을 TDragObject를 이용해 기호에 맞는 것으로  변경
할 수   있다. 디폴트로  드랙-오버와 드랙-드롭   이벤트에는 드랙된  아이템의
Source와 그것을 받아들이는 컨트롤 위의 마우스 좌표가 주어진다.  TDragObject
를 상속 받아 그것의 가상  메쏘드들을 오버라이딩하여 추가적인 정보를  얻도록
구성할 수 있다. TDragObject를 이용하면 드랙의 Source는 TDragControl형의  컨
트롤 오브젝트가 아니다. TDragObject인 오브젝트 그 자체가 된다.

OnStartDrag 이벤트 핸들러를 통해 고유의 드랙 오브젝트를 생성할 수 있다.  이
때, 타겟의 OnDragOver 이벤트에서는 IsDragObject 공용함수를 이용해 드랙 드롭
을 받아들일지를 결정한다.

TDragObject는 보다 유동적인 드랙-드롭을 처리를 할 수 있는 방법이다.  보통의
경우, OnDragOver와 OnDragDrop 이벤트의 Source 인자는 드랙 작용을 시작한  컨
트롤이다. 만일 서로 다른 형태의 컨트롤들이 동일한 종류의 데이터를 이용해 드
랙을 시작하게 하고 싶다면 이 Source는 각 종류의 컨트롤을 모두 지원하는 형태
가 되어야 한다. 각각의 소스  컨트롤들이 OnStartDrag 이벤트에서 같은  형태의
드랙 오브젝트를 생성하는 경우, 드랙 오브젝트는 타겟이 그것을 어떻게  소스로
처리할 것인지를 알게하는 하는 것이 주 역할이 된다. OnDragOver와  OnDragDrop
이벤트 핸들러 내부에서는 IsDragObject 함수를 이용해 소스가 드랙  오브젝트인
지 아닌지를 알아낼 수 있다.

드랙 오브젝트는 메인이 되는 .EXE의 안에서와 동일하게 여러 .DLL들 사이에서도
드랙 될 수 있다. 여러분이 패키지를 이용하지 않으면서도 .EXE에서 이용되는 폼
과 .DLL에서 이용되는 폼사이에서 드랙-드롭이  이루어지게 하기를 원한다면 이
것이 매우 유용한 기능이 될 것이다.

TDragObject에 대한 개념만을 파악했다. 사실 이 것을 이용해 드랙-드롭을  지원
해야 하는 경우는 드물기 때문에 상세한 내용과 예제는 다음 기회로 미루기로 한
다.

○ 드랙마우스 포인터의 변경

델파이가 사용하는 드랙 작용에서 사용하는 마우스 포인터를 변경할 수 있다. 이
것을 위해 컴퍼넌트의 DragCursor 프로퍼티를 디자인 타임에서 변경한다. 필요하
다면 커서 리소스를 만들 수도 있다. 이 부분은 델파이 사용자라면 대부분 처리
할 수 있으리라 보고 내용을 생략한다.

신고
크리에이티브 커먼즈 라이선스
Creative Commons License

티스토리 툴바