Sign in with Microsoft
Sign in or create an account.

徵狀

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

原因

這個問題通常會在接收到其中一個捲軸通知訊息時,因為所採取的動作所產生的動作而執行。滾動時,系統會在 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。 因為沒有收到,所以捲軸會繼續滾動。

需要更多協助?

擴展您的技能
探索訓練
優先取得新功能
加入 Microsoft 測試人員

這項資訊有幫助嗎?

您對語言品質的滿意度如何?
以下何者是您會在意的事項?

感謝您的意見反應!

×