Проблема, которая у меня есть, кажется тривиальной, но я не могу найти способ ее решить.Вот.У меня есть окно с графикой.
Для простоты, скажем, это сплошной зеленый прямоугольник, который заполняет всю клиентскую область окна.Я хочу, чтобы этот прямоугольник перерисовывался и заполнял все окно каждый раз, когда окно меняет свой размер.Первоначально я сделал это.Я отправил WM_PAINT сообщение от обработчика WM_SIZE .
Это работает, но если я быстро перемещаю мышь, я вижу немного неокрашенной (белой) области вокруг зеленого прямоугольника (на самом деле только одна или две стороны, рядом с тем местом, где находится мышь).Мое понимание проблемы состоит в том, что системный поток, который обрабатывает пользовательский ввод (мышь), работает быстрее, чем мой обработчик сообщения WM_PAINT.Это означает, что к тому времени, когда я начинаю рисовать обновленный прямоугольник (его размер взят из WM_SIZE), мышь фактически немного перемещается, и система рисует новую рамку окна, которая отличается от того, что я пытаюсь заполнить зеленым цветом.Это создает незаполненные области рядом с границами, которые перемещаются во время изменения размера.
Когда я прекращаю изменение размера, зеленый цвет в конечном итоге заполняет все окно, но во время изменения размера возникает небольшое мерцание вблизи границ, что раздражает.Чтобы решить проблему, я попробовал следующее.
bool finishedPainting;
RECT windowRect;
case WM_PAINT :
// ..... painting here
finishedPainting = TRUE;
break;
case WM_SIZE :
// .... some actions
// posting WM_PAINT
InvalidateRect(hWnd, NULL, FALSE);
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case WM_SIZING :
// this supposedly should prevent the system from passing
// new window size to WM_SIZE
if (!finishedPainting) memcpy((void*)lParam, &windowRect, sizeof(windowRect));
else {
// remember current window size for later use
memcpy(&windowRect, (void*)lParam, sizeof(windowRect));
finishedPainting = FALSE;
}
return TRUE;
Это не работает.В качестве небольшого изменения я тоже попробовал это.
bool finishedPainting;
POINT cursorPos;
case WM_PAINT :
// ..... painting here
finishedPainting = TRUE;
break;
case WM_SIZE :
if (!finishedPainting) SetCursorPos(cursorPos.x, cursorPos.y);
else {
finishedPainting = FALSE;
GetCursorPos(&cursorPos);
// .... some actions
InvalidateRect(hWnd, NULL, FALSE);
PostMessage(hWnd, WM_PAINT, 0, 0);
}
break;
Это тоже не работает.Насколько я понимаю, решение проблемы заключается в том, чтобы каким-то образом замедлить работу мыши, чтобы она переместилась в следующую позицию на экране (перетаскивая за нее угол или сторону окна) только после завершения рисования.
Есть идеи, как этого добиться?Или, может быть, что-то в корне неверно в том, как я вижу проблему, и решение лежит где-то еще?
// ====================================================
Обновление
Я провел несколько экспериментов и здесьэто то, что я нашел
1) При изменении размера, последовательность сообщений WM_SIZING - WM_NCPAINT - WM_SIZE - WM_PAINT.Это выглядит немного странно для меня.Я ожидал бы, что WM_SIZE будет следовать за WM_SIZING без прерывания WM_NCPAINT
2) В каждом обработчике сообщений я проверял ширину окна во время изменения размера (для простоты я только изменял ширину).Удивительно, но ширина, измеренная в WM_SIZE, оказалась отличной от ширины в WM_SIZING, но такой же, как в WM_NCPAINT и WM_PAINT.Это не проблема как таковая, просто странный факт.
3) Я пришел к выводу, что есть две основные причины мерцания, возникающие у границ окна.Во-первых, WM_NCPAINT предшествует WM_PAINT.Представь, что ты растягиваешь свое окно.Сначала появится новый кадр (первым идет WM_NCPAINT), затем WM_PAINT заполняет клиентскую область.Человеческий глаз ловит тот короткий промежуток времени, когда новый кадр уже находится на экране, но он пуст.Даже если вы укажете, что не хотите, чтобы фон окна удалялся перед перекрашиванием, вновь добавленная область пуста, и вы можете увидеть ее за доли секунды.Эту причину мерцания лучше всего продемонстрировать, когда вы берете правый край окна и быстро перемещаете его вправо.Другая причина мерцающего эффекта менее очевидна и лучше всего видна, когда вы берете левый край окна и перемещаете его влево.Во время этого движения вы увидите незаполненные области по правому краю.Насколько я понимаю, эффект вызван этим.Когда пользователь выполняет изменение размера, Windows делает следующее: A) отправляет WM_NCPAINT, чтобы нарисовать новый фрейм, B) копирует содержимое старой клиентской области в новый левый верхний угол окна (в нашем случае он перемещается влево),В) он отправляет WM_PAINT для заполнения новой клиентской области.Однако на этапе B по какой-то причине Windows создает эти незаполненные области по правому краю, хотя кажется, что этого не должно быть, потому что старый контент должен просто оставаться там, где он есть, пока он не будет перекрашен во время WM_PAINT.
OkОстается вопрос - как избавиться от этих артефактов при изменении размеров.Насколько я сейчас вижу, это невозможно сделать, используя стандартные методы и функции, потому что они вызваны последовательностью шагов, которые Windows выполняет во время изменения размера.Поменять местами WM_NCPAINT и WM_PAINT, вероятно, было бы невозможно, но, похоже, это вне нашего контроля (если нет простого способа сделать это, о котором я просто не знаю).