9.2.2 接收拖動項(xiàng)目
一個控件能否接收拖動項(xiàng)目是由該控件的OnDragOver事件決定的。在TabSet拖動中,主要是利用鼠標(biāo)的位置進(jìn)行判斷。
procedure TForm1.TabSet1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
var
DropPos: Integer;
begin
if Source = TabSet1 then
begin
DropPos := TabSet1.ItemAtPos(Point(X, Y));
Accept := (DropPos > -1) and (DropPos <> TabSet1.TabIndex) and
(DropPos < TabSet1.Tabs.Count);
end;
else
Accept := False;
end;
9.2.3 放下拖動項(xiàng)目
當(dāng)OnDragOver事件處理過程返回的Accept為True且項(xiàng)目被放下時(shí),由OnDragDrop事件處理過程來完成拖動放下后的響應(yīng)。在TabSet拖放實(shí)例中是改變標(biāo)簽的位置。
procedure TForm1.TabSet1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
OldPos: Integer;
NewPos: Integer;
begin
if Source = TabSet1 then
begin
OldPos := TabSet1.TabIndex;
NewPos := TabSet1.ItemAtPos(Point(X, Y));
if (NewPos > -1) and (NewPos <> OldPos) then
TabSet1.Tabs.Move(OldPos, NewPos);
end;
end;
9.2.4 結(jié)束拖動操作
結(jié)束拖動操作的方式有兩種:或者是用戶釋放了鼠標(biāo)鍵或者是程序用EndDrag方法強(qiáng)行中止拖動。結(jié)束拖動操作的后果有兩種:放下被接受或放下被忽略。
拖動操作結(jié)束后源控件都要收到一條消息響應(yīng)拖動結(jié)束事件OnEndDrag。
9.3 拖放應(yīng)用實(shí)例:文件管理器的拖放支持
在第六章最后開發(fā)的文件管理器應(yīng)用實(shí)例,雖然功能上已初具規(guī)模,但在操作上與Windows的文件管理器相比還有很大不足。其中最大的缺陷是它不支持文件的拖放移動和拖放拷貝。在這一章結(jié)束的時(shí)候,我們可以來彌補(bǔ)這一缺陷了。
文件拖放移動指的是當(dāng)用戶把一個文件拖動到目錄樹下的某一目錄并放下時(shí),文件將自動移動到該目錄中;文件拖放拷貝指的是當(dāng)用戶把一個文件拖動到某個驅(qū)動器標(biāo)簽上并放下時(shí),文件將自動拷貝到該驅(qū)動器的當(dāng)前目錄下。作為源控件的文件列表框和作為目標(biāo)控件的目錄樹、驅(qū)動器標(biāo)簽可以位于不同的子窗口。驅(qū)動器的當(dāng)前目錄是任一子窗口的最新操作結(jié)果,而不論這一子窗口與拖動源、拖動目標(biāo)是否有關(guān)系。
為了實(shí)現(xiàn)上述功能,有兩個問題必須首先解決:
1.如何記錄每一驅(qū)動器的當(dāng)前目錄?
為此我們定義了一個全局變量:
var
CurentDirList: Array[0...25] of string[70];
在DirectoryOutline的OnChange事件中:
procedure TFMForm.DirectoryOutlineChange(Sender: TObject);
begin
CreateCaption;
FileList.clear;
FileList.Directory := DirectoryOutline.Directory;
FileList.Update;
CurrentDirList[DriveTabSet.TabIndex] := DirectoryOutline.Directory;
FileManager.DirectoryPanel.Caption := DirectoryOutline.Directory;
end;
由于DriveTabSet在響應(yīng)OnDragDrop事件前先響應(yīng)OnClick事件,并由該事件激發(fā)DirectoryOutline的Onchange事件,因而可保證在任何時(shí)候OnDragDrop事件中用到的CurrentDirList數(shù)組項(xiàng)不為空字符串。
2.如何保證移動、拷貝與子窗口的無關(guān)性?
在這里一個關(guān)鍵問題是我們判斷源控件時(shí)是用is操作符進(jìn)行類型檢查:
If Source is TFileList then
…
如果我們用下面的語句:
If Source = FileList then
…
則移動、拷貝操作將限制在本子窗口范圍內(nèi)。
當(dāng)解決了上述問題后我們的工作就只是遵循拖放的一般開發(fā)步驟,按步就班來完成了。
1.FileList開始拖動操作
procedure TFMForm.FileListMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
with Sender as TFileListBox do
begin
if ItemAtPos(Point(X, Y), True) >= 0 then
BeginDrag(False);
end;
end;
ItemAtPos用來檢查當(dāng)前是否有文件存在。而BeginDrag方法傳遞參數(shù)False, 允許FileList單獨(dú)處理鼠標(biāo)事件而并不開始拖動。事實(shí)上這種情況是大量存在的。
2.DirectoryOutline、DriveTabSet決定是否能接受拖動的就地放下。
procedure TFMForm.DirectoryOutlineDragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
begin
if Source is TFileListBox then
Accept := True;
end;
procedure TFMForm.DriveTabSetDragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
var
PropPos: Integer;
begin
if Source is TFileListBox then
with DriveTabSet do
begin
PropPos := ItemAtPos(Point(X,Y));
Accept := (PropPos > -1) and (PropPos < Tabs.Count);
end;
end;
DirectoryOutline是無條件的接受,而DriveTabSet需檢查是否是合法的標(biāo)簽。
3.拖動放下的響應(yīng)
DirectoryOutline的拖動放下用于實(shí)現(xiàn)文件移動功能。程序中調(diào)用ConfirmChange事件處理過程,目標(biāo)路徑由DirctoryOutline.Items[GetItem(X,Y)].FullPath來得到。
procedure TFMForm.DirectoryOutlineDragDrop(Sender, Source: TObject; X,
Y: Integer);
begin
if Source is TFileListBox then
with DirectoryOutline do
begin
ConfirmChange('Move',FileList.FileName, Items[GetItem(X, Y)].FullPath);
end;
end;
DriveTabSet的拖動放下用于實(shí)現(xiàn)文件拷貝功能。程序中把當(dāng)前位置轉(zhuǎn)化為相應(yīng)的驅(qū)動器號,目標(biāo)路徑由CurrentDirList[DriveTabSet.TabIndex]獲得。
procedure TFMForm.DriveTabSetDragDrop(Sender, Source: TObject; X,Y: Integer);
var
APoint: TPoint;
begin
APoint.X := X; APoint.Y := Y;
DriveTabSet.TabIndex := DriveTabSet.ItemAtPos(APoint);
if Source is TFileListBox then
with DriveTabSet do
begin
if CurrentDirList[TabIndex] <> '' then
ConfirmChange('Copy',TheFilename,CurrentDirList[TabIndex]);
end;
end;
4.FileList響應(yīng)拖動結(jié)束,更新文件列表
procedure TFMForm.FileListEndDrag(Sender, Target: TObject; X, Y: Integer);
begin
if Target <> nil then FileList.Update;
end;
到目前為止,我們的文件管理器功能已足夠強(qiáng)大。 不過還有許多問題值得讀者去進(jìn)一步探討,如:
1.文件與應(yīng)用程序關(guān)聯(lián)的建立;
2.在文件列表框中顯示更多的文件信息;
3.文件列表框中的文件按后綴各排序等。
文件管理器是一個真正的綜合例程,對它的鉆研會使您更進(jìn)一步模到Delphi編程的精髓。
相關(guān)推薦:2010年9月計(jì)算機(jī)等級考試試題及答案解析專題北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |