본문 바로가기
Delphi Tip/+Tip

Drag and Drop(끌어서 놓기)

by MonoSoft 2023. 7. 26.
728x90
반응형

Drag and Drop

 

728x90

 

 

 

 

Drag and Drop(끌어서 놓기)

 

사용자가 마우스로 객체를 선택하여 다른 위치로 끌어서 놓는

인터랙션 기술을 의미합니다.

 

이를 통해 사용자는 애플리케이션 내의 요소를 직접 이동하거나 복사할 수 있습니다.

 

 

드래깅의 시작

모든 컨트롤에는 사용자가 컴퍼넌트의 드래깅을 시작했을 때

그것의 응답을 처리하는 방법을 지정하는 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 프로퍼티를 디자인 타임에서 변경한다.

필요하다면 커서 리소스를 만들 수도 있다.

 

델파이에서 Drag and Drop을 구현하는 과정은 간단한데,

다음과 같은 주요 단계로 이루어집니다

 

 

1.드래그 앤 드롭 대상 설정

드래그 앤 드롭을 지원할 컨트롤(예: TPanel, TImage 등)을 선택합니다.

사용자가 이 컨트롤을 드래그하여 다른 위치로 이동하고자 할 때 이 컨트롤이 대상이 됩니다.

 

2.드래그 가능하도록 설정

대상 컨트롤의 속성을 설정하여 드래그 앤 드롭이 가능하도록 만듭니다.

이는 컨트롤의 DragMode 속성을 설정하여 수행합니다.

일반적으로 DragMode 속성을 dmAutomatic로 설정하여 드래그 앤 드롭을 활성화합니다.

 

3.이벤트 처리

델파이는 Drag and Drop 작업에 관련된 이벤트를 제공합니다.

대표적으로 OnDragOver, OnDragDrop, OnDragEnter, OnDragLeave 등의 이벤트가 있습니다.

 

이벤트 핸들러를 사용하여 드래그 앤 드롭 작업을 처리합니다.

 

간단한 예제로 TImage 컨트롤을 드래그 앤 드롭할 수 있도록 만드는 방법을 보여드리겠습니다.

 

TImage 컨트롤을 폼에 추가합니다.

 

이벤트 핸들러를 구현합니다

procedure TForm1.Image1DragDrop(Sender, Source: TObject; X, Y: Integer);

begin

  // 드롭이 발생한 위치(X, Y)에 이미지 컨트롤을 이동시킵니다.

  Image1.Left := X; Image1.Top := Y;

end;

 

procedure TForm1.Image1DragOver(Sender, Source: TObject; X, Y: Integer;

State: TDragState; var Accept: Boolean);

begin

  // 드롭이 가능한 상태로 변경합니다.

  Accept := True;

end;

 

대상 컨트롤의 DragMode 속성을 dmAutomatic로 설정합니다.

 

폼 생성자나 OnCreate 이벤트에서 다음 코드를 추가합니다

procedure TForm1.FormCreate(Sender: TObject);

begin

  Image1.DragMode := dmAutomatic;

end;

 

이제 실행하고 TImage 컨트롤을 드래그하여 폼 내에서 원하는

위치로 끌어서 놓을 수 있게 됩니다.

 

위 예제는 간단한 드래그 앤 드롭 동작을 보여주기 위한 것이며,

실제 애플리케이션에서는 더 복잡한 동작과 데이터

이동을 구현할 수 있습니다.

 

728x90
반응형

댓글