Чтобы полностью избежать мерцания, вам нужно будет завершить все рисование в интервале между обновлениями экрана. Windows не предоставляет никаких простых средств для выполнения этого при обычном рисовании окон (Vista предоставляет составное рисование через DWM, но на это нельзя положиться даже в системах под управлением Vista). Следовательно, лучшее, что вы можете сделать, чтобы минимизировать мерцание, - это рисовать все как можно быстрее (уменьшить разрыв, увеличивая ваши шансы на завершение всего рисования в цикле обновления), и избегать перерисовки (рисование части screen, а затем нарисовать что-то еще поверх: рискует представить пользователю частично нарисованный экран).
Давайте обсудим представленные здесь техники:
Ничего не делать OnEraseBkgnd (): помогает избежать чрезмерного рисования, предотвращая заполнение недействительной области окна цветом фона окна. Полезно, когда вы будете снова рисовать всю область во время WM_PAINT обработки в любом случае, как в случае рисования с двойной буферизацией ... но см. Примечания по предотвращению перерисовки предотвращая рисование после вашего WM_PAINT метода.
Возвращение NULL для OnCtlColor (): на самом деле это не должно делать ничего ... если у вас нет дочерних элементов управления в вашей форме. В этом случае см. Примечания по предотвращению перерисовки путем предотвращения рисования после вашего WM_PAINT метода.
Рисование с двойной буферизацией: помогает избежать разрывов (а также потенциально перерисовки) за счет сокращения фактического рисования на экране до одного BitBLT. Однако это может сократить время, необходимое для рисования: аппаратное ускорение не может использоваться (хотя с GDI + шансы использования любого аппаратного рисования довольно малы), растровое изображение за пределами экрана должно создаваться и заполняться для каждой перерисовки, а все окно необходимо перекрашивать при каждой перерисовке. См. Примечания по эффективной двойной буферизации.
Использование вызовов GDI вместо GDI + для BitBlt: часто это хорошая идея - Graphics::DrawImage()
может быть очень медленным. Я даже обнаружил, что обычный вызов GDI BitBlt()
быстрее на некоторых системы. Поиграйте с этим, но только предварительно попробовав несколько других предложений.
Избегайте стилей классов окон, которые заставляют полностью перерисовывать при каждом изменении размера (CS_VREDRAW, CS_HREDRAW): это поможет, но только если вы этого не сделаете. необходимо перерисовывать все окно при изменении размера.
Примечания по предотвращению перерисовки путем предотвращения рисования до вашего метода WM_PAINT
Когда все или часть окна становится недействительным, оно стирается и перекрашивается. Как уже отмечалось, вы можете пропустить стирание, если планируете перекрашивать всю недопустимую область. Однако, если вы работаете с дочерним окном, вы должны убедиться, что родительские окна также не стирают вашу область экрана. Стиль WS_CLIPCHILDREN должен быть установлен для всех родительских окон - это предотвратит рисование областей, занятых дочерними окнами (включая ваш вид).
Примечания по предотвращению перерисовки путем предотвращения рисования после вашего метода WM_PAINT
Если у вас есть какие-либо дочерние элементы управления, размещенные в вашей форме, вы захотите использовать стиль WS_CLIPCHILDREN, чтобы не рисовать поверх них (и впоследствии не рисоваться ими. Имейте в виду, это несколько повлияет на скорость работы BitBlt.
Примечания по эффективной двойной буферизации
Прямо сейчас вы создаете новое изображение заднего буфера каждый раз, когда представление рисует себя. Для больших окон это может означать выделение и высвобождение значительного объема памяти и приведет к значительным проблемам с производительностью. Я рекомендую сохранить динамически выделяемое растровое изображение в вашем объекте представления, перераспределяя его по мере необходимости, чтобы соответствовать размеру вашего представления.
Обратите внимание, что при изменении размера окна это приведет к тому же количеству выделений, что и в существующей системе, поскольку каждый новый размер потребует выделения нового растрового изображения заднего буфера, чтобы соответствовать ему - вы можете немного облегчить боль, округлив размеры в большую сторону. до следующего по величине числа, кратного 4, 8, 16 и т. д., что позволяет избежать перераспределения при каждом крошечном изменении размера.
Обратите внимание, что если размер окна не изменился с момента последнего рендеринга в задний буфер, вам не нужно повторно рендерить его, когда окно становится недействительным - просто перенесите уже отрендеренное изображение на экран.
Также выделите растровое изображение, соответствующее разрядности экрана. Конструктор для Bitmap
, который вы сейчас используете, по умолчанию будет 32bpp, ARGB-layout; если это не соответствует экрану, то его придется преобразовать. Рассмотрите возможность использования метода GDI CreateCompatibleBitmap()
для получения соответствующего растрового изображения.
Наконец ... Я предполагаю, что ваш пример кода - это просто иллюстративный фрагмент. Но если вы на самом деле ничего не делаете, кроме рендеринга существующего изображения на экран, тогда вам вообще не нужно поддерживать задний буфер - просто Blt прямо из изображения (и заранее преобразуйте формат изображения в соответствовать экрану).
person
Shog9
schedule
14.10.2008