c++ builder裡四種處理“滑鼠離開窗體”事件的方法 (轉)

worldblog發表於2007-12-14
c++ builder裡四種處理“滑鼠離開窗體”事件的方法 (轉)[@more@]

  在處理窗體訊息的時候,我想不少人都會碰到滑鼠離開窗體的訊息(下面稱之為MouseLeave)。在C++ Builder裡,並沒有直接提供處理這種訊息的方法,需要我們自己動手來做。透過參考一些資料,我發現在C++ Builder裡面處理MouseLeave,不外乎以下四種方法,現寫出來供大家參考。如果有什麼不對之處,請指正。

(一)、笨拙的Timer

  每每提到捕捉滑鼠離開窗體的訊息的時候,也許有人就會馬上想到用Timer來處理。不錯,這種方法很簡單,也確實有效。只須在Timer的OnTimer事件中判斷滑鼠所處位置的座標是否在窗體內就可以了,詳細程式碼如下:

void __fastcall TForm1::Timer1Timer(T *Sender)
{
  POINT pt;
  GetCursorPos(&pt);  //得到滑鼠的座標
  RECT rect;
  GetWindowRect(Handle,&rect);  //得到窗體的矩形範圍
  if(!PtInRect(rect,pt))  //判斷滑鼠的座標是否在窗體的矩形範圍內

  Caption="out";
  else
  Caption="in";
}

  為什麼我要說是笨拙的Timer呢?原因有二:其一、OnTimer是優先順序別比較低的訊息,從嚴格意義上講,上面這種做法並不精準。如果正在處理一大堆級別比較高的訊息,那我們就無法及時獲得MouseLeave訊息。其二、Timer是比較寶貴的系統資源,用在MouseLeave上面似乎有些浪費了,因為我們還有更好的方法來做同樣的事情。

(二)、霸道的SetCapture()

  SetCapture()可以讓指定的窗體捕獲所有滑鼠訊息,當然也包括MouseLeave了:

void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,
  int X, int Y)
{
  Caption="in";
  SetCapture(Handle);
  TPoint pt(X,Y);
  TRect rect;
  rect=GetClientRect();
  if (!PtInRect(rect,pt))
  {
  ReleaseCapture();
  Caption="out";
  }
}

 不過這種方法太過於霸道了,因為SetCapture()將所有的滑鼠訊息據為己有。雖然在捕獲了MouseLeave以後已經ReleaseCapture了,但是在捕獲過程中,你卻無法對其他的滑鼠訊息做出反應。不信?你不妨在窗體在多放一個Button,再執行點點看?:)

(三)、受限的TrackMouseEvent()

  MSDN上面說,TrackMouseEvent()可以讓指定的窗體接受WM_MOUSELEAVE訊息。但是在接受訊息以後如果還要繼續接受WM_MOUSELEAVE訊息,必須重新TrackMouseEvent():

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  MouseTrack=false; //TForm1的私有變數,檢測滑鼠是否已經被Track
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WndProc(TMessage& Message)  //過載WndProc
{
  if (Message.Msg==WM_MOUSELEAVE) //在這裡捕獲WM_MOUSELEAVE訊息
  {
  Caption="out";
  MouseTrack=false; //滑鼠Track已經完成
  }
  TForm::WndProc(Message);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,
  int X, int Y)
{
  Caption="in";
  if (!MouseTrack)
  {
  TRACKMOUSEEVENT tt;
  tt.cbSize=sizeof(tt);
  tt.dwFlags=TME_LEAVE;
  tt.hwndTrack=Handle;
  TrackMouseEvent(&tt);
  MouseTrack=true;  //開始滑鼠Track
  }
}
//---------------------------------------------------------------------------

  這種方法很好用,唯一的缺點是可能不支援(具體支不支援我也沒有做過實驗,哪位兄弟有Win98的幫我測試一下)。在的環境下,我推薦用這種方法,:)

(四)、未知的CM_MOUSELEAVE

  在CSDN論壇裡經常看到有人說可以透過捕獲CM_MOUSELEAVE訊息來達到同樣的效果。不過根據我的測試,CM_MOUSELEAVE在控制元件上面工作得很好,可以用來捕獲滑鼠離開控制元件的訊息。但用在窗體上似乎就不靈驗了,可能我自己沒有做對吧。如果有哪位大蝦知道該怎麼用,請告知小弟一聲,我將感激不盡。

以上程式碼均在 Professional+bcb6.0環境中編譯成功。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993083/,如需轉載,請註明出處,否則將追究法律責任。

相關文章