Правильный метод перерисовки многослойного окна

У меня есть окно, созданное с 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(...);
}
Другие вопросы по тегам