很喜歡一些軟件的按鈕:鼠標移進去,就會呈現某種效果(如文字變色、突起顯示等等),移出以
後效果就消失。但是自己動手的時候,卻發現不像自己想象的那樣簡單。其中鼠標移入的效果很容
易實現,使用MouseMove事件就可以了,但是移出呢?要知道Windows裡並沒有鼠標移入移出的消
息呀!(至少我在C++ Builder自帶的Windows API裡翻了遍也沒找著。)以前,我就用了一些取
巧的方法來實現:
1.比如要讓一個按鈕實現移入變色功能,我就在按鈕本身的MouseMove裡寫一句代碼,讓它的顏
色改變,然後在它的容器控件(如Form, Panel等等)的MouseMove裡寫一句代碼,讓它的顏色還
原。毋需多言,這樣的代碼肯定是很煩瑣的,特別是要控制的控件相當多的時候。
2.在每個按鈕的MouseMove事件裡設置按鈕狀態。再使用一個定時器,每隔一段較短的時間檢測
狀態,根據狀態設置顏色。這樣做的好處是改變顏色的代碼段只有一段(在定時器事件裡),而不
像第一種方法一樣在許多地方改變顏色。但代碼依然是很煩瑣的,而且還要浪費一個定時器資源。
最重要的是,以上兩種方法都由控件外部來控制,這樣的話,想做一個實現這種功能的控件是不可
能了。那麼,那些第三方控件的這種功能是怎樣實現的呢?
一個偶然的機會,我看到了一個具有鼠標感知能力(注:我們把這種可以感知鼠標是否在自己上面
的能力叫做鼠標感知能力。)的控件的源代碼。於是就細細研究了起來。
在閱讀了一大堆令人目眩的代碼之後,我發現,它的鼠標感知能力是來自兩條消息:
CM_MOUSEENTER和CM_MOUSELEAVE,但是在它的源代碼中並沒有產生這兩個消息的任何語句。在
Window API幫助裡又查不到這兩條消息。奇怪,難道是微軟不想讓我們知道有這兩個消息?該死
的微軟……,等等!我發現CM_這個前綴並不是微軟的標准前綴(看來錯怪微軟了)。CM是……,
對了,是Custom Message的縮寫!好,這個消息不是控件編寫者自己寫的,也不是微軟提供的,
那麼……。不錯,這是Borland提供的一個用戶定義消息。其聲明在controls.hpp中。好,有了
這兩個消息,問題就好解決了。下面是我編寫的一個簡單的控件,為TSpeedButton增加了
EnterFontColor屬性和OnMouseEnter、OnMouseExit兩個事件。
//附:TexSpeedButton控件的關鍵程序段
//exSpeedButton.h
TexSpeedButton::public TSpeedButton
{
//………………
private:
TColor FEnterFontColor, FOldFontColor;
TNotifyEvent FOnMouseEnter, FOnMouseExit;
protected:
virtual void __fastcall WndProc(TMessage &Message); //重載WndProc方法處理消
息
virtual void __fastcall MouseEnter(void); //鼠標感知的處理函數
virtual void __fastcall MouseExit(void) //定義成虛以便以後繼承
public:
//………………
__publish:
__property TColor EnterFontColor = {read = FEnterFontColor, write
FEnterFontColor, default = clBlue};
__property TNotifyEvent OnMouseEnter = {read = FOnMouseEnter, write =
FOnMouseEnter};
__property TNotifyEvent OnMouseExit = {read = FOnMouseExit, write =
FOnMouseExit};
};
//exSpeedButton.cpp
TexSpeedButton::TexSpeedButton(TComponent *Owner):public TSpeedButton(Owner)
{
FEnterColor = clBlue; //移入顏色缺省為藍色
}
void TexSpeedButton::WndProc(TMessage &Message)
{
TCustomControl::WndProc(Message); //調用祖先類的缺省處理(注:這是4.0版的寫法, 5.0中TCustomControl的WndProc方法已經被隱藏,只能用TControl::WndProc)
if (Message.Msg == CM_MOUSEENTER) //處理CM_MOUSEENTER消息
{
MouseEnter();
Repaint(); //別忘了刷新界面
}
if (Message.Msg == CM_MOUSELEAVE) //處理CM_MOUSELEAVE消息
{
MouseEnter();
Repaint(); //同樣別忘了刷新界面
}
}
void TexSpeedButton::MouseEnter(void)
{
if(FOnMouseEnter) //如果事件處理句柄存在(用戶寫了相應事件)
{
FOnMouseEnter(this); //執行用戶定義的事件
}
else //否則執行缺省處理
{
FOldFontColor = Font->Color;
Font->Color = FEnterFontColor;
}
}
void TexSpeedButton::MouseExit(void)
{
if(FOnMouseEnter) //如果事件處理句柄存在(用戶寫了相應事件)
{
FOnMouseEnter(this); //執行用戶定義的事件
}
else //否則執行缺省處理
{
Font->Color = FOldFontColor;
}
}