徵狀
即使您放開滑鼠左鍵,捲軸也會持續滾動。 捲軸的類型與此問題無關,也就是說,不論捲軸是視窗的一部分或是捲軸控制項,都會發生相同的問題。
原因
這個問題通常會在接收到其中一個捲軸通知訊息時,因為所採取的動作所產生的動作而執行。滾動時,系統會在 Windows 中啟動內部訊息檢索迴圈。 此郵件迴圈的工作是追蹤滾動,並傳送適當的捲軸通知訊息,WM_HSCROLL 和 WM_VSCROLL。 在收到 WM_LBUTTONUP 之後,就會終止滾動。 如果在滾動期間啟動另一個郵件迴圈,則會透過該訊息迴圈來檢索 WM_LBUTTONUP,而且因為應用程式無法存取捲軸的內部訊息檢索迴圈,WM_LBUTTONUP 無法正確地派單。 因此,內部訊息檢索器永遠不會收到 WM_LBUTTONUP,且滾動永不結束。如果應用程式是滾動,就不需要明確地檢索訊息,就能造成這個問題。 在滾動時,呼叫下列任何函數或處理包含訊息檢索迴圈的任何訊息,都可能導致 WM_LBUTTONUP 遺失。 下面所列的函數屬於這個類別:
DialogBox() DialogBoxIndirect() DialogBoxIndirectParam() DialogBoxParam() GetMessage() MessageBox() PeekMessage()
解決方案
在滾動時,不應從佇列中的任何訊息檢索迴圈(除了捲軸的內部)來檢索 WM_LBUTTONUP 訊息。應用程式可能會在這個問題上遇到,如下所示:
-
應用程式會實現訊息檢索迴圈來實現背景處理,例如,在執行畫圖時進行背景處理。
-
應用程式會實現訊息檢索迴圈,以實現與其他應用程式或 DLL 的通訊。 例如,若要滾動,應用程式必須從其他位置接收資料。
可能的解決方法
下列是兩種可能的解決方法。 第一個因應措施是由許多現有的應用程式和 Windows 所使用;不過,在極少數情況下,第一個因應措施可能不是切實可行的情況。 在這種情況下,可能會使用第二種因應措施。 不過,如果可能的話,請儘量避免在滾動時完全實現郵件檢索。
-
使用計時器-以訊息為基礎的處理。 將複雜的處理分為較小的工作,並追蹤每個任務的開始和結束位置,然後根據計時器訊息執行每項工作。 當處理的所有元件都完成時,請終止計時器。 請參閱下面的因應措施範例。
-
實現郵件檢索迴圈,但請確定它不會透過它來檢索 WM_LBUTTONUP。 這可以透過使用篩選來完成。 如需此因應措施的一些範例,請參閱下面的說明。
示範解決方法1的範例
應用程式有複雜的畫圖程式。 呼叫 ScrollWindow ()來滾動,會產生畫圖訊息。 在進行繪製時,會進行背景處理。
-
當您收到 WM_PAINT 訊息時,請執行下列動作:
-
呼叫 BeginPaint ()。
-
將不正確 rect 複製到要在步驟2中使用的全域 rect 變數(例如,grcPaint)。 全域 rect grcPaint 會是先前取得的 rect (grcPaint)與新的無效矩形(.ps rcPaint)的聯合。 這會與下列程式碼類似:
RECT grcPaint; // Should be initialized before getting the // first paint message. : : UnionRect(&grcPaint, &ps.rcPaint,&grcPaint);
-
使用 rcPaint 呼叫 ValidateRect ()。
-
呼叫 EndPaint ()。
-
設定計時器。
如此一來,不會產生更多 WM_PAINT 的訊息,因為沒有不正確區域,且已設定計時器,這會產生 WM_TIMER 訊息。
-
-
收到 WM_TIMER 訊息時,請核取 [全域 rect] 變數;如果不是空白,請拍攝一個章節並加以繪製。 然後調整全域矩形變數,使其不再包含繪製的區域。
-
全域 rect 變數為空之後,就會終止計時器。
示範解決方法2的範例
應用程式需要透過 DDE 或其他應用程式的其他機制來取得部分資料,然後再顯示在視窗中。 為了進行滾動,應用程式必須要求,然後從伺服器應用程式取得資料。您可以使用三種不同的篩選來設定 PeekMessage ()並取得資訊。 您可以使用 PeekMessage ()的 uFilterFirst 和 uFilterLast 參數來設定篩選。 uFilterFirst 會在要核取的範圍內指定 fist 訊息,uFilterLast 指定要檢查範圍中的最後一封郵件。
-
只檢查並檢索取得所需資料的相關訊息。
-
檢查 WM_LBUTTONUP 但不將它移除會形成佇列;如果是在佇列中,請中斷。 否則,請取回並傳送所有訊息。
-
檢索所有小於 WM_LBUTTONUP 且大於 WM_LBUTTONUP 的訊息,但不會檢索 WM_LBUTTONUP。
其他相關資訊
重現問題的步驟
下列是導致 WM_LBUTTONUP 訊息遺失的事件順序:
-
使用滑鼠按一下捲軸。
-
步驟1產生 WM_NCLBUTTONDOWN 的訊息。
-
步驟2會導致啟動 Windows 內部訊息迴圈。 此訊息迴圈會尋找與捲軸相關的訊息。 此郵件迴圈的目的是產生適當的 WM_HSCROLL 或 WM_VSCROLL 的訊息。 在收到 WM_LBUTTONUP 之後,郵件迴圈和滾動就會終止。
-
當接收 WM_HSCROLL 或 WM_VSCROLL 訊息時,應用程式會直接取得訊息檢索迴圈,或呼叫可導致郵件檢索的函數。
-
在步驟4中提到的訊息迴圈會從佇列中移除 WM_LBUTTONUP。 然後,就會分派 WM_LBUTTONUP。
-
由於步驟 5 WM_LBUTTONUP 訊息會在其他地方派發,而在步驟3中提到的內部訊息檢索迴圈就不會收到它。 步驟3中的訊息迴圈正在尋找停止滾動的 WM_LBUTTONUP。 因為沒有收到,所以捲軸會繼續滾動。