DragDropListCtrl.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. /////////////////////////////////////////////////////////////////////////////
  2. // DragDropListCtrl.cpp : implementation file
  3. //
  4. // Adrian Stanley 13/02/2000
  5. // Totally free source code - use however you like.
  6. // adrian@adrians.demon.co.uk.
  7. //
  8. // This class illustrates how to implement drag and drop for a MFC
  9. // list control.
  10. //
  11. // It has the following features:
  12. // Supports dragging of single and multiple selections.
  13. // Potential drag targets are highlighted (selected) as the mouse moves
  14. // over them.
  15. // The list box will scroll when you try to drag out of the top or bottom.
  16. // Horizontal mouse movement is ignored; if the mouse is to the left or right
  17. // of the list control, dragging still occurs as though the mouse is over
  18. // the control.
  19. // Works with LVS_EX_FULLROWSELECT style on or off.
  20. // Preserves checked state of dragged items.
  21. // All code encapulated in the control - no changes required to parent
  22. // class.
  23. /////////////////////////////////////////////////////////////////////////////
  24. #include "stdafx.h"
  25. #include "DragDropListCtrl.h"
  26. #ifdef _DEBUG
  27. #define new DEBUG_NEW
  28. #undef THIS_FILE
  29. static char THIS_FILE[] = __FILE__;
  30. #endif
  31. static const int SCROLL_TIMER_ID = 1;
  32. ////////////////////////////////////////////////////////////////////////////
  33. CDragDropListCtrl::CDragDropListCtrl() :
  34. m_nDropIndex(-1),
  35. m_pDragImage(NULL),
  36. m_nPrevDropIndex(-1),
  37. m_uPrevDropState(NULL),
  38. m_uScrollTimer(0),
  39. m_ScrollDirection(scrollNull),
  40. m_dwStyle(NULL)
  41. {
  42. }
  43. CDragDropListCtrl::~CDragDropListCtrl()
  44. {
  45. // Fail safe clean up.
  46. delete m_pDragImage;
  47. m_pDragImage = NULL;
  48. KillScrollTimer();
  49. }
  50. BEGIN_MESSAGE_MAP(CDragDropListCtrl, CListCtrl)
  51. ON_WM_MOUSEMOVE()
  52. ON_WM_LBUTTONUP()
  53. ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBeginDrag)
  54. ON_WM_TIMER()
  55. END_MESSAGE_MAP()
  56. // MFC控件事件函数-拖动时产生的事件;
  57. void CDragDropListCtrl::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
  58. {
  59. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  60. if (pNMListView)
  61. {
  62. m_nPrevDropIndex = -1;
  63. m_uPrevDropState = NULL;
  64. // Items being dragged - can be one or more.
  65. // 可以拖动一个或多个子项;
  66. m_anDragIndexes.RemoveAll(); // 清空数组,重新添加被选中的拖动的项索引;
  67. POSITION pos = GetFirstSelectedItemPosition();
  68. while (pos)
  69. {
  70. m_anDragIndexes.Add(GetNextSelectedItem(pos));
  71. }
  72. // 获取当前控件的模式;
  73. DWORD dwStyle = GetStyle();
  74. // 如果是单选,设置为多选样式以使能够拖动时能多个图标一起移动;
  75. if ((dwStyle & LVS_SINGLESEL) == LVS_SINGLESEL)
  76. {
  77. // List control is single select; we need it to be multi-select so
  78. // we can show both the drag item and potential drag target as selected.
  79. m_dwStyle = dwStyle;
  80. ModifyStyle(LVS_SINGLESEL, NULL);
  81. }
  82. // 如果选中的即将被拖动的项索引数不为0;
  83. if (m_anDragIndexes.GetSize() > 0)
  84. {
  85. // Create a drag image from the centre point of the item image.
  86. // Clean up any existing drag image first.
  87. // 清空所有之前存在的拖动图标,并以当前项中心点重新创建一个拖动图标;
  88. delete m_pDragImage;
  89. CPoint ptDragItem;
  90. // 创建新的拖动图标;
  91. m_pDragImage = CreateDragImageEx(&ptDragItem);
  92. if (m_pDragImage)
  93. {
  94. m_pDragImage->BeginDrag(0, ptDragItem);
  95. //m_pDragImage->DragEnter(CWnd::GetDesktopWindow(), pNMListView->ptAction);
  96. m_pDragImage->DragEnter(GetParent(), pNMListView->ptAction);
  97. // Capture all mouse messages in case the user drags outside the control.
  98. // 设置当前线程窗口捕获鼠标;
  99. SetCapture();
  100. }
  101. }
  102. }
  103. *pResult = 0;
  104. }
  105. // Based on code by Frank Kobs.
  106. CImageList* CDragDropListCtrl::CreateDragImageEx(LPPOINT lpPoint)
  107. {
  108. // 单个项时的矩形;
  109. CRect rectSingle;
  110. // 所有项并集后的矩形大小;
  111. CRect rectComplete(0, 0, 0, 0);
  112. // 选中项的索引;
  113. int nIndex = -1;
  114. // 是否初始化并集矩形变量;
  115. BOOL bFirst = TRUE;
  116. // Determine the size of the drag image.
  117. // 确定拖动图标的大小;
  118. POSITION pos = GetFirstSelectedItemPosition();
  119. while (pos)
  120. {
  121. nIndex = GetNextSelectedItem(pos);
  122. GetItemRect(nIndex, rectSingle, LVIR_BOUNDS);
  123. if (bFirst)
  124. {
  125. // Initialize the CompleteRect
  126. // 初始化并集矩形变量;
  127. GetItemRect(nIndex, rectComplete, LVIR_BOUNDS);
  128. bFirst = FALSE;
  129. }
  130. // 并集每一个项的大小;
  131. rectComplete.UnionRect(rectComplete, rectSingle);
  132. }
  133. // Create bitmap in memory DC
  134. // 获取当前客户区域DC句柄;
  135. CClientDC dcClient(this);
  136. CDC dcMem;
  137. CBitmap Bitmap;
  138. // 创建兼容内存位图DC;
  139. if (!dcMem.CreateCompatibleDC(&dcClient))
  140. {
  141. return NULL;
  142. }
  143. // 在DC上创建兼容位图;
  144. if (!Bitmap.CreateCompatibleBitmap(&dcClient, rectComplete.Width(), rectComplete.Height()))
  145. {
  146. return NULL;
  147. }
  148. // 保存DC上创建的兼容位图;
  149. CBitmap* pOldMemDCBitmap = dcMem.SelectObject(&Bitmap);
  150. // Here green is used as mask color.
  151. // 用绿色作为屏蔽色;
  152. dcMem.FillSolidRect(0, 0, rectComplete.Width(), rectComplete.Height(), RGB(0, 255, 0));
  153. // Paint each DragImage in the DC.
  154. // 在DC环境上画出每一个项的拖动图标;
  155. CImageList* pSingleImageList = NULL;
  156. CPoint pt;
  157. pos = GetFirstSelectedItemPosition();
  158. while (pos)
  159. {
  160. nIndex = GetNextSelectedItem(pos);
  161. GetItemRect(nIndex, rectSingle, LVIR_BOUNDS);
  162. // 为每一个项创建拖动图标;
  163. pSingleImageList = CreateDragImage(nIndex, &pt);
  164. if (pSingleImageList)
  165. {
  166. // Make sure width takes into account not using LVS_EX_FULLROWSELECT style.
  167. IMAGEINFO ImageInfo;
  168. // 获取每个项的图标信息;
  169. pSingleImageList->GetImageInfo(0, &ImageInfo);
  170. rectSingle.right = rectSingle.left + (ImageInfo.rcImage.right - ImageInfo.rcImage.left);
  171. // 合并所有拖动图标并在并集矩形内重绘;
  172. pSingleImageList->DrawIndirect(
  173. &dcMem,
  174. 0,
  175. CPoint(rectSingle.left - rectComplete.left,
  176. rectSingle.top - rectComplete.top),
  177. rectSingle.Size(),
  178. CPoint(0,0));
  179. // 释放内存;
  180. delete pSingleImageList;
  181. }
  182. }
  183. dcMem.SelectObject(pOldMemDCBitmap);
  184. // Create the imagelist with the merged drag images.
  185. // 用合并后的拖动图标矩形创建一个ImageList对象;
  186. CImageList* pCompleteImageList = new CImageList;
  187. pCompleteImageList->Create(rectComplete.Width(), rectComplete.Height(), ILC_COLOR | ILC_MASK, 0, 1);
  188. // Here green is used as mask color.
  189. pCompleteImageList->Add(&Bitmap, RGB(0, 255, 0));
  190. Bitmap.DeleteObject();
  191. // As an optional service:
  192. // Find the offset of the current mouse cursor to the imagelist
  193. // this we can use in BeginDrag().
  194. if (lpPoint)
  195. {
  196. CPoint ptCursor;
  197. GetCursorPos(&ptCursor);
  198. ScreenToClient(&ptCursor);
  199. lpPoint->x = ptCursor.x - rectComplete.left;
  200. lpPoint->y = ptCursor.y - rectComplete.top;
  201. }
  202. return pCompleteImageList;
  203. }
  204. void CDragDropListCtrl::OnMouseMove(UINT nFlags, CPoint point)
  205. {
  206. if (m_pDragImage)
  207. {
  208. // Must be dragging, as there is a drag image.
  209. // Move the drag image.
  210. // 移动拖动图标;
  211. CPoint ptDragImage(point);
  212. ClientToScreen(&ptDragImage);
  213. m_pDragImage->DragMove(ptDragImage);
  214. // Leave dragging so we can update potential drop target selection.
  215. // 去除DragLeave函数,在拖动时就不会闪烁了;
  216. //m_pDragImage->DragLeave(CWnd::GetDesktopWindow());
  217. //m_pDragImage->DragLeave(GetParent());
  218. // Force x coordinate to always be in list control - only interested in y coordinate.
  219. // In effect the list control has captured all horizontal mouse movement.
  220. static const int nXOffset = 8;
  221. CRect rect;
  222. GetWindowRect(rect);
  223. // 获取移动中鼠标下方的窗口句柄;
  224. CWnd* pDropWnd = CWnd::WindowFromPoint(CPoint(rect.left + nXOffset, ptDragImage.y));
  225. // Get the window under the drop point.
  226. if (pDropWnd == this)
  227. {
  228. // Still in list control so select item under mouse as potential drop target.
  229. // 如果点仍在CListCtrl控件内,更新拖动图标的位置;
  230. point.x = nXOffset; // Ensures x coordinate is always valid.
  231. UpdateSelection(HitTest(point));
  232. }
  233. // 获取控件的客户区域;
  234. CRect rectClient;
  235. GetClientRect(rectClient);
  236. // 获取拖动图标的坐标点;
  237. CPoint ptClientDragImage(ptDragImage);
  238. ScreenToClient(&ptClientDragImage);
  239. // Client rect includes header height, so ignore it, i.e.,
  240. // moving the mouse over the header (and higher) will result in a scroll up.
  241. CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
  242. if (pHeader)
  243. {
  244. CRect rectHeader;
  245. pHeader->GetClientRect(rectHeader);
  246. rectClient.top += rectHeader.Height();
  247. }
  248. if (ptClientDragImage.y < rectClient.top)
  249. {
  250. // Mouse is above the list control - scroll up.
  251. SetScrollTimer(scrollUp);
  252. }
  253. else if (ptClientDragImage.y > rectClient.bottom)
  254. {
  255. // Mouse is below the list control - scroll down.
  256. SetScrollTimer(scrollDown);
  257. }
  258. else
  259. {
  260. KillScrollTimer();
  261. }
  262. // Resume dragging.
  263. //m_pDragImage->DragEnter(CWnd::GetDesktopWindow(), ptDragImage);
  264. m_pDragImage->DragEnter(GetParent(), ptDragImage);
  265. }
  266. else
  267. {
  268. KillScrollTimer();
  269. }
  270. CListCtrl::OnMouseMove(nFlags, point);
  271. }
  272. void CDragDropListCtrl::UpdateSelection(int nDropIndex)
  273. {
  274. if (nDropIndex > -1 && nDropIndex < GetItemCount())
  275. {
  276. // Drop index is valid and has changed since last mouse movement.
  277. RestorePrevDropItemState();
  278. // Save information about current potential drop target for restoring next time round.
  279. m_nPrevDropIndex = nDropIndex;
  280. m_uPrevDropState = GetItemState(nDropIndex, LVIS_SELECTED);
  281. // Select current potential drop target.
  282. SetItemState(nDropIndex, LVIS_SELECTED, LVIS_SELECTED);
  283. m_nDropIndex = nDropIndex; // Used by DropItem().
  284. UpdateWindow();
  285. }
  286. }
  287. void CDragDropListCtrl::RestorePrevDropItemState()
  288. {
  289. if (m_nPrevDropIndex > -1 && m_nPrevDropIndex < GetItemCount())
  290. {
  291. // Restore state of previous potential drop target.
  292. SetItemState(m_nPrevDropIndex, m_uPrevDropState, LVIS_SELECTED);
  293. }
  294. }
  295. void CDragDropListCtrl::SetScrollTimer(EScrollDirection ScrollDirection)
  296. {
  297. if (m_uScrollTimer == 0)
  298. {
  299. m_uScrollTimer = SetTimer(SCROLL_TIMER_ID, 100, NULL);
  300. }
  301. m_ScrollDirection = ScrollDirection;
  302. }
  303. void CDragDropListCtrl::KillScrollTimer()
  304. {
  305. if (m_uScrollTimer != 0)
  306. {
  307. KillTimer(SCROLL_TIMER_ID);
  308. m_uScrollTimer = 0;
  309. m_ScrollDirection = scrollNull;
  310. }
  311. }
  312. void CDragDropListCtrl::OnLButtonUp(UINT nFlags, CPoint point)
  313. {
  314. if (m_pDragImage)
  315. {
  316. KillScrollTimer();
  317. // Release the mouse capture and end the dragging.
  318. // 释放对窗口鼠标的捕获;
  319. ::ReleaseCapture();
  320. //m_pDragImage->DragLeave(CWnd::GetDesktopWindow());
  321. m_pDragImage->DragLeave(GetParent());
  322. m_pDragImage->EndDrag();
  323. m_pDragImage->DeleteImageList();
  324. delete m_pDragImage;
  325. m_pDragImage = NULL;
  326. // Drop the item on the list.
  327. DropItem(point);
  328. }
  329. CListCtrl::OnLButtonUp(nFlags, point);
  330. }
  331. void CDragDropListCtrl::DropItem()
  332. {
  333. RestorePrevDropItemState();
  334. // Drop after currently selected item.
  335. // 删除当前选中的项;
  336. m_nDropIndex++;
  337. if (m_nDropIndex < 0 || m_nDropIndex > GetItemCount() - 1)
  338. {
  339. // Fail safe - invalid drop index, so drop at end of list.
  340. m_nDropIndex = GetItemCount();
  341. }// 从尾部开始;
  342. int nColumns = 1;
  343. CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
  344. if (pHeader)
  345. {
  346. nColumns = pHeader->GetItemCount();
  347. }
  348. // Move all dragged items to their new positions.
  349. // 将所有拖动项移动到新位置;
  350. for (int nDragItem = 0; nDragItem < m_anDragIndexes.GetSize(); nDragItem++)
  351. {
  352. // 获取拖动项的索引;
  353. int nDragIndex = m_anDragIndexes[nDragItem];
  354. if (nDragIndex > -1 && nDragIndex < GetItemCount())
  355. {
  356. // Get information about this drag item.
  357. // 获取指定索引位置的拖动项的信息,LV_ITEM必须指定iItem值,才能GetItem获取mask标识的其他项信息;
  358. // 同时,这属于一个GetItem的使用示例;
  359. char szText[256];
  360. LV_ITEM lvItem;
  361. ZeroMemory(&lvItem, sizeof(LV_ITEM));
  362. lvItem.iItem = nDragIndex;
  363. lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
  364. lvItem.stateMask = LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED | LVIS_STATEIMAGEMASK;
  365. lvItem.pszText = szText;
  366. lvItem.cchTextMax = sizeof(szText) - 1;
  367. GetItem(&lvItem);
  368. BOOL bChecked = GetCheck(nDragIndex);
  369. // Before moving drag item, make sure it is deselected in its original location,
  370. // otherwise GetSelectedCount() will return 1 too many.
  371. SetItemState(nDragIndex, static_cast<UINT>(~LVIS_SELECTED), LVIS_SELECTED);
  372. // Insert the dragged item at drop index.
  373. // 重新赋值iItem,将拖动项插入到删除索引位置上(起始时m_nDropIndex为最后项索引);
  374. lvItem.iItem = m_nDropIndex;
  375. InsertItem(&lvItem);
  376. if (bChecked)
  377. {
  378. SetCheck(m_nDropIndex);
  379. }
  380. // Index of dragged item will change if item has been dropped above itself.
  381. if (nDragIndex > m_nDropIndex)
  382. {
  383. nDragIndex++;
  384. }
  385. // Fill in all the columns for the dragged item.
  386. // 填充所有拖动项的列信息(子项中的文字);
  387. lvItem.mask = LVIF_TEXT;
  388. lvItem.iItem = m_nDropIndex;
  389. for (int nColumn = 1; nColumn < nColumns; nColumn++)
  390. {
  391. _tcscpy(lvItem.pszText, (LPCTSTR)(GetItemText(nDragIndex, nColumn)));
  392. lvItem.iSubItem = nColumn;
  393. SetItem(&lvItem);
  394. }
  395. // Delete the original item.
  396. // 删除原始项;
  397. DeleteItem(nDragIndex);
  398. // Need to adjust indexes of remaining drag items.
  399. for (int nNewDragItem = nDragItem; nNewDragItem < m_anDragIndexes.GetSize(); nNewDragItem++)
  400. {
  401. int nNewDragIndex = m_anDragIndexes[nNewDragItem];
  402. if (nDragIndex < nNewDragIndex && nNewDragIndex < m_nDropIndex)
  403. {
  404. // Item has been removed from above this item, and inserted after it,
  405. // so this item moves up the list.
  406. m_anDragIndexes[nNewDragItem] = max(nNewDragIndex - 1, 0);
  407. }
  408. else if (nDragIndex > nNewDragIndex && nNewDragIndex > m_nDropIndex)
  409. {
  410. // Item has been removed from below this item, and inserted before it,
  411. // so this item moves down the list.
  412. m_anDragIndexes[nNewDragItem] = nNewDragIndex + 1;
  413. }
  414. }
  415. if (nDragIndex > m_nDropIndex)
  416. {
  417. // Item has been added before the drop target, so drop target moves down the list.
  418. m_nDropIndex++;
  419. }
  420. }
  421. }
  422. if (m_dwStyle != NULL)
  423. {
  424. // Style was modified, so return it back to original style.
  425. ModifyStyle(NULL, m_dwStyle);
  426. m_dwStyle = NULL;
  427. }
  428. }
  429. void CDragDropListCtrl::OnTimer(UINT nIDEvent)
  430. {
  431. if (nIDEvent == SCROLL_TIMER_ID && m_pDragImage)
  432. {
  433. WPARAM wParam = NULL;
  434. int nDropIndex = -1;
  435. if (m_ScrollDirection == scrollUp)
  436. {
  437. wParam = MAKEWPARAM(SB_LINEUP, 0);
  438. nDropIndex = m_nDropIndex - 1;
  439. }
  440. else if (m_ScrollDirection == scrollDown)
  441. {
  442. wParam = MAKEWPARAM(SB_LINEDOWN, 0);
  443. nDropIndex = m_nDropIndex + 1;
  444. }
  445. m_pDragImage->DragShowNolock(FALSE);
  446. SendMessage(WM_VSCROLL, wParam, NULL);
  447. UpdateSelection(nDropIndex);
  448. m_pDragImage->DragShowNolock(TRUE);
  449. }
  450. else
  451. {
  452. CListCtrl::OnTimer(nIDEvent);
  453. }
  454. }
  455. int CDragDropListCtrl::GetPtItemIndex(CPoint pt)
  456. {
  457. // 判断点是否还在控件内;
  458. // CWnd* pDropWnd = CWnd::WindowFromPoint(pt);
  459. // if (pDropWnd != this)
  460. // {
  461. // AfxMessageBox(_T("不在控件上"));
  462. // return -1;
  463. // }
  464. // 遍历全部项,查找点在哪个项上;
  465. CRect rtItem;
  466. int nCount = GetItemCount();
  467. int nIndex = 0;
  468. for (nIndex = 0; nIndex < nCount; nIndex++)
  469. {
  470. GetItemRect(nIndex, &rtItem, LVIR_BOUNDS);//LVIR_ICON
  471. if ( PtInRect(rtItem,pt) )
  472. break;
  473. }
  474. // 返回项索引值;
  475. return (nIndex == nCount) ? -1 : nIndex;
  476. }
  477. void CDragDropListCtrl::DropItem(CPoint pt)
  478. {
  479. RestorePrevDropItemState();
  480. // 获取点对应的项值;
  481. int nCurIndex = GetPtItemIndex(pt);
  482. #if 1
  483. CString strIndex;
  484. strIndex.Format(_T("%d~%d"), m_anDragIndexes[0],nCurIndex);
  485. AfxMessageBox(strIndex);
  486. #endif
  487. // 相等时,不处理;
  488. if (nCurIndex > m_anDragIndexes[0])// 拖动项往后拖;
  489. {
  490. int nColumns = 1;
  491. CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
  492. if (pHeader)
  493. {
  494. nColumns = pHeader->GetItemCount();
  495. }
  496. int nDragIndex = m_anDragIndexes[0];
  497. // 获取指定索引位置的拖动项的信息,LV_ITEM必须指定iItem值,才能GetItem获取mask标识的其他项信息;
  498. // 同时,这属于一个GetItem的使用示例;
  499. char szText[256];
  500. LV_ITEM lvItem;
  501. ZeroMemory(&lvItem, sizeof(LV_ITEM));
  502. lvItem.iItem = nDragIndex;
  503. lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
  504. lvItem.stateMask = LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED | LVIS_STATEIMAGEMASK;
  505. lvItem.pszText = szText;
  506. lvItem.cchTextMax = sizeof(szText) - 1;
  507. GetItem(&lvItem);
  508. BOOL bChecked = GetCheck(nDragIndex);
  509. // Before moving drag item, make sure it is deselected in its original location,
  510. // otherwise GetSelectedCount() will return 1 too many.
  511. SetItemState(nDragIndex, static_cast<UINT>(~LVIS_SELECTED), LVIS_SELECTED);
  512. // Insert the dragged item at drop index.
  513. // 重新赋值iItem,将拖动项插入到删除索引位置上(起始时m_nDropIndex为最后项索引);
  514. lvItem.iItem = m_nDropIndex;
  515. InsertItem(&lvItem);
  516. if (bChecked)
  517. {
  518. SetCheck(m_nDropIndex);
  519. }
  520. // Index of dragged item will change if item has been dropped above itself.
  521. if (nDragIndex > m_nDropIndex)
  522. {
  523. nDragIndex++;
  524. }
  525. // Fill in all the columns for the dragged item.
  526. // 填充所有拖动项的列信息(子项中的文字);
  527. lvItem.mask = LVIF_TEXT;
  528. lvItem.iItem = m_nDropIndex;
  529. for (int nColumn = 1; nColumn < nColumns; nColumn++)
  530. {
  531. _tcscpy(lvItem.pszText, (LPCTSTR)(GetItemText(nDragIndex, nColumn)));
  532. lvItem.iSubItem = nColumn;
  533. SetItem(&lvItem);
  534. }
  535. // Delete the original item.
  536. // 删除原始项;
  537. DeleteItem(nDragIndex);
  538. }
  539. else if (nCurIndex < m_anDragIndexes[0])// 拖动项往前拖;
  540. {
  541. }
  542. #if 0
  543. // Drop after currently selected item.
  544. // 删除当前选中的项;
  545. m_nDropIndex++;
  546. if (m_nDropIndex < 0 || m_nDropIndex > GetItemCount() - 1)
  547. {
  548. // Fail safe - invalid drop index, so drop at end of list.
  549. m_nDropIndex = GetItemCount();
  550. }// 从尾部开始;
  551. int nColumns = 1;
  552. CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
  553. if (pHeader)
  554. {
  555. nColumns = pHeader->GetItemCount();
  556. }
  557. // Move all dragged items to their new positions.
  558. // 将所有拖动项移动到新位置;
  559. for (int nDragItem = 0; nDragItem < m_anDragIndexes.GetSize(); nDragItem++)
  560. {
  561. // 获取拖动项的索引;
  562. int nDragIndex = m_anDragIndexes[nDragItem];
  563. if (nDragIndex > -1 && nDragIndex < GetItemCount())
  564. {
  565. // Get information about this drag item.
  566. // 获取指定索引位置的拖动项的信息,LV_ITEM必须指定iItem值,才能GetItem获取mask标识的其他项信息;
  567. // 同时,这属于一个GetItem的使用示例;
  568. char szText[256];
  569. LV_ITEM lvItem;
  570. ZeroMemory(&lvItem, sizeof(LV_ITEM));
  571. lvItem.iItem = nDragIndex;
  572. lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
  573. lvItem.stateMask = LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED | LVIS_STATEIMAGEMASK;
  574. lvItem.pszText = szText;
  575. lvItem.cchTextMax = sizeof(szText) - 1;
  576. GetItem(&lvItem);
  577. BOOL bChecked = GetCheck(nDragIndex);
  578. // Before moving drag item, make sure it is deselected in its original location,
  579. // otherwise GetSelectedCount() will return 1 too many.
  580. SetItemState(nDragIndex, static_cast<UINT>(~LVIS_SELECTED), LVIS_SELECTED);
  581. // Insert the dragged item at drop index.
  582. // 重新赋值iItem,将拖动项插入到删除索引位置上(起始时m_nDropIndex为最后项索引);
  583. lvItem.iItem = m_nDropIndex;
  584. InsertItem(&lvItem);
  585. if (bChecked)
  586. {
  587. SetCheck(m_nDropIndex);
  588. }
  589. // Index of dragged item will change if item has been dropped above itself.
  590. if (nDragIndex > m_nDropIndex)
  591. {
  592. nDragIndex++;
  593. }
  594. // Fill in all the columns for the dragged item.
  595. // 填充所有拖动项的列信息(子项中的文字);
  596. lvItem.mask = LVIF_TEXT;
  597. lvItem.iItem = m_nDropIndex;
  598. for (int nColumn = 1; nColumn < nColumns; nColumn++)
  599. {
  600. _tcscpy(lvItem.pszText, (LPCTSTR)(GetItemText(nDragIndex, nColumn)));
  601. lvItem.iSubItem = nColumn;
  602. SetItem(&lvItem);
  603. }
  604. // Delete the original item.
  605. // 删除原始项;
  606. DeleteItem(nDragIndex);
  607. // Need to adjust indexes of remaining drag items.
  608. for (int nNewDragItem = nDragItem; nNewDragItem < m_anDragIndexes.GetSize(); nNewDragItem++)
  609. {
  610. int nNewDragIndex = m_anDragIndexes[nNewDragItem];
  611. if (nDragIndex < nNewDragIndex && nNewDragIndex < m_nDropIndex)
  612. {
  613. // Item has been removed from above this item, and inserted after it,
  614. // so this item moves up the list.
  615. m_anDragIndexes[nNewDragItem] = max(nNewDragIndex - 1, 0);
  616. }
  617. else if (nDragIndex > nNewDragIndex && nNewDragIndex > m_nDropIndex)
  618. {
  619. // Item has been removed from below this item, and inserted before it,
  620. // so this item moves down the list.
  621. m_anDragIndexes[nNewDragItem] = nNewDragIndex + 1;
  622. }
  623. }
  624. if (nDragIndex > m_nDropIndex)
  625. {
  626. // Item has been added before the drop target, so drop target moves down the list.
  627. m_nDropIndex++;
  628. }
  629. }
  630. }
  631. if (m_dwStyle != NULL)
  632. {
  633. // Style was modified, so return it back to original style.
  634. ModifyStyle(NULL, m_dwStyle);
  635. m_dwStyle = NULL;
  636. }
  637. #endif
  638. }