用鼠标拖动listbox的items?(100分)

  • 主题发起人 主题发起人 TourAn
  • 开始时间 开始时间
T

TourAn

Unregistered / Unconfirmed
GUEST, unregistred user!
大侠们,谁知道在listbox中用鼠标拖动items的思路?
告急!!
 
是两个LISTBOX中的ITEMS的拖动吗?这是很典型的例子,先把要使用(拖操作)的LISTBOX的DRAGMODE设成dmAutomatic,
然后剩下的工作就不多了,然后在目标LISTBOX(放操作)的DragOver事件中将ACCEPT参数设为TRUE(最好判断一下拖放源)。这样才能允许对象在目标LISTBOX中放下。然后将要处理的一些代码写在目标LISTBOX的DragDrop事件中。
这样整个操作就完成了。当然也可以手工控制拖放操作:将LISTBOX的DRAGMODE设成dmManual,然后在源LISTBOX(拖操作)的MOUSEDOWN事件中写下:LISTBOX1.BEGINDRAG(TRUE),参数设为TRUE,FALSE是控制鼠标指针的变化时限,准确说是控制拖放操作的开始。
给你个例子如下:(两个Tlistbox名叫:lbx1,lbx2)
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
lbx1: TListBox;
lbx2: TListBox;
procedure lbx2DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure lbx2DragDrop(Sender, Source: TObject; X, Y: Integer);
procedure lbx1DragDrop(Sender, Source: TObject; X, Y: Integer);
procedure lbx1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.lbx2DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
if source=lbx1 then //如果源对象是LBX1
accept:=true;
end;

procedure TForm1.lbx1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
if source=lbx2 then //如果源对象是LBX2
accept:=true;
end;


procedure TForm1.lbx2DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
lbx2.Items.Add(lbx1.Items.Strings[lbx1.ItemIndex]); //实现拖放操作的结果,ITEM的增减
lbx1.Items.Delete(lbx1.ItemIndex);
end;

procedure TForm1.lbx1DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
lbx1.Items.Add(lbx2.Items.Strings[lbx2.ItemIndex]); //实现拖放操作的结果,ITEM的增减
lbx2.Items.Delete(lbx2.ItemIndex);
end;


procedure TForm1.FormCreate(Sender: TObject);
var
i:integer;
begin
//给两个LISTBOX加上几个条目以供演示
for i:=0 to 5 do
begin
lbx1.Items.Add(inttostr(i));
lbx2.Items.Add(inttostr(i));
end;
end;

end.
 
listbox2.items:=listbox1.items;
listbox2.items.delete;
 
用控件的拖放事件控制.
 
sorry,我的意思是在一个Listbox中,如果用户想把两个item换个位置,
直接用鼠标拖拉实现。
 
我知道了,你说清楚嘛,一个其实也差不多,只不过有处理一下而已。
你要做的就是先把这个LISTBOX的DRAGMODE设成dmAutomatic,然后在两个事件中写代码:
(重复的我就不帖了)
procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
if source=listbox1 then
accept:=true;
end;

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
tempstr:string;
P_move:Tpoint;
begin
{通过坐标获得ITEM}
P_move.x:=x;
p_move.y:=y;
if (listbox1.itemindex<>-1) and (listbox1.ItemAtPos(P_move,true)<>-1) then
begin //互换ITEM
tempstr:=listbox1.Items.Strings[listbox1.itemindex];
listbox1.Items.Strings[listbox1.itemindex]:=listbox1.items.Strings[listbox1.ItemAtPos(P_move,true)];
listbox1.items.Strings[listbox1.ItemAtPos(P_move,true)]:=tempstr;
end;
end;
我试过了,没有问题的
 
zyg_zm,首先谢谢你的回答,我还有一个问题,就是在拖拉的时候鼠标变成手的形状,
我试了几次都不成功,望赐教!

和我联系OICQ : 28261363
 
这个问题u不应该不知道吧。LISTBOX有个属性:dragcursor,把它设成你想要的鼠标指针就可以呀,
如要变成手形就设成crhandpoint,或者在FORMCREATE事件里加上:listbox1.dragcursor:=crhandpoint;
其它许多VCL构件也一样有这个属性啊
 
zyg_zm:
分已经给你加上了,还有个小问题,
1。就是托动的时候,如果经过另一个item时,那个item如何显示为选中状态
2。如果托动时当鼠标在listbox的外面时放开则delete托动的item,应如何写

祝 好运!
 
第一个问题我昨天也考虑过,让它显示为选中状态是不行的,因为这样LISTBOX的ITEMINDEX就会乱掉,后面的操作就会出问题
我想了一下,给它画个框框也可以,只要可以识别就行。

第二个问题:
只需在LISTBOX的ENDDRAG事件中判断一下就可以了,不过还得记住要把你认为“listbox的外面”的对象的
DRAGOVER事件中加上ACCEPT:=TRUE,让它可以接受LISTBOX拖出来的动作。比如这个LISTBOX脱出去就是FORM了


两个问题加起来代码可以这样写:(另外上次写的互换ITEM的那几句代码我发现LISTBOX有这样一个方法是专门互换ITEM,也一并改过来了)
因为要在上次写的事件中添加代码,所以我把修改后的这几个事件都贴上了:
有个很重要的别忘了:要声明一个窗体级以上的变量oldrect:Trect;,可以加在private下面

procedure TForm1.FormDragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
//这是让FORM接受从LISTBOX里拖出的动作,注意要个FORM留出空间在外面
if source=listbox1 then
accept:=true;
end;

procedure TForm1.ListBox1EndDrag(Sender, Target: TObject; X, Y: Integer);
begin
if (target<>nil)and(target.ClassName<>sender.ClassName) then
listbox1.Items.Delete(listbox1.itemindex);
if target=nil then
listbox1.Canvas.DrawFocusRect(oldrect);
oldrect.Bottom:=0; //拖放完之后把矩形变量清空
end;

procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
var
mypos:Tpoint;
begin
if source=listbox1 then
accept:=true;
mypos.x:=x;
mypos.y:=y;
if listbox1.ItemAtPos(mypos,true)<>-1 then
begin
listbox1.Canvas.DrawFocusRect(oldrect); //通过‘异或’去掉上次的框框
listbox1.Canvas.DrawFocusRect(listbox1.ItemRect(listbox1.ItemAtPos(mypos,true)));//画上本次的框框
oldrect:=listbox1.ItemRect(listbox1.ItemAtPos(mypos,true));
end;

end;

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
P_move:Tpoint;
begin
{通过坐标获得ITEM}
P_move.x:=x;
p_move.y:=y;

if (listbox1.itemindex<>-1) and (listbox1.ItemAtPos(P_move,true)<>-1) then
//这一句可以替换上次那几句
listbox1.Items.Exchange(listbox1.itemindex,listbox1.ItemAtPos(P_move,true));//互换ITEM

//下面一句也是拖放不成功的时候要去掉最后画的那个FOCUS框
if listbox1.ItemAtPos(P_move,true)=-1 then
listbox1.Canvas.DrawFocusRect(oldrect);
end;
这些我都试过的,没问题。

好了,问题回答完了,该给分了,其实我也很水的,不过你比我更水。

 
后退
顶部