Pictrue Control和TreeCtrl的拖动

来源:互联网 发布:那英唱歌真难听知乎 编辑:程序博客网 时间:2024/06/03 09:15

Pictrue Control实际上就是CStatic,它的动态创建过程如下:

m_Static.Create(_T(""), WS_VISIBLE|WS_CHILD|SS_BITMAP|SS_CENTERIMAGE, CRect(200,200,300,300), this);HBITMAP hBitMap = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP_Black));m_Static.SetBitmap(hBitMap);

然后就是响应鼠标的几个动作:

按下左键:

void CXXXDlg::OnLButtonDown(UINT nFlags, CPoint point){CRectrectPic;POINTptPut = point;//GetDlgItem(IDC_STATIC_Image1)->GetWindowRect(rectPic);m_Static.GetWindowRect(rectPic);ClientToScreen(&ptPut);if(rectPic.PtInRect(ptPut)){CBitmapbitmapTemp, *pOldBitmap;CDC*pDC= m_Static.GetDC();CDC *pMemDC= new CDC;//创建位图内存bitmapTemp.CreateCompatibleBitmap(pDC, rectPic.Width(), rectPic.Height());pMemDC->CreateCompatibleDC(pDC);pOldBitmap= pMemDC->SelectObject(&bitmapTemp);pMemDC->BitBlt(0, 0, rectPic.Width(), rectPic.Height(), pDC, 0, 0, SRCCOPY);pMemDC->SelectObject(pOldBitmap);deletepMemDC;ReleaseDC(pDC);m_bIsLButtonDown= TRUE;m_ptOffset.x= ptPut.x-rectPic.left;m_ptOffset.y= ptPut.y-rectPic.top;m_imgDrag.DeleteImageList();m_imgDrag.Create(rectPic.Width(), rectPic.Height(), ILC_COLOR32|ILC_MASK, 0, 1);m_imgDrag.Add(&bitmapTemp, RGB(0, 0, 0));m_imgDrag.BeginDrag(0, m_ptOffset);m_imgDrag.DragEnter(NULL, ptPut);SetCapture();}CDialog::OnLButtonDown(nFlags, point);}

鼠标移动:

void CXXXXDlg::OnMouseMove(UINT nFlags, CPoint point){if(m_bIsLButtonDown){CRectrtClient, rtPicture;m_ptMove= point;//GetDlgItem(IDC_STATIC_Image1)->GetWindowRect(rtPicture);m_Static.GetWindowRect(rtPicture);GetClientRect(rtClient);ClientToScreen(&rtClient);ClientToScreen(&m_ptMove);if(rtClient.left>m_ptMove.x-m_ptOffset.x)m_ptMove.x= rtClient.left+m_ptOffset.x;if(rtClient.top>m_ptMove.y-m_ptOffset.y)m_ptMove.y= rtClient.top+m_ptOffset.y;if(rtClient.right-rtPicture.Width()<m_ptMove.x-m_ptOffset.x)m_ptMove.x= rtClient.right-rtPicture.Width()+m_ptOffset.x;if(rtClient.bottom-rtPicture.Height()<m_ptMove.y-m_ptOffset.y)m_ptMove.y= rtClient.bottom-rtPicture.Height()+m_ptOffset.y;CImageList::DragMove(m_ptMove);}CDialog::OnMouseMove(nFlags, point);}

左键弹起:

void CXXXXDlg::OnLButtonUp(UINT nFlags, CPoint point){if(m_bIsLButtonDown){CRect rectPic;ScreenToClient(&m_ptMove);m_Static.GetWindowRect(rectPic);m_Static.MoveWindow(m_ptMove.x-m_ptOffset.x, m_ptMove.y-m_ptOffset.y, rectPic.Width(), rectPic.Height());m_bIsLButtonDown= FALSE;CImageList::DragLeave(this);CImageList::EndDrag();ReleaseCapture();m_Static.Invalidate();}CDialog::OnLButtonUp(nFlags, point);}


TreeCtrl也是一样,同样是响应鼠标的几个动作,只不过麻烦一点:

按下左键:

void CDragDropTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point){SetFocus();do{HTREEITEM hItem = HitTest(point,&nFlags);if( nFlags & TVHT_ONITEMBUTTON ){// Check if any child presentif(!ItemHasChildren(hItem)){break;}CTreeCtrl::OnLButtonDown(nFlags,point);break;}if( NULL == hItem ){break;}if( NULL == GetParentItem(hItem) ){break;}unsigned short shKeyState = GetKeyState(VK_CONTROL);shKeyState >>= 15;//get high-order bitif( shKeyState == 1 )// key down{ OnControlKeyPress(hItem);break;} else{if( m_vSelItem.size() == 0 ){SetItemState(hItem,TVIS_SELECTED,TVIS_SELECTED);m_vSelItem.push_back(hItem);break;}shKeyState = GetKeyState(VK_SHIFT);shKeyState >>= 15;if( shKeyState == 1 ){OnShiftKeyPress(hItem);break;}}m_hLastSelItem = hItem;if( m_vSelItem.size() == 1 ){ClearSelection();SetItemState(m_hLastSelItem,TVIS_SELECTED,TVIS_SELECTED);m_vSelItem.push_back(m_hLastSelItem);}}while(false);}
其中OnShiftKeyPress是响应shift按键,用来添加一组item,实现如下:

void CDragDropTreeCtrl::OnShiftKeyPress(HTREEITEM hCurItem){if( m_vSelItem.size() > 0 ){if( !IsInTheSameLevel(hCurItem) ){return;}}HTREEITEM hItemFrom = m_vSelItem[0];SetItemState(hCurItem,TVIS_SELECTED,TVIS_SELECTED);SelectItems(hItemFrom,hCurItem);}BOOL CDragDropTreeCtrl::IsInTheSameLevel(HTREEITEM hItem){BOOL bInTheSameLevel = TRUE;SEL_ITEM_LIST::iterator itr;for( itr = m_vSelItem.begin(); itr != m_vSelItem.end(); ++itr ){if( GetParentItem(hItem) != GetParentItem(*itr) ){bInTheSameLevel = FALSE;}}return bInTheSameLevel;}

SelectItems用来将item加入链表或从链表清除:

void CDragDropTreeCtrl::SelectItems(HTREEITEM hItemFrom,HTREEITEM hItemTo){RECT FromRect;GetItemRect(hItemFrom,&FromRect,FALSE);RECT ToRect;GetItemRect(hItemTo,&ToRect,FALSE);HTREEITEM hTemp;if( FromRect.top > ToRect.top ){hTemp = hItemFrom;hItemFrom = hItemTo;hItemTo = hTemp;}ClearSelection();hTemp = hItemFrom;while(1){SetItemState(hTemp,TVIS_SELECTED,TVIS_SELECTED);m_vSelItem.push_back(hTemp);if( hTemp ==  hItemTo ){break;}hTemp = GetNextVisibleItem(hTemp);}}void CDragDropTreeCtrl::ClearSelection(){int nSelItemCount = m_vSelItem.size();for( int nIdx = 0; nIdx < nSelItemCount; ++nIdx){SetItemState(m_vSelItem[nIdx],0,TVIS_SELECTED);//全部置0}m_vSelItem.clear();}


OnControlKeyPress用来响应Ctrl按键,用来逐个添加或删除item

void CDragDropTreeCtrl::OnControlKeyPress(HTREEITEM hCurItem){if( m_vSelItem.size() > 0 ){if( !IsInTheSameLevel(hCurItem) ){return;}}int nState = (TVIS_SELECTED == GetItemState(hCurItem,TVIS_SELECTED))?0:TVIS_SELECTED;SetItemState(hCurItem,nState,TVIS_SELECTED);if( 0 == nState ){RemoveFromSelectionList(hCurItem);}else{m_vSelItem.push_back(hCurItem);}}void CDragDropTreeCtrl::RemoveFromSelectionList(HTREEITEM hItem){SEL_ITEM_LIST::iterator itr;for( itr = m_vSelItem.begin(); itr != m_vSelItem.end(); ++itr ){if( (*itr) == hItem ){m_vSelItem.erase(itr);break;}}  }
还需要在鼠标点击空白处时取消选中:

void CDragDropTreeCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult){//if click is not on any item clear all the selectionint nSelItemCount = m_vSelItem.size();for( int nIdx = 0; nIdx < nSelItemCount; ++nIdx){SetItemState(m_vSelItem[nIdx],0,TVIS_SELECTED);//全部置0}m_vSelItem.clear();    }


移动鼠标:

void CDragDropTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) {if( ::DragDetect(m_hWnd,point) ){OnDrag(point);}CTreeCtrl::OnMouseMove(nFlags,point);} void CDragDropTreeCtrl::OnDrag(CPoint point){if( m_vSelItem.size() ==  0 )//没有拖动item{return;}m_bDragging = TRUE;UINT nFlags;HTREEITEM hItem = HitTest(point,&nFlags);m_pImageList = CreateDragImageEx();ASSERT (m_pImageList != NULL);if (m_pImageList != NULL){CRect rect;GetItemRect (hItem, rect, TRUE);POINT pt;pt.x = rect.left+5;pt.y = rect.top+5;ClientToScreen ( &pt ) ;m_pImageList->BeginDrag (0,CPoint(-5,-5));m_pImageList->DragEnter (NULL, pt);    SetCapture();int nEventListenerCount = m_vEventListener.size();for( int nEventListenerIdx = 0; nEventListenerIdx < nEventListenerCount; ++nEventListenerIdx ){m_vEventListener[nEventListenerIdx]->OnDrag();//外部接口实现}}}
其中的关键步骤在于移动中对item的绘制:

CImageList* CDragDropTreeCtrl::CreateDragImageEx(){// Find the bounding rectangle of all the selected itemsCRectrectBounding; // Holds rectangle bounding area for bitmapCRectrectFirstItem; // Holds first item's height and widthCRectrectTextArea;  // Holds text area of imageintnNumSelected; // Holds total number of selected itemsHTREEITEMhItem;CClientDCDraggedNodeDC(this); // To draw drag imageCDC*pDragImageCalcDC = NULL;// to find the drag image width and heightCStringstrItemText;CBitmap*pBitmapOldMemDCBitmap = NULL; // Pointer to bitmap in memoryCFont*pFontOld = NULL; // Used for  bitmap fontintnIdx = 0, nCounter = 0; // Counts array elementsintnMaxWidth = 0;// holds the maximum width to be taken to form the bounding rect//UINTuiSelectedItems;  // Holds an itemCImageList*pImageListDraggedNode = NULL; // Holds an image list pointernNumSelected = m_vSelItem.size();if( nNumSelected > 0){pDragImageCalcDC = GetDC();if(pDragImageCalcDC == NULL){return NULL;}CImageList *pImageList = GetImageList(TVSIL_NORMAL);if (pImageList == NULL){return NULL;}//HICON hIcon = pImageList->ExtractIcon(nImg);int cx,cy;ImageList_GetIconSize(*pImageList, &cx, &cy);// Calculate the maximum width of the bounding rectanglefor ( nIdx = 0; nIdx < nNumSelected; nIdx++){// Get the item's height and width one by onehItem = m_vSelItem[nIdx];strItemText = GetItemText(hItem);rectFirstItem.SetRectEmpty();pDragImageCalcDC->DrawText(strItemText, rectFirstItem, DT_CALCRECT);//得到rectif(nMaxWidth < ( rectFirstItem.Width()+cx)){nMaxWidth = rectFirstItem.Width()+cx;}}// Get the first item's height and widthhItem = m_vSelItem[0];strItemText = GetItemText(hItem);rectFirstItem.SetRectEmpty();pDragImageCalcDC->DrawText(strItemText, rectFirstItem, DT_CALCRECT);ReleaseDC(pDragImageCalcDC);// Initialize textRect for the first itemrectTextArea.SetRect(1, 1, nMaxWidth, rectFirstItem.Height());// Find the bounding rectangle of the bitmaprectBounding.SetRect(0,0, nMaxWidth+2, (rectFirstItem.Height()+2)*nNumSelected);CDC MemoryDC; // Memory Device Context used to draw the drag image// Create bitmapif( !MemoryDC.CreateCompatibleDC(&DraggedNodeDC) ){return NULL;}CBitmapDraggedNodeBmp; // Instance used for holding  dragged bitmapif( !DraggedNodeBmp.CreateCompatibleBitmap(&DraggedNodeDC, rectBounding.Width(), rectBounding.Height()) ){return NULL;}pBitmapOldMemDCBitmap = MemoryDC.SelectObject( &DraggedNodeBmp );pFontOld = MemoryDC.SelectObject(GetFont());CBrush brush(RGB(255,255,255));MemoryDC.FillRect(&rectBounding, &brush);MemoryDC.SetBkColor(RGB(255,255,255));MemoryDC.SetBkMode(TRANSPARENT);MemoryDC.SetTextColor(RGB(0,0,0));// Search through array listfor( nIdx = 0; nIdx < nNumSelected; nIdx++){hItem = m_vSelItem[nIdx];int nImg = 0,nSelImg=0;GetItemImage(hItem,nImg,nSelImg);HICON hIcon = pImageList->ExtractIcon(nImg);//cdcMemory.DrawIcon(rectTextArea.left,rectTextArea.top,hIcon);MemoryDC.MoveTo(rectTextArea.left,rectTextArea.top);if( nIdx != nNumSelected-1 ){MemoryDC.LineTo(rectTextArea.left,rectTextArea.top+18);}else{MemoryDC.LineTo(rectTextArea.left,rectTextArea.top+8);}MemoryDC.MoveTo(rectTextArea.left,rectTextArea.top+8);MemoryDC.LineTo(rectTextArea.left+5,rectTextArea.top+8);int nLeft = rectTextArea.left;rectTextArea.left += 3;::DrawIconEx(MemoryDC.m_hDC,rectTextArea.left,rectTextArea.top,hIcon,\16,16,0,NULL,DI_NORMAL);rectTextArea.left += cx;MemoryDC.Rectangle(rectTextArea);MemoryDC.DrawText(GetItemText(hItem), rectTextArea, DT_LEFT| DT_SINGLELINE|DT_NOPREFIX);rectTextArea.left = nLeft;rectTextArea.OffsetRect(0, rectFirstItem.Height()+2);DestroyIcon(hIcon);}MemoryDC.SelectObject( pFontOld );MemoryDC.SelectObject( pBitmapOldMemDCBitmap );MemoryDC.DeleteDC();// Create imagelistpImageListDraggedNode = new CImageList;pImageListDraggedNode->Create(rectBounding.Width(), rectBounding.Height(),\ILC_COLOR | ILC_MASK, 0, 1);pImageListDraggedNode->Add(&DraggedNodeBmp, RGB(255, 255,255)); return pImageListDraggedNode;}return NULL;}


最后是响应左键弹起:

void CDragDropTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) {if( !(MK_CONTROL&nFlags) && !(MK_SHIFT&nFlags) ){if( m_vSelItem.size() > 1 ){ClearSelection();SetItemState(m_hLastSelItem,TVIS_SELECTED,TVIS_SELECTED);m_vSelItem.push_back(m_hLastSelItem);}    }if ( m_bDragging && m_pImageList != NULL ) {m_bDragging = FALSE;    //KillTimer(1);ReleaseCapture();//// Terminate the dragging operation and release the mouse.//m_pImageList->DragLeave (this);m_pImageList->DragLeave (GetParent());m_pImageList->EndDrag ();SelectDropTarget(NULL);delete m_pImageList;m_pImageList = NULL;HTREEITEM hItem = HitTest(point,&nFlags);//得到鼠标松开时落点的itemint nListenerCount = m_vEventListener.size();for( int  nListenerIdx = 0; nListenerIdx < nListenerCount; ++nListenerIdx ){m_vEventListener[nListenerIdx]->OnDragRelease(point,hItem);//外部接口实现}}CTreeCtrl::OnLButtonUp(nFlags, point);}







原创粉丝点击