鱼C论坛

 找回密码
 立即注册
查看: 2480|回复: 2

[技术交流] Delphi实现控件的拖放功能

[复制链接]
发表于 2013-3-16 20:15:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x

DELPHI控件的拖放支持


拖放操作中控件可以分为源控件和目标控件两类。绝大部分控件既可以作为源控件也可以作为目标控件。但也有一部分控件只能支持其中的一种。

拖放属性

拖放属性主要有两个:

● DragMode : 拖动模式

● DragCursor : 拖动光标

它们都是在拖放的源控件中设置。DragMode控制用户在运行时间内当在控件上按下鼠标时控件如何反应。如果DragMode置为dmAutomatic,那么当用户在控件上按下鼠标时拖动自动开始;如果DragMode置为dmManual(这是缺省值),则将通过处理鼠标事件来判断一个拖动是否可以开始。

DragCursor用于选择拖动时显示的光标,缺省值是CrDrag,一般不要去修改它。在程序设计过程中通用的界面规范应该得到开发者的尊重。但有时候为了特定的目的,开发者也可以把自己设计的光标赋给DragCursor。

拖放事件

拖放事件主要有三个:

●OnDragOver:拖动经过时激发

●OnDragDrop:拖动放下时激发

●OnEndDrop :拖动结束时激发

前两个事件由目标控件响应,后一个事件由源控件响应。

OnDragOver事件最主要的功能是确定当用户就地放下拖动时控件是否可以接受。它的参数包括:

Source : TObject;  {源控件}

X,Y : Integer; {光标位置}

State : TDragState; {拖动状态}

var Accept : Boolean {能否接受}

TDragState是一个枚举类型,表示拖放项目与目标控件的关系。

type

TDragState = (dsDragEnter, dsDragLeave, dsDragMove);

不同取值的意义如下表:

DragState 的取值与意义

━━━━━━━━━━━━━━━━━━━━━━━━━━━

取 值 意 义

───────────────────────────

dsDragEnter 拖动对象进入一个允许拖动对象放下

的控件中。为缺省状态。

dsDragLeave 拖动对象离开一个允许拖动对象放下

的控件。

dsDragMove 拖动对象在一个允许拖动对象放下的

控件内移动。

━━━━━━━━━━━━━━━━━━━━━━━━━━━

用户可以利用提供的参数来确定放下的拖动是否可被接受,如:

● 判断源控件类型:

Accept := Source is TLabel;

● 判断源控件对象:

Accept := (Source = TabSet1);

● 判断光标位置:

见(9.2),(9.3)中的例程。

● 判断拖动状态:
If (Source is TLabel) and (State = dsDragMove) then 
begin 
source.DragIcon := ' New.Ico '; 
Accept := True; end else Accept := False; 

当Accept=True时,目标控件可以响应OnDragDrop事件,用于确定拖动被放下后程序如何进行处理。

OnDragDrop事件处理过程的参数包括源控件和光标位置。这些信息可用于处理方式的确定。

OnEndDrag事件是在拖动操作结束后由源控件来进行响应的,用于源控件进行相应的处理。拖动操作结束既包括拖动放下被接受,也包括用户在一个不能接受放下的控件上释放了鼠标。该事件处理过程的参数包括目标控件(Target)和放下位置的坐标。如果Target=nil, 表示拖动项目没有被任何控件接受。

如果操作成功,则文件列表框应更新显示内容。下面这段程序用于实现这一功能。
procedure TFMForm.FileListEndDrag(Sender, Target: TObject; X, Y: Integer); 
begin
if Target <> nil then FileList.Update; 
end; 
除以上介绍的三个事件外,还有一个事件OnMouseDown 也常用于拖放操作的响应。OnMouseDown虽然不是一个专门的拖放事件,但在人工模式下拖动的开始是在这一事件的处理过程中实现的。

拖放方法

拖放方法有三个:

●BeginDrag : 人工方式下开始一个拖动

●EndDrag : 结束一个拖动

●Dragging : 判断一个控件是否正被拖动

这三个方法都被源控件使用。

当DragMode置为dmManual时,拖动必须调用控件的BeginDrag方法才能开始。BeginDrag有一个布尔参数Immediate。如果输入参数为True,拖动立即开始,光标改变到DragCursor的设置。如果输入参数为False,直到用户将光标移动了一定的距离(5个象素点)后才改变光标,开始拖动。这就允许控件接受一个OnClick事件而并不开始拖动操作。

EndDrag方法中止一个对象的被拖动状态。它有一个布尔参数Drop。如果Drop设置为True,被拖动的对象在当前位置放下(能否被接受由目标控件决定);如果Drop设置为False,则拖动就地被取消。

下面一段程序表明当拖动进入一控制面板时拖动被取消。
procedure TForm1.Panel1DragOver(Sender, Source: TObject; X, Y: Integer; 
State: TDragState; var Accept: Boolean); 
begin 
Accept := False; if (Source is TLabel) and (State = dsDragEnter) then 
(Source as TLabel).EndDrag(False); 
end; 
Draging方法判断一个控件是否正被拖动。在下面的例子中当用户拖动不同的检查框时窗口改变为不同的颜色
procedure TForm1.FormActivate(Sender: TObject); 
begin 
CheckBox1.DragMode := dmAutomatic; 
CheckBox2.DragMode := dmAutomatic; CheckBox3.DragMode := dmAutomatic; 
end; 
procedure TForm1.FormDragOver(Sender, Source: TObject; X, Y: Integer; 
State: TDragState; var Accept: Boolean); 
begin 
if CheckBox1.Dragging then Color := clAqua; 
if CheckBox2.Dragging then Color := clYellow; 
if CheckBox3.Dragging then Color := clLime; 
end; 
开发拖放功能的一般步骤

拖放作为Windows提供的一种方便操作对象的功能,在Delphi中可以很容易地开发出来。根据拖放操作的过程可以把开发步骤划分为四个阶段,即:

● 开始拖动操作

● 接收拖动项目

● 放下拖动项目

● 终止拖动操作

在介绍过程中我们将结合一个TabSet(标签集)的拖放操作实例。界面设计如图。在运行时当用户把一个标签拖动到另一个标签的位置时,该标签将移动到该位置并引起标签集的重新布置。

开始拖动操作

当拖动模式(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; 
接收拖动项目

一个控件能否接收拖动项目是由该控件的OnDragOver事件决定的。在TabSet拖动中,主要是利用鼠标的位置进行判断。
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;





放下拖动项目

当OnDragOver事件处理过程返回的Accept为True且项目被放下时,由OnDragDrop事件处理过程来完成拖动放下后的响应。在TabSet拖放实例中是改变标签的位置。

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;



结束拖动操作

结束拖动操作的方式有两种:或者是用户释放了鼠标键或者是程序用EndDrag方法强行中止拖动。结束拖动操作的后果有两种:放下被接受或放下被忽略。

拖动操作结束后源控件都要收到一条消息响应拖动结束事件OnEndDrag
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2013-3-29 19:11:41 | 显示全部楼层
沙发,多谢分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2015-2-1 16:43:12 | 显示全部楼层
支持楼主发扬Delphi
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-23 04:47

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表