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