MFC 實現圖片的拖拽功能,程式碼很詳細,貼過去就能用!

MFC 實現圖片的拖拽功能,程式碼很詳細,貼過去就能用!

拖動是介面程式設計頻繁使用的一個效果,在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實現拖動。具體程式碼如下

1、加入一個Picture Control控制元件,並且將該控制元件屬性中的Type設為Bitmap

2、定義CStatic m_pictureCtl;

    並且與Picture Control控制元件關聯起來 DDX_Control(pDX, IDC_STATIC_DEMO, m_pictureCtl);

3、OnInitDialog()中,將點陣圖載入該控制元件中:

HBITMAP hBitMap2 = (HBITMAP)::LoadImage( NULL, _T(“res\\Dog.bmp”), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_pictureCtl.SetBitmap(hBitMap2);

4、此時Picture控制元件就可以將加入的點陣圖顯示出來。

再接下來:

標頭檔案public中增加:

	//滑鼠按下,擡起和移動的響應函式
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
CPoint m_ptMove;
CPoint m_ptOffset;
BOOL m_bIsLButtonDown;
CImageList m_imgDrag;

.CPP檔案中:

BEGIN_MESSAGE_MAP(CMyDialogDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_SIZE()
//滑鼠左鍵按下,擡起,移動響應訊息 
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()


下來就是響應函式:

void CMyDialogDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
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( );  
}  
CDialogEx::OnLButtonDown(nFlags, point);
}
void CMyDialogDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CRect rect;
GetClientRect(&rect);
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();  
}  
CDialogEx::OnLButtonUp(nFlags, point);
}
void CMyDialogDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_bIsLButtonDown)  
{  
CRect       rtClient, rtPicture;  
CPoint tempPoint;
GetClientRect(rtClient);  
m_ptMove    = point; 
GetDlgItem(IDC_STATIC_DEMO)->GetWindowRect(rtPicture);  
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);  
}  
CDialogEx::OnMouseMove(nFlags, point);
}

PS:

上邊的例項圖片中有背景圖片,關於如何新增背景圖片,請參見上一篇文章 http://blog.csdn.net/max900428/article/details/23622945,但是一定要記住,先畫背景圖片,再m_pictureCtl.SetBitmap(hBitMap2);
 否則背景圖片會把此Picture控制元件蓋住,具體位置在執行完BitBlt後m_pictureCtl.SetBitmap(hBitMap2);即可。