Правильный метод перерисовки многослойного окна
У меня есть окно, созданное с WS_EX_LAYERED
стиль окна В настоящее время я рисую на растровое изображение памяти, используя GDI+, и использую UpdateLayeredWindow
обновить графическое содержимое моего многослойного окна. Я намерен использовать это окно в качестве основного окна моего приложения, что потребовало бы его частой перерисовки.
Видя, как многослойные окна не получают WM_PAINT
Windows сообщение [?], мне нужно придумать соответствующий метод для перерисовки окна. Оптимизация не обязательна, но всегда приятно иметь свой пирог и есть его. Поэтому я нахожусь в поиске "правильного" метода для использования.
Вот мои мысли до сих пор:
Я предполагаю, что это хорошая идея, чтобы сделать рендеринг на растровое изображение вне экрана, прежде чем
BitBlt
или аналогичный.60 кадров в секунду должно быть (больше чем?) Достаточно (но как это сравнить с частотой кадров других приложений?).
Возможные решения:
использование
SetTimer
отправитьWM_TIMER
сообщение на регулярной основе.Полезно, потому что, указав значение тайм-аута, я могу достичь желаемых кадров в секунду, не требуя измерения длительности, в течение которой "визуализируется" кадр.
Скорее всего, будет причиной ввода или других задержек из-за частоты и скорости сообщений.
Рендеринг кадров только тогда, когда происходят определенные события, такие как изменение размера окна.
Требуется, чтобы я выяснил все события, которые потребуют перерисовки.
Значительно уменьшит количество ненужных кадров.
Рендеринг кадров, когда в очереди сообщений нет сообщений, проверяя
PeekMessage
,Это может замедлить обработку оконных сообщений.
Это приведет к высокой загрузке ЦП, поскольку обрабатывается больше кадров, чем необходимо.
Создайте новый поток для выполнения цикла рендеринга.
- Расчет времени должен быть выполнен, чтобы поддерживать постоянную частоту кадров.
2 ответа
Многослойные окна не получают WM_PAINT
сообщения, которые в противном случае будут сгенерированы после изменения видимости окна, но это не помешает им вообще получить это сообщение.
Вы можете продолжать использовать InvalidateRect
чтобы изменить регион обновления окна, дождитесь WM_PAINT
в вашей оконной процедуре нарисуйте содержимое в растровом изображении и вызовите UpdateLayeredWindow
изменить содержимое окна. Вы можете использовать этот метод для запроса перерисовки при изменении содержимого окна, например, когда была нажата кнопка или размер окна был изменен (или активирован / деактивирован).
Это не должно быть так сложно, это псевдокод для вашего цикла сообщений:
while (true)
{
// GetMessages
while (PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&msg, hWnd, 0, 0 ))
{
// Need to handle WM_QUIT
...
break;
}
TranslateMessage( &msg );
DispatchMessage( &msg );
}
// Check if we need to draw
if (TimeForANewFrameHasCome() ||
IfWeNeedToDrawAfterInputOrInvalidate() ||
AnyOtherCaseThatCausesAnUpdate())
{
// Render
UpdateMemoryDCOrBitmap(...);
// Display it
UpdateLayeredWindow(...);
}
// May sleep a while
// Either Sleep(20); or better MsgWaitForMultipleObjects, that makes it possible
// to wake up upon an Event too...
MsgWaitForMultipleObjects(...);
}