在网上搜索很多关于拖动ClistCtrl中一项的文章,找到了一些,但却编译不了。有个例子不错,但总觉得不合适我的程序,于是自己下决心做一个,过程倒还挺顺利。现在拿出来和大家分享,希望对大家有所帮助。阿弥陀佛!^_^
一、先上个图片个给大家看一下效果吧。
二、源代码下载
DragListCtrl_VC6.zip (VC6下编译通过,支持unicode)
三、几点说明
1.本例子只能在CListCtrl的报告样式中应用,其它样式的不行。
2.为了简单方便和高效,我没有选择重绘ClistCtrl(其实是我不会,哈哈)。
3.自己写的CDragList最主要代码都集中在OnMouseMove()函数,本来不用那么复杂的,但有个问题增加了这个复杂性:
一开始,当程序拖动到最后一项时,不能放在最后一项的后面(或者是放在最前面一项)。我发现很多程序的拖动项都有类似的“毛病”,比如一些程序在自定义菜单项位置时或在一些树目录中移动文件,都有这样的问题。最后花了努力克服这个问题,但代码复杂了,方法也有点怪,但毕竟效果不错。相信代码还有改进的空间。诸位看客如果谁改进了,请给我一个副本,先感谢了。
4.当有滚动条时,拖到最下面或最上面时都会自动滚动滚动条(这个当然是必要的啦)
5.确定交换两项后,CDragList会向ListCtrl的父窗口发送WM_MOVEITEM消息
父窗口添加自定义消息函数并处理item的交换,更新ListCtrl
四、使用方法
1.把DragList.h 和 DragList.cpp 添加到你的工程里
并且在你自己的派生的ClistCtrl里包含头文件DragList.h
2.在你自己的派生的ClistCtrl的鼠标消息函数里添加以下代码
1. //鼠标按下:
2. void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
3. {
4. CListCtrl::OnLButtonDown(nFlags, point);
5. CDragList::BeginDrag(m_hWnd,point); //一定要放在OnLButtonDown(nFlags, point);后面
6. }
7. //鼠标弹起
8. void CMyListCtrl::OnLButtonUp(UINT nFlags, CPoint point)
9. {
10. CDragList::EndDrag(m_hWnd,point);
11. CListCtrl::OnLButtonUp(nFlags, point);
12. }
13. //鼠标移动
14. void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point)
15. {
16. if( CDragList::m_SelectItem!=SELECT_NONE && nFlags&MK_LBUTTON )
17. CDragList::Dragging(m_hWnd,point);
18.
19. CListCtrl::OnMouseMove(nFlags, point);
20. }
3.ListCtrl的父窗口添加自定义消息,处理交换item的消息
(1)对话框头文件里
// Generated message map functions |
(2)对话框源文件里
BEGIN_MESSAGE_MAP(CDemoDlg, CDialog) |
(3)在此添加移动一项后的处理代码
/**************************************************************************** //---------------------------步骤1.获取要移动的项的信息----------------------------------------- //获取要移动的项 //get the first column text //将item移到要插入的位置 //---------------------------步骤3.确定要移动的项的新索引位置----------------------------------------- return 0; |
DragList.h
1. #ifndef _DRAG_LIST_H_
2. #define _DRAG_LIST_H_
3.
4. #include "Resource.h"
5. #include <vector>
6. using namespace std;
7. #define SELECT_NONE -1
8. #define BUTTON_UP -1
9. #define WM_SWAPITEM WM_USER+435
10. class CDragList
11. {
12. private:
13. static vector <RECT> ItemRect;
14. static int m_ActiveItem;
15. static bool m_IsOut;
16. static bool m_IsInFilstPart;
17. static bool m_IsInSecondPart;
18. static POINT MouseDownPoint;
19. public:
20. static int m_SelectItem;
21. public:
22. static void BeginDrag(HWND ListWnd,POINT point) ;
23. static void EndDrag(HWND ListWnd,POINT point) ;
24. static void Dragging(HWND ListWnd,POINT point) ;
25. static void DrawLine(HWND hWnd,int BeginX,int BeginY,int EndX,int EndY);
26. };
27. #endif // #define _DRAG_LIST_H_
DragList.cpp
1. #include "stdafx.h"
2. #include "DragList.h"
3. vector <RECT> CDragList::ItemRect;
4. int CDragList::m_ActiveItem=SELECT_NONE;
5. bool CDragList::m_IsOut=true;
6. int CDragList::m_SelectItem=SELECT_NONE;
7. bool CDragList::m_IsInFilstPart=false;
8. bool CDragList::m_IsInSecondPart=false;
9. POINT CDragList::MouseDownPoint={-10,-10};
10.
11. void CDragList::BeginDrag(HWND ListWnd,POINT point)
12. {
13. ::SetCapture(ListWnd);
14.
15. //设置焦点
16. if (::GetFocus()!=ListWnd )
17. ::SetFocus(ListWnd);
18.
19. //enum to find out if select one
20. int count=(int)::SendMessage(ListWnd, LVM_GETITEMCOUNT, 0, 0);
21. int state;
22. for (int i=0;i<count;i++)
23. {
24. state=(int)::SendMessage(ListWnd, LVM_GETITEMSTATE, i,(LPARAM) LVIS_SELECTED);
25. if (state|LVIS_SELECTED==1)
26. {
27. m_SelectItem=i;
28. m_ActiveItem=i;
29. m_IsOut=true;
30. MouseDownPoint=point;
31. }
32. }
33. }
34. void CDragList::EndDrag(HWND ListWnd,POINT point)
35. {
36. if (m_ActiveItem!=SELECT_NONE )
37. {
38. ::InvalidateRect(ListWnd,&ItemRect[m_ActiveItem],false);
39. if ( m_ActiveItem!=m_SelectItem && m_SelectItem!=SELECT_NONE)
40. {
41. //最后的Item的处理
42. if (m_IsInSecondPart==true)
43. m_ActiveItem+=1;
44.
45. ::PostMessage(::GetParent(ListWnd),WM_SWAPITEM,m_SelectItem,m_ActiveItem);
46. }
47. }
48.
49. ::ReleaseCapture();
50. m_SelectItem=SELECT_NONE;
51. }
52. void CDragList::Dragging(HWND ListWnd,POINT point)
53. {
54. //当鼠标按下后没有移动就弹起时,ClistCtrl会发送一个click消息,
55. //并且会有一个WM_MOUSEMOVE的消息(却没有WM_LBUTTONDUP的消息)
56. //我们这里简单的返回
57. if (point.x==MouseDownPoint.x && point.y==MouseDownPoint.y)
58. {
59. ::ReleaseCapture();
60. m_SelectItem=SELECT_NONE;
61. return;
62. }
63. //get the rect of ListCtrl
64. RECT rect;
65. ::GetWindowRect(ListWnd,&rect);
66. rect.top+=24; //去掉头表的高度
67. POINT MousePoint;
68. ::GetCursorPos(&MousePoint);
69.
70. //mouse is not in the ListCtrl
71. if(!::PtInRect(&rect,MousePoint))
72. {
73. m_IsOut=true;
74. if (m_ActiveItem!=SELECT_NONE)
75. {
76. ::InvalidateRect(ListWnd,&ItemRect[m_ActiveItem],false);
77. m_ActiveItem=SELECT_NONE;
78. }
79.
80. ::SetCursor(LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR2)));
81.
82. //超过窗体上边,向上滚动
83. if (MousePoint.y<rect.top)
84. {
85. ::SendMessage(ListWnd,WM_KEYDOWN,VK_UP,0);
86. ::SendMessage(ListWnd,WM_KEYUP,VK_UP,0);
87. }
88. //超过窗体下边,向下滚动
89. else if (MousePoint.y>rect.bottom )
90. {
91. ::SendMessage(ListWnd,WM_KEYDOWN,VK_DOWN,0);
92. ::SendMessage(ListWnd,WM_KEYUP,VK_DOWN,0);
93. }
94. return;
95. }
96.
97. //if is outside the widnow,re receive all the item rect again
98. if (m_IsOut)
99. {
100. m_IsOut=false;
101. m_IsInFilstPart=false;
102. m_IsInSecondPart=false;
103. //get the count of listctrl
104. int count=(int)::SendMessage(ListWnd, LVM_GETITEMCOUNT, 0, 0);
105. //initial data
106. ItemRect.clear();
107. ItemRect.resize(count);
108.
109. for (int i=0;i<count;i++)
110. {
111. //save item rect
112. ItemRect[i].left=LVIR_SELECTBOUNDS ;
113. ::SendMessage(ListWnd, LVM_GETITEMRECT , i,(LPARAM)&ItemRect[i]);
114.
115. }
116. }
117.
118.
119. //begin find item
120. int i;
121. for(i=0; i<ItemRect.size() && !::PtInRect(&ItemRect[i],point) ; i++) ; //注意这行的分号
122.
123. //if found item(即鼠标在List里面)
124. if(i!=ItemRect.size())
125. {
126. //改变鼠标形状
127. ::SetCursor(LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_MOVEITEMCUR)));
128.
129. //在最后一项移动
130. if (i==ItemRect.size()-1)
131. {
132. //是否第一次移入此Item
133. if (m_ActiveItem!=i)
134. {
135. //假如需要,更新原来的ItemRect
136. if (m_ActiveItem!=SELECT_NONE)
137. ::InvalidateRect(ListWnd,&ItemRect[m_ActiveItem],false);
138.
139. //保存当前焦点的按钮索引
140. m_ActiveItem=i;
141. }
142.
143. //在最后一个item的上半部分上移动
144. if ( point.y<(ItemRect[m_ActiveItem].top+ItemRect[m_ActiveItem].bottom)/2 )
145. {
146. //第一次进入最后一个item的前半部分
147. if (m_IsInFilstPart==false)
148. {
149. m_IsInFilstPart=true;
150. m_IsInSecondPart=false;
151. ::InvalidateRect(ListWnd,&ItemRect[m_ActiveItem],false);
152. ::UpdateWindow(ListWnd);
153. DrawLine(ListWnd,ItemRect[m_ActiveItem].left+2,ItemRect[m_ActiveItem].top+2,
154. ItemRect[m_ActiveItem].right-2,ItemRect[m_ActiveItem].top+2);
155. }
156. }
157.
158. //在最后一个item的后半部分上移动
159. else
160. {
161. //第一次进入最后一个item的后半部分
162. if (m_IsInSecondPart==false)
163. {
164. m_IsInSecondPart=true;
165. m_IsInFilstPart=false;
166. ::InvalidateRect(ListWnd,&ItemRect[m_ActiveItem],false);
167. ::UpdateWindow(ListWnd);
168. DrawLine(ListWnd,ItemRect[m_ActiveItem].left+2,ItemRect[m_ActiveItem].bottom-2,
169. ItemRect[m_ActiveItem].right-2,ItemRect[m_ActiveItem].bottom-2);
170. }
171. }
172. return;
173. }
174.
175. //是否第一次移入此Item
176. if (m_ActiveItem!=i)
177. {
178. m_IsInFilstPart=false;
179.
180. //假如需要,更新原来的ItemRect
181. if (m_ActiveItem!=SELECT_NONE)
182. ::InvalidateRect(ListWnd,&ItemRect[m_ActiveItem],false);
183.
184. //保存当前焦点的按钮索引
185. m_ActiveItem=i;
186.
187. DrawLine(ListWnd,ItemRect[m_ActiveItem].left+4,ItemRect[m_ActiveItem].top+2,
188. ItemRect[m_ActiveItem].right-4,ItemRect[m_ActiveItem].top+2);
189.
190. return;
191. }
192. }
193.
194. //if not found item(鼠标不在List里面)
195. else
196. {
197. //假如第一次移出List
198. if (m_ActiveItem!=SELECT_NONE)
199. {
200. //重绘原来的按钮
201. ::InvalidateRect(ListWnd,&ItemRect[m_ActiveItem],false);
202.
203. //表示鼠标在List外
204. m_ActiveItem=SELECT_NONE;
205. }
206.
207. m_IsInFilstPart=false;
208. m_IsInSecondPart=false;
209.
210. //改变鼠标形状
211. ::SetCursor(LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR2)));
212. }
213. }
214. void CDragList::DrawLine(HWND hWnd,int BeginX,int BeginY,int EndX,int EndY)
215. {
216. HDC hdc=::GetDC(hWnd);
217. HPEN Pen=::CreatePen(PS_SOLID,4,RGB(0,0,0));
218. HPEN OldPen=(HPEN)SelectObject(hdc,Pen) ;
219. HBRUSH OldBrush=(HBRUSH)::SelectObject (hdc,(HBRUSH)GetStockObject(NULL_BRUSH));
220.
221. MoveToEx(hdc,BeginX,BeginY,NULL);
222. LineTo(hdc,EndX,EndY);
223.
224. ::SelectObject (hdc,OldBrush) ;
225. ::SelectObject (hdc,OldPen) ;
226. ::DeleteObject(Pen);
227. ::ReleaseDC(hWnd,hdc) ;
228. }
六、其他在网上找到的例子。供大家参考
其实有问题可以上www.codeproject.com上找,往往会有意想不到的收获