拖動是界面編程頻繁使用的一個效果,在windows系統下可謂大行其道。縱觀時下的應用軟件幾乎各個都支持各類各樣拖動的效果,windows7更是把拖動作到了極致。其實提及來拖動的實現也很簡單,對於有句柄的對象均可以經過MoveWindow或SetWindowPos實現位置變更,而沒有句柄的對象實現拖動無非就是作些參數修改,說到底實現拖動就是在OnLButtonDown、OnMouseMove和OnLButtonUp中處理數據,固然你可使用鼠標右鍵甚至中建消息來實現,基本原理是同樣的。
基本原理是不難,不過要想作到效果二字就要動一番腦筋了。讓咱們來看看win7下的圖標拖放,鼠標會拖起一個半透明的圖標副本到你想要的位置,透過這個透明的圖標你能夠看到其下面的狀況,這樣的效果其實在windows的早期版本就已經實現了,它有着很好的用戶體驗。那麼咱們能不能輕鬆的實現相似的拖動效果呢?答案固然是確定的!最近看到論壇裏幾個討論拖動的帖子,正巧前一段時間本身也作了一些相關的工做,小研究了一下,因而就想把研究成果拿出來和你們分享,這樣纔有利於交流和進步嘛。之前我寫博客沒貼過效果圖,以致於不少網友下載示例代碼以後發現不是本身想要的東西,這個確實很差,在此我向你們表示歉意。此次把效果圖貼上,若是以爲這個效果很通常或者不是你所須要的那就不要浪費你寶貴的時間閱讀文章和下載代碼了。編程
從圖中能夠看出,個人小豬頭像是能夠被拖動的,半透明的那個就是拖動的副本,截圖的時候鼠標沒有截到,呵呵。爲了讓半透明效果可以明顯的看出來我特地爲對話框貼了張背景圖。被拖動的實際上是一個picture ctrl,也就是一個靜態控件,固然經過後面的介紹你們會發現這個方法的擴展性比較強,能夠應用於不少場合,甚至能夠應用於非控件的拖動對象的狀況。好了,效果就是這樣了,下面切入正題開始介紹實現方法。
對於熟悉拖動效果製做的朋友們都應該知道,實現拖動有一個很簡單的方法就是經過CImageList。CImageList提供了BeginDrag、DragEnter、DragMove、DragLeave、EndDrag系列函數,分別在OnLButtonDown、OnMouseMove和OnLButtonUp等消息中合理調用這些函數就能夠輕鬆實現對CImageList的元素的拖動效果。那麼咱們要作的就是構造一個CImageList,使它的元素是咱們想要拖動的圖片,這樣就大功告成了。那怎樣獲取圖像呢?答案也很簡單,就是到被拖動的對象的DC中將所要拖動的區域拷貝到一個內存位圖中便可。具體到個人這個例子,我是這樣實現的:
在OnLButtonDown中判斷鼠標是否在控件範圍內,若是在就將控件範圍內的DC內容拷貝到內存位圖中,而後建立CImageList將包含有控件內容的位圖添加進CImageList做爲其元素,接着經過這個ImageList實現拖動。具體代碼以下
windows
void CDragDemoDlg::OnLButtonDown(UINT nFlags, CPoint point) { CRect rectPic; POINT ptPut = point; GetDlgItem(IDC_STATIC_DEMO)->GetWindowRect(rectPic); ClientToScreen(&ptPut); if(rectPic.PtInRect(ptPut)) { CBitmap bitmapTemp, *pOldBitmap; CDC *pDC = GetDlgItem(IDC_STATIC_DEMO)->GetDC(), *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); delete pMemDC; 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 CDragDemoDlg::OnMouseMove(UINT nFlags, CPoint point) { if(m_bIsLButtonDown) { CRect rtClient, rtPicture; m_ptMove = point; GetDlgItem(IDC_STATIC_DEMO)->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 = rtClient.right-rtPicture.Width()+m_ptOffset.x; if(rtClient.bottom-rtPicture.Height() m_ptMove.y = rtClient.bottom-rtPicture.Height()+m_ptOffset.y; CImageList::DragMove(m_ptMove); } CDialog::OnMouseMove(nFlags, point); }
void CDragDemoDlg::OnLButtonUp(UINT nFlags, CPoint point) { if(m_bIsLButtonDown) { CRect rectPic; CWnd* pPic = GetDlgItem(IDC_STATIC_DEMO); ScreenToClient(&m_ptMove); pPic->GetWindowRect(rectPic); pPic->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(); pPic->Invalidate(); } CDialog::OnLButtonUp(nFlags, point); }
void CDragDemoDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CDialog::OnActivate(nState, pWndOther, bMinimized); if(nState==WA_INACTIVE)//當失去焦點後, { m_bIsLButtonDown = FALSE; CImageList::DragLeave(this); CImageList::EndDrag(); ReleaseCapture(); } }