• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            小步慢跑

             

            SonicUI 內部定時器實現分析

            SonicUI中有一個內部定時器的概念(InternalTimer),SonicUI中的動畫效果都是使用的這個定時器。這個定時器實現的思路是很清晰的:WM_TIMER消息加定時輪詢。

            首先使用SonicUI的工程都有一個全局的CSonicUI類的實例。在這個類中有一個靜態的成員變量HWND m_hWnd,它指向的是一個 "SonicWnd"的窗口類的窗口實例。此窗口類在CSoinicUI::Init中定義如下:

               1:  
               2: #define MY_WND            _T("SonicWnd")
               3: BOOL CSonicUI::Init()
               4:  
               5: {
               6:     WNDCLASSEX wcex;
               7:     wcex.cbSize = sizeof(WNDCLASSEX);
               8:     wcex.style            = CS_HREDRAW | CS_VREDRAW;
               9:     wcex.lpfnWndProc    = (WNDPROC)CSonicUI::InternalWndProc;
              10:     wcex.cbClsExtra        = 0;
              11:     wcex.cbWndExtra        = 0;
              12:     wcex.hInstance        = NULL;
              13:     wcex.hIcon            = NULL;
              14:     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
              15:     wcex.hbrBackground    = NULL;
              16:     wcex.lpszMenuName    = NULL;
              17:     wcex.lpszClassName    = MY_WND;
              18:     wcex.hIconSm        = NULL;
              19:     if(!RegisterClassEx(&wcex))
              20:     {
              21:         return FALSE;
              22:     }
              23:     HMODULE hMod = GetModuleHandle(_T("User32.dll"));
              24:     if(hMod == NULL)
              25:     {
              26:         return FALSE;
              27:     }
              28:     m_pOldBeginPaint = ReplaceFuncAndCopy(GetProcAddress(hMod, "BeginPaint"), MyBeginPaint);
              29:     m_pOldEndPaint = ReplaceFuncAndCopy(GetProcAddress(hMod, "EndPaint"), MyEndPaint);
              30:     if(m_pOldEndPaint == NULL || m_pOldEndPaint == NULL)
              31:     {
              32:         return FALSE;
              33:     }
              34:     return TRUE;
              35: }

             

            這個窗口始終是不可見的,但SonicUI通過他來實現內部消息的轉發,定時器消息就是在 這個窗口類的消息處理函數(InternalWndProc)中處理的。m_hWnd成員變量是在CSonicUI::GetSonicUI ()中被賦值的。代碼如下:

               1: ISonicUI * GetSonicUI()
               2: {
               3:     BOOL bRet = FALSE;
               4:     if(CSonicUI::m_hWnd == NULL)
               5:     {
               6:         // Initialization
               7:         __try
               8:         {            
               9:             // 省略
              10:         }
              11:         __finally
              12:         {
              13:             if(bRet)
              14:             {
              15:                 //創建了全局唯一的不可見窗口,用于轉發內部消息
              16:                 CSonicUI::m_hWnd = CreateWindow(MY_WND, NULL, WS_POPUP, 0, 0, 1, 1, NULL, NULL, NULL, NULL);
              17:                 g_UI.CreateTip();
              18:                 
              19:                 //開啟了一個 10ms定時器,相當于每隔10ms就輪詢下當前是否有定時器到期
              20:                 SetTimer(CSonicUI::m_hWnd, TIMER_BASE_DATA, GIF_INTERVAL, NULL);
              21:             }
              22:         }
              23:     }
              24:     else
              25:     {
              26:         bRet = TRUE;
              27:     }
              28:     if(!bRet)
              29:     {
              30:         return NULL;
              31:     }
              32:     return &g_UI;
              33: }

            可見,當SonicUI第一次初始化后就開始了一個10ms間隔的定時器。那這個定時器如何使用呢?看一下設置、刪除定時器的代碼。在 ISonicBaseData 類中。代碼如下:

               1: typedef list<ISonicBaseData *> LIST_BASE_DATA;
               2: class ISonicBaseData
               3: {
               4: public:
               5:     //刪除了和定時器不相關的代碼
               6:  
               7:     typedef map<int, DWORD> INTERVAL_TO_TIMER; //定時器間隔和定時器id的map,注意一個定期是間隔可能關聯著多個定時器ID
               8:  
               9:     void   OnInternalTimer();//全局的窗口的的輪詢周期(10ms)到達如果當前類中設置了定時器,此方法會被調用
              10:     virtual void SetInternalTimer(DWORD dwTimerId, int nInterval, BOOL bOnceTimer = FALSE);//設置定時器,注意 dwTimerId 的定義
              11:     virtual void KillInternalTimer(DWORD dwTimerId);
              12:     virtual BOOL QueryInternalTimer(DWORD dwTimerId);//查看當前是否設置了dwTimerId的定時器
              13:     virtual void ClearInternalTimer();//刪除所有的定時器
              14:     virtual void OnInternalTimer(DWORD dwTimerId); //dwTimerId 對應的定時周期到達
              15:  
              16:     DWORD m_dwTimer;      // 從第一次設置定時器起到現在止一共有多少毫秒
              17:     DWORD m_dwTimerOnce; //保存所有一次性定時器的定時器ID
              18:     DWORD  m_dwTimerId;      // 保存當前的所有定時器ID,使用 位掩碼
              19:     INTERVAL_TO_TIMER m_mapIntervalToTimer;
              20:     HWND m_hWnd;    
              21:     static LIST_BASE_DATA m_TimerList; //靜態成員,類似全局變量的作用,保存了當前所有設置了定時器的 ISonicBaseData 的實例
              22: };

            由于 ISonicBaseData 是SonicUI中所有控件的基類,這意味這SonicUI所有的控件都支持內部定時器。目前我們看到了兩個全局變量(類似于全局變量):可以每10ms產生一個wm_timer消息的 sonicui對象和記錄的所有申請了定時器的控件對象(ISonicBaseData 的子類)。SonicUI的定時器機制是這樣的:每一個輪詢周期(10ms)到達,sonicui對象 就問每一個ISonicBaseData 對象,“又過去10ms了,你有沒有定時器到期啊?”,ISonicBaseData  就看自己內部申請的定時器中有沒有到期的,如果有的話,他就執行這個定時器(調用OnInternalTimer(DWORD dwTimerId))。

            接下來要了解的有兩個問題:

            • ISonicBaseData怎么維護的定時器ID的?SonicUI的內部定時器的ID定義如下:
               1:  
               2: #define TIMER_SHOWING_GENTLY       0x1
               3: #define TIMER_MOVE_GENTLY          0x2
               4: #define TIMER_FRAME                0x8    
               5: #define TIMER_TRANSFORM            0x10
               6: #define TIMER_SLIDE                0x20
               7: #define TIMER_TRACK_MOUSE          0x40
               8: #define TIMER_SHUTTER              0x80

            不難看出這是win32api中常用的“按位設置值”(這個不知道怎么說,掩碼?)的定義方法。可以使用一個DWORD來表示多個定時器的ID,對定時器ID的增刪查就可以用下面的語句完成:

               1: //定義了一個定時器
               2: DWORD dwTimerID = TIMER_SHOWING_GENTLY;
               3: //增加一個定時器
               4: dwTimerID  |= TIMER_MOVE_GENTLY;
               5: //刪除一個定時器
               6: dwTimerID   &= ~TIMER_MOVE_GENTLY;
               7: //查詢一個定時器是否存在
               8: BOOL bExist = dwTimerID&TIMER_MOVE_GENTLY;
            •   如何判斷一個定時器是否到期?

                這個問題的答案就是 ISonicBaseData的m_dwTimer變量。它記錄了從上次 增加定時器到現在的總時長(單位毫秒)。每當調用SetInternalTimer是就把他清零(這個會影響當前已經設置了的定時器),當全局的輪詢周期到達就把m_dwTimer加10毫秒,然后看m_dwTimer是內部哪個定時器的周期的整倍數,是就代表這個定時器到期了,否則就是沒到期,等下一個輪詢周期的到來。因此m_dwTimer的取值總是10的倍數,而內部定時器的周期也必須是10的倍數。SonicUI中幾種內部定時器的周期定義如下:

               1: // internal timer defined must be times of base interval
               2: #define BASE_INTERVAL            10
               3: #define ANIMATION_INTERVAL        20
               4: #define GIF_INTERVAL            10
               5: #define FADEOUT_INTERVAL        50

             

            可見,SonicUI的定時器精度并不高,但相比較 CreateTimerQueueTimer 避免了多線程。

            posted on 2012-08-29 17:42 zaccheo 閱讀(701) 評論(0)  編輯 收藏 引用 所屬分類: C++ win32/MFC

            導航

            統計

            常用鏈接

            留言簿

            隨筆分類(23)

            隨筆檔案(26)

            文章分類(1)

            文章檔案(1)

            csdn

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久国产成人午夜aⅴ影院| 亚洲一本综合久久| 亚洲AV无码久久| 狠狠色丁香婷综合久久| 精品无码久久久久久国产| 亚洲人成电影网站久久| 伊人久久综合无码成人网| 国产高潮国产高潮久久久91 | 精品亚洲综合久久中文字幕| 青青草原综合久久| 久久精品国产男包| 亚洲午夜精品久久久久久人妖| 深夜久久AAAAA级毛片免费看| 久久99国产亚洲高清观看首页| 欧美激情精品久久久久久久 | 国产999精品久久久久久| 欧美与黑人午夜性猛交久久久| 国产精品久久久久AV福利动漫| 亚洲国产精品无码久久久久久曰| 国产91久久精品一区二区| 狠狠色丁香婷婷久久综合| 99久久夜色精品国产网站| 亚洲va中文字幕无码久久不卡| 亚洲精品美女久久久久99小说| 狠狠色综合网站久久久久久久 | 国内精品久久久久久野外| 久久婷婷人人澡人人爽人人爱 | 久久精品国产亚洲AV不卡| 久久精品国产亚洲av日韩| 亚洲va国产va天堂va久久| 亚洲?V乱码久久精品蜜桃| 狠狠色综合网站久久久久久久| 久久久久久a亚洲欧洲aⅴ| 成人久久精品一区二区三区| 性做久久久久久久| 亚洲中文字幕久久精品无码APP| 久久婷婷五月综合色奶水99啪| 性做久久久久久久久老女人| 欧美亚洲国产精品久久久久| 蜜桃麻豆WWW久久囤产精品| 久久亚洲国产最新网站|