C++技巧之一(MFC)

字號(hào):

在冗長和粒狀的操作中更新窗口時(shí)的一個(gè)典型難題就是窗口閃爍,改變控件內(nèi)容導(dǎo)致反復(fù)重畫控件可見區(qū)域的部分或全部。當(dāng)短時(shí)間內(nèi)這樣的更新大量發(fā)生時(shí),這就成問題了,而且這種反復(fù)重畫是以一種無任何吸引力的可視干擾形式出現(xiàn)的。解決這一難題的兩種常用方法是使用API函數(shù)LockWindowUpdate和WM-SETREDRAW消息。
    LockWindowUpdate通過換出此窗口的正常設(shè)備場景(device context)來實(shí)現(xiàn),以可見區(qū)域?yàn)榭盏拇翱趤硖娲舜翱凇.?dāng)LockWindowUpdate被以NULL呼叫時(shí)(解除窗口鎖定),原來的設(shè)備場景被替換,系統(tǒng)使在它之內(nèi)的與臨時(shí)性的窗口大小和位置相同的一個(gè)區(qū)域失效,這樣窗口將收到一要求以重畫修改的區(qū)域。因此所有的窗口繪制在單一操作中有效完成,而且視覺效果更加無縫。使用LockWindowUpdate的缺點(diǎn)是它一次僅能用于一個(gè)窗口,因此它不能被用來同時(shí)鎖定一批相關(guān)的控件集。呼叫此函數(shù)的第一個(gè)窗口被鎖定,而解除鎖定之前的所有其它呼叫均失敗。(這一點(diǎn)很容易地顯示地被顯示出來,通過測試程序執(zhí)行文件wndscope.cpp的第93行上的運(yùn)行按鈕的未注釋的人工鎖定,wndscope.cpp包括在這個(gè)月的代碼文檔中)。有趣的是,使用LockWindowUpdate的應(yīng)用程序的兩個(gè)版本同時(shí)運(yùn)行 ,看起來,任何一個(gè)呼叫此函數(shù)的過程“擁有”鎖定功能,移去以前成功呼叫的所有權(quán),這還原成為串的閃爍的解除鎖定的行為插入。
    WM-SETREDRAW是被各種標(biāo)準(zhǔn)和自定義控件實(shí)現(xiàn)的消息,這些控件包括列表框(listbox),組合框 (combobox),列表視圖控件(list view),按鈕(button),和tab控件(tab control)。它通過清除和設(shè)置窗口重畫標(biāo)記(flag)工作。的微小缺點(diǎn)是應(yīng)用程序必須在發(fā)送恢復(fù)活動(dòng)的消息之后使窗口矩形失效,因此全部可視窗口矩形將被重畫。WM-SETREDRAW的使用一般取代LockWindowUpdate的使用。當(dāng)然,對于不支持這一消息的窗口,LockWindowUpdate仍然是可選用的工具。
    這里給出WinSTL庫(http://winstl.org/)中的兩個(gè)類—window_update_scope 和 window_redraw_scope—提供鎖定locking的兩種形式的自動(dòng)化作用域。(有所刪節(jié)的實(shí)現(xiàn)部分內(nèi)容見列表1和列表2。 完整的執(zhí)行部分在檔案文件中提供,而在WinSTL站點(diǎn)也可聯(lián)機(jī)獲取)。鎖定在構(gòu)造器constructor中設(shè)定,然后在析構(gòu)器destructor中重置:
    window_update_scope呼叫其constructor中的LockWindowUpdate,如果成功在其析構(gòu)器destructor中呼叫LockWindowUpdate(NULL);window_redraw_scope發(fā)送其constructor中的WM-SETREDRAW (傳遞False)并且發(fā)送WM-SETREDRAW (傳遞True)。它們二者都取得窗口的句柄以在它們的constructors中的鎖定;window_redraw_scope取得第二個(gè)參數(shù)(缺省值為True)以確定當(dāng)未鎖定時(shí)窗口是否失效(通過呼叫InvalidateRect)。
    這兩種技術(shù)的用法在附隨的的應(yīng)用程序(圖表1 )中作了演示,把許多項(xiàng)目發(fā)送到一個(gè)列表框listbox,使用或沒有使用兩種剛剛描述的鎖定技術(shù)。為了顯示技術(shù),簡單地執(zhí)行程序并且選擇“Run”,演示閃爍。然后依次選擇“Use LockWindowUpdate”和“Use WM-SETREDRAW”并運(yùn)行,演示鎖定。