После отпускания кнопки мыши полоса прокрутки продолжает прокручиваться

Проблемы

Полоса прокрутки непрерывно прокручивается, даже когда вы отпустите левую кнопку мыши. Тип полосы прокрутки не имеет значения для этой проблемы, то есть проблема возникает, независимо от того, является ли полоса прокрутки частью окна или элементом управления "полоса прокрутки".

Причина

Эта проблема возникает, как правило, при выполнении цикла получения сообщений в результате действий, предпринятых для прокрутки при получении одного из сообщений с уведомлением полосы прокрутки. При прокрутке в 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 () создаются сообщения Paint. Фоновая обработка происходит во время рисования.

  1. При появлении WM_PAINT сообщение выполните указанные ниже действия.

    1. Вызовите BeginPaint ().

    2. Скопируйте недействительный Rect в глобальную переменную Rect (например, grcPaint), которая будет использоваться на этапе 2. Global Rect grcPaint — это объединение ранее полученного значения Rect (grcPaint) и нового недействительного Rect (PS. rcPaint). Код для этого будет выглядеть следующим образом:

               RECT grcPaint;    // Should be initialized before getting the                           // first paint message.            :            :         UnionRect(&grcPaint, &ps.rcPaint,&grcPaint);
    3. Вызовите ValidateRect () с помощью PS. rcPaint.

    4. Вызовите EndPaint ().

    5. Установка таймера.

    Таким образом, больше никаких WM_PAINT сообщений не будет создано, так как в ней нет недопустимых областей и настроен таймер, который будет создавать сообщения WM_TIMER.

  2. После получения сообщения WM_TIMER проверьте глобальную переменную Rect; Если это значение не пустое, сделайте раздел и заполните его. Затем настройте глобальную переменную Rect таким образом, чтобы она больше не включала окрашенную область.

  3. После того как переменная Global Rect будет пустой, запусти таймер.

Пример решения, демонстрирующий 2

Приложению требуется получить данные через DDE или другой механизм из другого приложения, который затем отображается в окне. Для прокрутки приложению необходимо запросить и получить данные из серверного приложения. Существует три разных фильтра, которые можно использовать для настройки PeekMessage () и получения информации. Фильтры можно настроить с помощью параметров uFilterFirst и uFilterLast в PeekMessage (). uFilterFirst указывает сообщение кулачки в проверяемом диапазоне, а 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. WM_LBUTTONUP удаляется из очереди с помощью цикла обработки сообщений, упомянутого в действии 4. После этого WM_LBUTTONUP отправляется.

  6. В результате шага 5 WM_LBUTTONUP сообщение отправляется в другом месте, а цикл получения внутренних сообщений, упомянутый в действии 3, никогда не получит его. Цикл обработки сообщений на этапе 3 ищет WM_LBUTTONUP для прекращения прокрутки. Так как она не получена, полоса прокрутки продолжает прокручиваться.

Нужна дополнительная помощь?

Совершенствование навыков
Перейти к обучению
Первоочередный доступ к новым возможностям
Присоединение к программе предварительной оценки Майкрософт

Были ли сведения полезными?

Спасибо за ваш отзыв!

Благодарим за отзыв! Возможно, будет полезно связать вас с одним из наших специалистов службы поддержки Office.

×