徵狀

即使您放開滑鼠左鍵,捲軸也會持續滾動。 捲軸的類型與此問題無關,也就是說,不論捲軸是視窗的一部分或是捲軸控制項,都會發生相同的問題。

原因

這個問題通常會在接收到其中一個捲軸通知訊息時,因為所採取的動作所產生的動作而執行。滾動時,系統會在 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 ()來滾動,會產生畫圖訊息。 在進行繪製時,會進行背景處理。

  1. 當您收到 WM_PAINT 訊息時,請執行下列動作:

    1. 呼叫 BeginPaint ()。

    2. 將不正確 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);
    3. 使用 rcPaint 呼叫 ValidateRect ()。

    4. 呼叫 EndPaint ()。

    5. 設定計時器。

    如此一來,不會產生更多 WM_PAINT 的訊息,因為沒有不正確區域,且已設定計時器,這會產生 WM_TIMER 訊息。

  2. 收到 WM_TIMER 訊息時,請核取 [全域 rect] 變數;如果不是空白,請拍攝一個章節並加以繪製。 然後調整全域矩形變數,使其不再包含繪製的區域。

  3. 全域 rect 變數為空之後,就會終止計時器。

示範解決方法2的範例

應用程式需要透過 DDE 或其他應用程式的其他機制來取得部分資料,然後再顯示在視窗中。 為了進行滾動,應用程式必須要求,然後從伺服器應用程式取得資料。您可以使用三種不同的篩選來設定 PeekMessage ()並取得資訊。 您可以使用 PeekMessage ()的 uFilterFirst 和 uFilterLast 參數來設定篩選。 uFilterFirst 會在要核取的範圍內指定 fist 訊息,uFilterLast 指定要檢查範圍中的最後一封郵件。

  1. 只檢查並檢索取得所需資料的相關訊息。

  2. 檢查 WM_LBUTTONUP 但不將它移除會形成佇列;如果是在佇列中,請中斷。 否則,請取回並傳送所有訊息。

  3. 檢索所有小於 WM_LBUTTONUP 且大於 WM_LBUTTONUP 的訊息,但不會檢索 WM_LBUTTONUP。

其他相關資訊

重現問題的步驟

下列是導致 WM_LBUTTONUP 訊息遺失的事件順序:

  1. 使用滑鼠按一下捲軸。

  2. 步驟1產生 WM_NCLBUTTONDOWN 的訊息。

  3. 步驟2會導致啟動 Windows 內部訊息迴圈。 此訊息迴圈會尋找與捲軸相關的訊息。 此郵件迴圈的目的是產生適當的 WM_HSCROLL 或 WM_VSCROLL 的訊息。 在收到 WM_LBUTTONUP 之後,郵件迴圈和滾動就會終止。

  4. 當接收 WM_HSCROLL 或 WM_VSCROLL 訊息時,應用程式會直接取得訊息檢索迴圈,或呼叫可導致郵件檢索的函數。

  5. 在步驟4中提到的訊息迴圈會從佇列中移除 WM_LBUTTONUP。 然後,就會分派 WM_LBUTTONUP。

  6. 由於步驟 5 WM_LBUTTONUP 訊息會在其他地方派發,而在步驟3中提到的內部訊息檢索迴圈就不會收到它。 步驟3中的訊息迴圈正在尋找停止滾動的 WM_LBUTTONUP。 因為沒有收到,所以捲軸會繼續滾動。

Need more help?

Expand your skills
Explore Training
Get new features first
Join Microsoft Insiders

Was this information helpful?

How satisfied are you with the translation quality?
What affected your experience?

Thank you for your feedback!

×