DragDropListCtrl.cpp 20 KB

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