现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

让ClistCtrl能够拖动项

2012-08-21 05:31 工业·编程 ⁄ 共 9552字 ⁄ 字号 暂无评论

    在网上搜索很多关于拖动ClistCtrl中一项的文章,找到了一些,但却编译不了。有个例子不错,但总觉得不合适我的程序,于是自己下决心做一个,过程倒还挺顺利。现在拿出来和大家分享,希望对大家有所帮助。阿弥陀佛!^_^

一、先上个图片个给大家看一下效果吧。

clip_image001

二、源代码下载

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
//{{AFX_MSG(CDemoDlg)
virtual BOOL OnInitDialog();
afx_msg LRESULT DragMoveItem(WPARAM wParam, LPARAM lParam);  /*声明自定义的消息响应函数*/
//}}AFX_MSG
DECLARE_MESSAGE_MAP()


2)对话框源文件里


BEGIN_MESSAGE_MAP(CDemoDlg, CDialog)
//{{AFX_MSG_MAP(CDemoDlg)
ON_MESSAGE(WM_MOVEITEM, DragMoveItem)  /*将消息和消息响应函数联系起来*/
//}}AFX_MSG_MAP
END_MESSAGE_MAP()


3)在此添加移动一项后的处理代码

/****************************************************************************
移动后接收到消息并做处理
****************************************************************************/
LRESULT CDemoDlg::DragMoveItem(WPARAM wParam, LPARAM lParam)  
{  
int src=wParam;
int des=lParam;

//---------------------------步骤1.获取要移动的项的信息-----------------------------------------

//获取要移动的项
LVITEM lvi;
lvi.cchTextMax=_MAX_FNAME;

//get the first column text
TCHAR ItemText0[_MAX_FNAME];
lvi.pszText=ItemText0;
lvi.iSubItem=0;
::SendMessage(m_ListCtrl.m_hWnd, LVM_GETITEMTEXT, (WPARAM)src, (LPARAM)&lvi);
//get the second column text
TCHAR ItemText1[_MAX_FNAME];
lvi.pszText=ItemText1;
lvi.iSubItem=1;
::SendMessage(m_ListCtrl.m_hWnd, LVM_GETITEMTEXT, (WPARAM)src, (LPARAM)&lvi);
//---------------------------步骤2.在目标位置des插入项-----------------------------------------

//将item移到要插入的位置
int nRow = m_ListCtrl.InsertItem(des, ItemText0,0);//插入1行"11"代表第0列的数据 参数(行数,标题,图标索引)
m_ListCtrl.SetItemText(nRow, 1, ItemText1); //设置第一列数据
//高亮移动后的item
m_ListCtrl.SetItemState(des,LVIS_SELECTED,LVIS_SELECTED);

//---------------------------步骤3.确定要移动的项的新索引位置-----------------------------------------
if (src>=des)
  src+=1;
//---------------------------步骤4.删除要移动的项-----------------------------------------
//删除要移动的项
m_ListCtrl.DeleteItem(src);

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上找,往往会有意想不到的收获

给我留言

留言无头像?