在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并设置该项目为高亮。

 

很简单,不是吗?

 

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值