在CListCtrl之间及CListCtrl内部实现拖放

 

在CListCtrl之间及CListCtrl内部实现拖放

 

源码下载

参考我的资源里.上传后地址还没出来,等出来后再放上

 

介绍

本篇文章将介绍如何实现使用拖放方法从一个CListCtrl移动项目到另一个CListCtrl,同样也显示了如何使用拖放

从在CListCtrl内部实现改变项目顺序。这是我很早就想学的一些东西,并且同样在Code Project看到很多关于这个的问题。

特别是如何在一个CListCtrl内部重排项目顺序。我希望这篇文章能回答那些问题。我很肯定还有其他方法可实现同样功能,

也许那些方法更好用,但我这个对我来说已经工作的很好了。

 

首先,我要先说明,网上的微软知识库有一个很好的工程例子(http://support.microsoft.com/default.aspx?scid=kb;en-us;Q148738),

它给我很大帮助。我的代码跟那个很像。那个例子说明了从CListView拖放到CTreeView。那跟我现在要介绍的有一些细微差别。不过微软

知识库的例子只给了代码,没有说明文字,尽管它有很好的注释。

 

同样,这篇文章假设你已经至少很熟悉如何使用CListCtrl了。在Code Project有两篇很好的文章介绍了如何使用CListCtrl和CHeadCtrl控件。

并且Chris Maunder写了一篇非常好的文章介绍使用CListCtrl的回调。如果你没有阅读过他们,请赶快阅读下哦。

 

概要:

Drag 和 Drop操作至少涉及以下操作步骤:

1.你处理拖放操作的通知消息(即用户点了鼠标左键,并开始拖动)

2.你必须跟踪鼠标的移动,那时用户在拖动项目。

3.最后,当鼠标按键释放时,实现实际的复制和移动动作。

 

 

 

对话框需要添加的成员变量:

在我们完成拖放操作时需要保存一些信息,所以我们给对话框添加一些成员变量,他们只需要实现为protected成员,因为只需要内部使用。

m_nDragIndex 是我们将要移动的CListCtrl项目索引

 

m_nDropIndex 是CListCtrl中鼠标将要停放的索引

 

m_pDragWnd 和 m_pDropWnd 是拖放涉及的CListCtrl窗口指针

 

m_bDragging 标识我们正在拖放操作. 在MouseMove函数中使用以便使我们知道何时跟踪

 

m_pDragImage 是一个CImageList对象指针. MFC使得创建和管理拖放对象的图片变得非常容易

 

最后需要一个数据结构保存从一个列表拖到另一个列表 (或在同一个列表当中从一个项目到另一个项目)的信息.该结构如下:

 

这个结构包含一个LVITEM指针和一个字符串。我们使用LVITEM指针来实现CListCtrl的GetItem,InsertItem,及其他操作。

CString保存CListCtrl的第二列的数据。如过你有超过两列数据,只要添加更多的字符串。

 

 

捕获Drag操作的通知信息:

使用向导添加处理LVN_BEGINDRAG消息的函数。顺便说下,如果你希望可以拖动多个控件,你需要在此消息为所有列表作处理。

首先,我们希望保存我们将拖动的项目索引。所以把那值保存到一个成员变量。我们在稍后使用这个索引来获取相关信息。

m_nDragIndex = pNMListView->iItem;

 

然后我们创建一个我们要拖动的项目图片。在这里MFC帮了我们很多。

有两个方法来实现这部分,最简单的是让MFC来帮你处理繁琐的操作,正如第一个方法所示。第二个方法也只是稍微复杂。但他

要求你创建使用的图片资源。第二个代码代码片断显示了该方法。

 

第一个方法:

 

第二个方法:

 

 

最后,我们调用SetCapture。这样我们保证了我们的控件(CListCtrl)能够接收所有的鼠标消息。

即便用户把项目拖离控件,甚至对话框,我们仍能接收到通知消息。直到我们释放了Capture(我们在松开右键时)。

或者直到另一个窗口Caoture了鼠标。

 

 

 

 

跟踪拖动过程:

使用类向导(ClassWizard),添加一个处理WM_MOUSEMOVE消息的函数。

只有在m_bDragging标记设置为TRUE时,才开始处理逻辑。

 

 

下一节我们就实际处理在屏幕移动拖动图片

DragShowNolock(false)调用允许窗口平滑显示拖动图片。如果我们不调用这个,拖动图片有时会显示它经过的画面。

 

 

WindowFromPoint(pt)返回pt所在点的窗口。让我们知道鼠标指向哪里,他是否指向了CListCtrl窗口。

 

 

这节仅仅处理高亮显示我们拖动经过的CListCtrl项目

 

 

 

当我们移动鼠标的时候,我们需要保持跟踪我们拖动过什么窗口,这样当我们释放鼠标时我们知道把项目放到哪个控件上了。

所以我们把它保留到我们的成员变量。

         

 

IsKindOf(RUNTIME_CLASS(CListCtrl))是另一个常用函数,允许我们判断鼠标移动过的窗口是否是CListCtrl。这节处理鼠标移动过

的项目高亮显示。

 

 

 

 

完成拖放,处理放的动作:

我们在此几乎完成了所有动作。再次使用类向导,添加一个WM_LBUTTONUP消息的处理函数。这部分很短很精致。

和上面的OnMouseMove函数一样,我们仅仅处理和拖放相关的代码

 

不要忘记释放捕捉的鼠标。

 

 

当我们释放了物件,我们不再处理拖动处理。 

 

 

 

MFC再次给我们提供了函数组来处理拖动图片。不要忘记删除上边创建的(拖动开始时创建)那个图片。

 

 

 

跟我们在OnMouseMove函数中处理的那样,我们找出鼠标在哪,以及所处的窗口。然后我们检测是否是一个CListCtrl窗口。

如果是,我们处理实际的放动作。为了容易阅读。我让处理复制和移动的代码打包进DropItemOnList函数中(如下所示)

 

然后进入最后的步骤,实际的复制/移动代码的处理。

 

实际复制/移动代码:

你需要手工添加一个函数来处理实际的复制/移动代码。这个函数可以是protected成员,

 

 

 

以下是实际的函数:

 

 

我们简单的设置LVITEM结构同时用来获取拖放来源控件的信息,以及添加该信息进拖放目标控件。

如果你的CListCtrl控件包含图标,不要忘记改变"lvi.mask=LVIF_TEXT"所在行。

 

所以我们设置来LVITEM结构,然后使用GetItem(&lvi)来获取我们拖动的列表项目的信息。

但你将注意到这个不会获取第二列的信息。那时我们为什么需要lvItem结构,我们使用pItem->sCol2=pDragList->GetItemText(pItem->plvi->iItem, 1);

来获取那个信息。

 

当我们处理拖动多项选择时,我们在lvItem对象设置一个CList,我们处理拖动来源CListCtrl并获取所有选项信息。然后如果我们处理的是Move操作,

我们删除所有来源的选项,然后通过处理CList并添加每一个项目到CListCtrl。

 

正如我的样例程序所实现,我检测用户是否拖动项目到其他的CListCtrl还是在同一个CListCtrl。如果用户释放一个项目到其他的CListCtrl,然后我们会

复制项目到其它控件,如果,用户仅仅拖放到同一个控件的不同点,我们将移动项目到新的索引(这是如何实现用户给一个列表按拖动来排序)。一般来说,

如果用户移动同一个控件的项目,我们会在添加回原列表前删除原来项目(获取完项目的信息后)。我们必须先删除,因为如果我们先添加的话,索引将不一致。

并且在很多实例中我们不允许将信息写到已存在的项目中。试着思考我所说的意思。在我们添加信息回列表后删除该项目,拖动列表的项目并看看发生了什么。

(译者注:最后一句我也不知道说的啥,只能猜测,所以把原文抄上: Try it to see what I mean. Move the part where we delete the item to AFTER we have added the item to the list. Drag items around in the list and see what happens.)

 

最后,我们添加项目到CListCtrl并设置该项目为高亮。

 

很简单,不是吗?

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值