全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1763
推到 Plurk!
推到 Facebook!

Delphi拖放编程(2)

 
wnhoo
高階會員


發表:75
回覆:443
積分:198
註冊:2003-04-22

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-04-26 18:29:31 IP:61.155.xxx.xxx 未訂閱
Delphi拖放编程(2) 开发拖放功能的一般步骤拖放作为Windows提供的一种方便操作对象的功能,在Delphi中可以很容易地开发出来。根据拖放操作的过程可以把开发步骤划分为四个阶段,即: ● 开始拖动操作 ● 接收拖动项目 ● 放下拖动项目 ● 终止拖动操作在介绍过程中我们将结合一个TabSet(标签集)的拖放操作实例。在运行时当用户把一个标签拖动到另一个标签的位置时,该标签将移动到该位置并引起标签集的重新布置。 1.开始拖动操作当拖动模式(DragMode)设置为dmAutomatic时,用户在源控件上按下鼠标时拖动自动开始;当设置为dmManual时通过处理鼠标事件来决定拖动是否开始。如果想开始拖动调用BeginDrag方法。 在TabSet拖放中,我们用下面的MouseDown事件处理过程来开始一个标签的拖动。 首先判断按下的是否是左键,而后再判断项目是否合法。 procedure TForm1.TabSet1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer); var DragItem: Integer; begin if Button = mbLeft then begin DragItem := TabSet1.ItemAtPos(Point(X,Y)); if (DragItem > -1) and (DragItem < TabSet1.Tabs.Count) then TabSet1.BeginDrag(False); end; end; 2.接收拖动项目一个控件能否接收拖动项目是由该控件的OnDragOver事件决定的。在TabSet拖动中,主要是利用鼠标的位置进行判断。 procedure TForm1.TabSet1DragOver(Sender,Source: TObject; X,Y: Integer;State: TDragState; var Accept: Boolean); var DropPos: Integer; begin if Source = TabSet1then begin DropPos := TabSet1.ItemAtPos(Point(X,Y)); Accept := (DropPos > -1) and (DropPos <> TabSet1.TabIndex) and (DropPos < TabSet1.Tabs.Count); end; else Accept := False; end; 3.放下拖动项目当OnDragOver事件处理过程返回的Accept为True且项目被放下时,由OnDragDrop事件处理过程来完成拖动放下后的响应。在TabSet拖放实例中是改变标签的位置。 procedure TForm1.TabSet1DragDrop(Sender,Source: TObject; X,Y: Integer); var OldPos: Integer; NewPos: Integer; begin if Source = TabSet1then begin OldPos := TabSet1.TabIndex; NewPos := TabSet1.ItemAtPos(Point(X,Y)); if (NewPos > -1) and (NewPos <> OldPos) then TabSet1.Tabs.Move(OldPos NewPos); end; end; 4.结束拖动操作结束拖动操作的方式有两种:或者是用户释放了鼠标键或者是程序用EndDrag方法强行中止拖动。结束拖动操作的后果有两种:放下被接受或放下被忽略。 拖动操作结束后源控件都要收到一条消息响应拖动结束事件OnEndDrag。 拖放应用实例:文件管理器的拖放支持的应用实例,虽然功能上已初具规模,但在操作上与Windows的文件管理器相比还有很大不足。其中最大的缺陷是它不支持文件的拖放移动和拖放拷贝。在本篇结束的时候,我们来弥补这一缺陷了。 文件拖放移动指的是当用户把一个文件拖动到目录树下的某一目录并放下时,文件将自动移动到该目录中;文件拖放拷贝指的是当用户把一个文件拖动到某个驱动器标签上并放下时,文件将自动拷贝到该驱动器的当前目录下。作为源控件的文件列表框和作为目标控件的目录树、驱动器标签可以位于不同的子窗口。驱动器的当前目录是任一子窗口的最新操作结果,而不论这一子窗口与拖动源、拖动目标是否有关系。 为了实现上述功能,有两个问题必须首先解决: 1.如何记录每一驱动器的当前目录? 为此我们定义了一个全局变量: 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在响应OnDragDrop事件前先响应OnClick事件,并由该事件激发DirectoryOutline的Onchange事件,因而可保证在任何时候OnDragDrop事件中用到的CurrentDirList数组项不为空字符串。 2.如何保证移动、拷贝与子窗口的无关性? 在这里一个关键问题是我们判断源控件时是用is操作符进行类型检查: If Source is TFileList then …如果我们用下面的语句: If Source = FileList then …则移动、拷贝操作将限制在本子窗口范围内。 当解决了上述问我们的工作就只是遵循拖放的一般开发步骤,按步就班来完成了。 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用来检查当前是否有文件存在。而BeginDrag方法传递参数False 允许FileList单独处理鼠标事件而并不开始拖动。事实上这种情况是大量存在的。 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需检查是否是合法的标签。 3.拖动放下的响应DirectoryOutline的拖动放下用于实现文件移动功能。程序中调用ConfirmChange 事件处理过程,目标路径由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的拖动放下用于实现文件拷贝功能。程序中把当前位置转化为相应的驱动器号,目标路径由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响应拖动结束,更新文件列表 procedure TFMForm.FileListEndDrag(Sender,Target: TObject; X,Y: Integer); begin if Target <> nil then FileList.Update; end; 到目前为止,我们的文件管理器功能已足够强大。不过还有许多问题值得去进一步探讨,如: 1.文件与应用程序关联的建立; 2.在文件列表框中显示更多的文件信息; 3.文件列表框中的文件按后缀各排序等。 文件管理器是一个真正的综合例程,对它的钻研会使您更进一步模到Delphi编程的精髓。 风花雪月 e梦情缘
------
风花雪月 e梦情缘
wnhoo
高階會員


發表:75
回覆:443
積分:198
註冊:2003-04-22

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-04-26 20:47:24 IP:61.155.xxx.xxx 未訂閱
Delphi拖放编程(1) http://delphi.ktop.com.tw/topic.php?TOPIC_ID=29490 风花雪月 e梦情缘
------
风花雪月 e梦情缘
系統時間:2024-05-15 5:06:30
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!