MFC的OnMouseMove移動位置和OnMouseWheel縮放實現

來源:互聯網
上載者:User

標籤:int   war   定義   tcl   像素   菜單   button   ecif   響應   

1. 基本作用

OnMouseMove響應滑鼠移動時間

OnMouseWheel響應滑鼠中鍵的滾動

 

2. 參數說明afx_msgvoidOnMouseMove(UINT nFlags, CPoint point);

nFlags說明:指示虛擬按鍵是否按下 ,此參數可以是任何下列值的組合

MK_CONTROL 當CTRL鍵按下時MK_LBUTTON 當滑鼠左鍵按下時MK_MBUTTON 當滑鼠中鍵按下時(滾動不屬於按下)MK_RBUTTON 當滑鼠右鍵按下時.MK_SHIFT 當SHIFT按下時。

point說明:滑鼠的X,Y座標:該座標為滑鼠相對所在視窗左上方為基點的位置,是一個相對位置而不是在螢幕像素上的絕對位置。

 

afx_msg BOOL OnMouseWheel( UINT nFlags, shortzDelta, CPointpt );

nFlags同上

zDelta:大於0時為向上滾動,小於0時為向下滾動。A value less than zero indicates rotating back (toward the user) while a value greater than zero indicates rotating forward (away from the user). Windows下通常向上滾動縮小/視窗上移,反之放大/下移

pt::滑鼠的X,Y座標,是以其父視窗的左上方為基點的。Specifies the x- and y-coordinate of the cursor. These coordinates are always relative to the upper-left corner of the window.

 

3. 移動的效果實現

要實現移動,例如滑鼠左鍵拖動butoon/圖片在視窗上移動,實現的結果附加要求:滑鼠放在button/圖片的A點,移動之後,滑鼠點依然在A點上

我們通過

a. 檢測滑鼠已在button/圖片上(確保不是在哪都可以移動表徵圖),並且左鍵按下

b. 記錄滑鼠當前點和上個點,計算兩個的位移值,然後使用這個位移值來移動button/圖片(MoveWindows)

(記錄上個點的方法可以使用靜態變數,移動完畢後,把當前點賦值給靜態變數)(具體實現可以靈活處理)

實現原理是:相對靜止---滑鼠和對象相對位置不變,滑鼠的位移量,就是我們對象的位移量

 

4. 縮放的效果實現(以滑鼠點為中心縮放)

要實現縮放,例如中件滑輪向上滑動縮小,向下滑動放大button/圖片,實現附加要求:滑鼠放在button/圖片的A點,縮放之後,滑鼠點依然在A點上,縮放是以滑鼠點為中心

a. 同樣檢測滑鼠已在button/圖片上(確保不是在哪都可以縮放button/圖片)

b. 擷取當前button/圖片的高和寬(使用getClientRect)

c. 擷取當前pt點x,y相對於button/圖片位置,然後計算該位置相對於寬和高的比值

d. 判斷zDelta正負確定放大縮小(按比例調整圖片高度和寬度),並調整圖片左上點(left,top)的位置,確保c中的比值不變(---確保了以滑鼠所在點為中心放大或縮小)

實現原理是:相對移動---滑鼠和所在對象點位置不變,滑鼠所在對象點的周圍 長和寬 成比例的縮放

 

 

滑鼠事件

 

 

在日常用到的很多軟體裡,當滑鼠停留在某個菜單或者按鈕上一定事件,會彈出關於這個空間的一些提示資訊,提示資訊可以利用MFC中的CToolTipCtrl 類來實現,輸出提示並不難,但是如何判斷滑鼠停留在某個按鈕上呢?可以在對話方塊中響應WM_SETCOUSE訊息,在響應事件中判斷髮生事件的視窗控制代碼是不是該控制項控制代碼,如果是做出響應的操作即可,但是如果要判斷游標離開控制項,則相對複雜一點。因為游標離開控制項後,接收滑鼠移動訊息的視窗控制代碼肯定不是該控制項控制代碼了,也可以解決,如下:

BOOLCMy12Dlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)

{

         if(pWnd->GetDlgCtrlID() == IDC_BUTTON3)

         {

                   pWnd->SetWindowTextW(_T("Hover"));

         }

         else if(pWnd->GetDlgCtrlID() != IDC_BUTTON3)

         {

                   GetDlgItem(IDC_BUTTON3)->SetWindowTextW(_T("Leave"));

         }

         returnCDialogEx::OnSetCursor(pWnd, nHitTest, message);

}

(註:這樣做,當滑鼠快速的移動的時候,就有可能出現滑鼠已經離開了按鈕,但按鈕還是顯示滑鼠停留在上面的現象。)

但是如果這樣的控制項不止一個的時候,難道要用n個else if去判斷該控制代碼是不是對應的控制項控制代碼嗎?這樣做就有點不合理了,有沒有更好的解決辦法呢?

經過實驗,以下方法可行且相對來說最好:

從Cbutton派生子類MyHoverBtn,在子類中響應WM_MOUSEMOVE事件,在該事件的響應函數中添加如下代碼來響應滑鼠的Hover和Leave事件:

void MyHoverBtn::OnMouseMove(UINT nFlags, CPointpoint)

{

         TRACKMOUSEEVENT mouse_event;//定義滑鼠移動事件結構體

         mouse_event.cbSize = sizeof(mouse_event);//定義結構體大小

         mouse_event.hwndTrack = m_hWnd;//關聯視窗控制代碼

         mouse_event.dwFlags = TME_HOVER |TME_LEAVE;//設定響應標記

         mouse_event.dwHoverTime = 100/*HOVER_DEFAULT=400*/;//設定Hover的時間

         _TrackMouseEvent(&mouse_event);

 

         CButton::OnMouseMove(nFlags, point);

}

然後在子類MyHoverBtn中響應WM_MOUSEHOVER和WM_MOUSELEAVE訊息,並在相應的事件響應函數中添加實現代碼;例如

void MyHoverBtn::OnMouseLeave()

{

         this->SetWindowTextW(_T("我離開了~"));

         CButton::OnMouseLeave();

}

 

 

void MyHoverBtn::OnMouseHover(UINT nFlags, CPointpoint)

{

         this->SetWindowTextW(_T("我來了~"));

         CButton::OnMouseHover(nFlags, point);

}

 

網上有人說可以在對話方塊中重載PreTranslateMessage函數,判斷訊息類型和控制項控制代碼,如果訊息是WM_MOUSEMOVE,且該事件發生的控制項控制代碼就是你要控制的控制項控制代碼,則做出響應的處理,代碼如下:

BOOLCMy12Dlg::PreTranslateMessage(MSG* pMsg)

{

         CWnd* pWnd = GetDlgItem(IDC_BUTTON1);

         if(pMsg->hwnd == pWnd->GetSafeHwnd() && pMsg->message ==WM_MOUSEMOVE)

         {

                   CPoint point(pMsg->pt);

                   pWnd->ScreenToClient(&point);

                   CRect rect;

                   pWnd->GetClientRect(&rect);

                   if(rect.PtInRect(point))

                            pWnd->SetWindowTextW(_T("Hover"));

                   else

                            pWnd->SetWindowTextW(_T("Leave"));

                   returnTRUE;

         }

         returnCDialogEx::PreTranslateMessage(pMsg);

}

請注意綠色部分,這裡不合理,因為當游標離開按鈕控制項後,滑鼠移動的事件目標控制項就不是該按鈕了,與文章開頭的方法是一樣的,需要另外判斷···

說了幾種方式,還是派生子類,然後在子類中響應滑鼠移動訊息,從而做出對應操作最好。但是在設定Hover的時間的時候如果按照預設的HOVER_DEFAULT設定,也就是時間是400毫秒,那麼滑鼠移動到控制項上面後需要等待這個時間才會響應OnMouseHover(),於是我將時間減小為100毫秒,比較合理了,如下:

       mouse_event.dwHoverTime = 100/*HOVER_DEFAULT=400*/;//設定Hover的時間

就是不懂如果將時間設定到很小,會不會導致程式不斷的提取滑鼠移動訊息,導致CPU佔用增加呢?

經測試將時間設定為1毫秒,相對與設定為100毫秒,cpu也不會大幅增加,MSDN對該參數的解釋如下:

dwHoverTime

Specifiesthe hover time-out (if TME_HOVER was specified in dwFlags), in milliseconds.Can be HOVER_DEFAULT, which means to use the system default hover time-out.

 

視窗重繪方面:

Invalidate()使視窗地區無效,以等待下一次重繪WM_PAINT訊息將在訊息佇列為空白時發送。與之類似的還有InvalidateRect(),可指定重繪具體的矩形地區。

UpdateWindow() 強制立即更新視窗,在OnPaint()函數中可以用GetUpdateRect()確定重繪地區或者判斷是否需要重繪。

RedrawWindow與UpdateWindow類似,強制重繪視窗,但是它提供了更多的參數以設定重繪的地區等

在重繪時,需調用BeginPaint()來準備好用於繪畫的windows裝置環境,填充 PAINTSTRUCT結構,並將DC控制代碼返回用於重繪。

繪畫結束時,需調用EndPaint()來釋放裝置控制代碼。

MFC的OnMouseMove移動位置和OnMouseWheel縮放實現

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.