一、拖放的要素
鼠標拖放的二個操作對象:源對象(source)和目標對象(Target)。鼠標左鍵在源控件(source)上按下拖動,直至可接收目標控件(Target)上放下,即完成一次拖放操作。有四個事件拖放事件依序發生:OnStartDrag,OnDragOver,OnDragDrop,OnEndDrag。按事件名的字義理解這四個事件就對了,OnDragOver和OnDragDrop由目標對象(Target)激發,OnStartDrag和OnEndDrag由源對象(source)激發,下面簡單的講解下四個事件。
注:下文中的拖放對象,指在拖放狀態的鼠標,而非TDragObject對象。
二、事件流程
1、OnStartDrag(Sender: TObject; var DragObject: TDragObject);
大多數的組件具有DragMode屬性, 表示拖放操作的開始方式。DragMode 屬性的默認值為dmManual,也就是要在源對象的OnMouseDown 事件的處理過程中調用BeginDrag過程才開始拖放操作,因此屬性值為dmManual時,不需要處理OnStartDrag事件,而代之以OnMouseDown事件(當然此情形下OnStartDrag事件還會發生)。如果將DragMode 屬性設置為dmAutomatic,則鼠標左鍵在源對象上按下後就自動開始拖放操作,這時就可在OnStartDrag事件中進行處理。
procedure TControl.BeginDrag(Immediate: Boolean; Threshold: Integer=-1);
Immediate參數為真時表示按下鼠標立即啟動拖放操作;
Threshold:鼠標拖動偏移量為多少時啟動操作,第一個參數為真時無意義,一般不用理會,默認偏移量為5。
TDragObject對象一般很少用到,大多情形是供VCL內部的使用,有興趣或需要的可看VCL源碼。
2、OnDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
拖放鼠標經過目標對象(Target)時,由其激發。
事件參數:Sender拖放目標組件;Source源對象;X,Y鼠標坐標;
State拖放操作狀態:枚舉類型,有三個值,dsDragEnter剛進入目標組件, dsDragMove移動, dsDragLeave離開。
注意:一般不需要處理State參數。這裡有一個陷阱,當State=dsDragLeave時,Accept設值為否,即不接收拖放操作放下,將阻斷拖放操作,使後續事件都不能激發,由此判斷當鼠標按鍵釋放時,即拖放對象放下時State=dsDragLeave。演示代碼:
[delphi]
procedure TMyForm.mmoNoteDragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept := State <> dsDragLeave;
end;
procedure TMyForm.mmoNoteDragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept := State <> dsDragLeave;
end;[不知道這算不算VCL的一個BUG,但絕對是一個陷阱!!]
3、OnDragDrop(Sender, Source: TObject; X, Y: Integer);
OnEndDrag(Sender, Target: TObject; X, Y: Integer);
拖放放下事件OnDragDrop和拖放結束事件OnEndDrag同時發生,所不同的事件激發對象不一樣,前者是目標對象(Target),後者是源對象(Source)。通常情況下只需要處理二事件其中之一。
結束:看到這裡,基本上你就已經掌握了VCL的拖放編程~當然你得動手一試才算。如果遇到問題,那跟蹤調試一番應該很快能解決。這是提高編程水平的不二之法。