前言
定時器是win32編程中常用的制作動畫效果的手段。在Win32編程中,可以使用::SetTimer來創建定時器,定時器消息會被會發到調用SetTimer時指定的HWND。
在SOUI中一般來說只有一個宿主窗口有HWND,所有的SWindow都屬於一個宿主窗口,如此一來直接使用::SetTimer創建的定時器就難以直接分發到SWindow對象了。
在SOUI的控件中使用定時器
為了能夠方便的在SWindow中使用定時器,在SOUI系統中,我們通過將定時器ID(共32位)按位進行分解:
class SOUI_EXP STimerID { public: DWORD Swnd:24; //窗口句柄,如果窗口句柄超過24位范圍,則不能使用這種方式設置定時器 DWORD uTimerID:7; //定時器ID,一個窗口最多支持128個定時器。 DWORD bSwndTimer:1; //區別通用定時器的標志,標志為1時,表示該定時器為SWND定時器 STimerID(SWND hWnd,char id) { SASSERT(hWnd<0x00FFFFFF && id>=0); bSwndTimer=1; Swnd=hWnd; uTimerID=id; } STimerID(DWORD dwID) { memcpy(this,&dwID,sizeof(DWORD)); } operator DWORD &() const { return *(DWORD*)this; } };
低24位用來存儲SWindow的窗口ID(swnd)。swnd是一個SWindow創建序號,在一個應用中,通常很難產生超過0xFFFFFF(16777215)個窗口對象,因此使用低24位來存儲窗口ID在大部分情況下都是夠用的了。
高8位中保留最高位設置為1,用來區別直接使用::SetTimer創建的定時器(不可以把最高位置1)。
剩下7位用於SWindow中作為定時器ID。因此在SOUI中,一個SWindow最多可以創建0-127個定時器。
創建定時器:
SWindow::SetTimer(0~127);
/** * SWindow::SetTimer * @brief 利用窗口定時器來設置一個ID為0-127的SWND定時器 * @param char id -- 定時器ID * @param UINT uElapse -- 延時(MS) * @return BOOL * * Describe 參考::SetTimer */ BOOL SWindow::SetTimer(char id,UINT uElapse);
銷毀定時器:
SWindow::KillTimer;
/** * KillTimer * @brief 刪除一個SWND定時器 * @param char id -- 定時器ID * @return void * * Describe */ void KillTimer(char id);
響應定時器消息:
在消息映射表中使用MSG_WM_TIMER_EX。參見:SGifPlayer.h
SOUI_MSG_MAP_BEGIN() MSG_WM_TIMER_EX(OnTimer) //定時器消息 MSG_WM_PAINT_EX(OnPaint) //窗口繪制消息 MSG_WM_SHOWWINDOW(OnShowWindow)//窗口顯示狀態消息 SOUI_MSG_MAP_END()
如果在一個窗口中必須要創建使用32位的定時器ID,在SOUI中可以使用另一個接口來實現:
/** * SetTimer2 * @brief 利用函數定時器來模擬一個兼容窗口定時器 * @param UINT_PTR id -- 定時器ID * @param UINT uElapse -- 延時(MS) * @return BOOL * * Describe 由於SetTimer只支持0-127的定時器ID,SetTimer2提供設置其它timerid * 能夠使用SetTimer時盡量不用SetTimer2,在Kill時效率會比較低 */ BOOL SetTimer2(UINT_PTR id,UINT uElapse); /** * KillTimer2 * @brief 刪除一個SetTimer2設置的定時器 * @param UINT_PTR id -- SetTimer2設置的定時器ID * @return void * * Describe 需要枚舉定時器列表 */ void KillTimer2(UINT_PTR id);
響應定時器:
使用SWindow::SetTimer2創建的定時器,最后會通過一個消息:WM_TIMER2來分發到SWindow。
#define WM_TIMER2 (WM_USER+5432) //定義一個與HWND定時器兼容的SOUI定時器 #define MSG_WM_TIMER2(func) \ if (uMsg == WM_TIMER2) \ { \ SetMsgHandled(TRUE); \ func(wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ }
在應用程序中使用定時器
前面兩種定時器都是在控件開發的時候使用定時器的方法。而在應用層,還可以為宿主窗口直接使用::SetTimer或者宿主窗口的基類:CSimpleWnd::SetTimer來創建定時器(注意最高位必須是0)。
在響應這類定時器時,一樣可以在宿主窗口的消息映射表中使用MSG_WM_TIMER來響應定時器消息。但是需要注意的是,這個映射宏會截獲所有分發給宿主窗口的定時器,如果不是自己創建的定時器,則需要繼續交給基類處理。
可以調用:SetMsgHandled(FALSE); 或者:SHostWnd::OnTimer(UINT_PTR idEvent);實現。