| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Системное программирование и WinAPI > Плавная перерисовка экрана |
| Автор: MironenkoDima 15.6.2013, 03:55 |
| Здравствуйте. Подскажите, пожалуйста, как реализовать плавное обновление экрана в программе. Вся графика выводится с использованием библиотеки GDI+. Программа позволяет перемещаться по рабочей области с помощью зажатия курсора мыши и т.п. манипуляции, при таком подходе экран мерцает при перерисовки. Как это можно преодолеть? |
| Автор: Dem_max 15.6.2013, 06:00 |
| Двойное буфферизирование ????? |
| Автор: Earnest 15.6.2013, 17:25 |
| Т.е. буферизация. Другими словами - рисуем в памяти, дураку полработы не показываем, а показываем все сразу, плюхнув эту память на экран, что, как правило, быстро. Ну и убираем лишние очистки экрана, которые тоже вызывают мерцания. (В виндовсе они по-умолчанию на каждом шагу.) |
| Автор: MironenkoDima 15.6.2013, 17:39 |
| Earnest, спасибо за развёрнутый ответ! Буду копать дальше ) |
| Автор: MironenkoDima 19.6.2013, 18:12 | ||||
| Под руки попалась книжка "Компьютерная графика" Виктора Порева. В ней нашёл кое-что про двойную буферизацию. Рассмотрено такое применение:
Попробовал я сделать подобное в своём проекте:
К сожалению не помогло.. Не подскажите, что можно изменить? |
| Автор: Dem_max 20.6.2013, 03:57 | ||
|
| Автор: Earnest 20.6.2013, 05:00 |
| Не помогло в каком смысле? Не рисуется? По прежнему мерцает? |
| Автор: MironenkoDima 20.6.2013, 18:35 |
Рисует, но по-прежнему мерцает. Dem_max, не совсем понял, в какое место Init и UnInit вставлять? Рабочая область у меня меняется, т.е. пользователь может увеличить/уменьшить размеры. Неужели в WM_SIZE постоянно обрабатывать? И правильно ли я понял, что перед всеми InvalidateRect'ов нужно вызывать функцию DrawStudyExampleToMemory(из вашего примера)? А в WM_PAINT'е оставить только функцию переноса BitBlt ? ----------------------------------- Так-с, попробовал ваш пример. В принципе, мерцаний стало гораздо меньше, только теперь пропала плавность. Изменения происходят с дёрганием |
| Автор: Dem_max 20.6.2013, 19:49 | ||||||||
в начале и конце программы.
Да. И постоянно вызывать UnInit() а потом Init().
WM_PAINT не трогай, что я нарисовал то и вставляй.
нет, не обязательно. InvalidateRect 'bh всего лишь одна из функций которая заставляет вызвать WM_PAINT DrawStudyExampleToMemory() вызывается в любой момент времени после Init() и пока не наступит UnInit() |
| Автор: MironenkoDima 21.6.2013, 00:23 |
| Вставил вызов Init в WM_CREATE, вызов UnInit в WM_DESTROY, пару UnInit+Init в WM_SIZE. Обработку WM_PAINT скопировал из вашего примера. Все прошлые вызовы InvalidateRect заменил на вызов функции, в которой рисуется вся графика, а в конец этой функции поставил InvalidateRect. Как сказал выше, теперь пропала плавность перерисовки.. |
| Автор: Dem_max 21.6.2013, 03:25 | ||
Как может пропасть "плавность" перерисовки если в WM_PAINT только 1 функция и то самая быстрая для переноса графики ????
|
| Автор: MironenkoDima 21.6.2013, 04:05 |
| Попробовал. Сделал rect - глобальной. И поместил GetClientRect в Init. Не помогло.. Может у меня нарушена "общая" логика обновления, но тут я даже не знаю, как можно по-другому. Всякий раз, когда мне нужно обновить экран, вызываю свою функцию рисования. В ней создаётся класс Graphics(gdi+) по дескриптору на контекст граф.устройства, который создаём в памяти(g_hdcMem из примера). Используются различные методы класса Graphics(не мало методов). В конце этой функции находится InvalidateRect.. |
| Автор: Dem_max 21.6.2013, 06:26 |
| Кидай сюда сокращенный код(проект) я посмотрю где накосячил. P.S. ну и расскажи что я должен увидеть и как ты определил что все не плавно. |
| Автор: Earnest 21.6.2013, 07:11 |
| MironenkoDima, за мерцание может отвечать стирание фона. По-умолчанию оно почти всегда есть. Бороться 2 способами: при регистрации класса окна задать нулевую кисть, либо перехватить WM_ERASEBKGND и ничего не делать (и вернуть TRUE... или FALSE... не помню, в MSDN смотри, там написано, чтобы система не лезла). Что касается принципа двойной буферизации, то он таков: на WM_PAINT ты практически всегда ТОЛЬКО копируешь на экран внеэкранный буфер. Рисовать во внеэкранный буфер можно в любой момент (и даже в отдельном потоке). Хотя можно и на PAINT, но совсем не каждый раз, а только при необходимости перерисовать внутренний буфер. Например, если твое окно временно перекрылось другим, при восстановлении буфер перестраивать не нужно. Бывают случаи, когда рисование происходит как бы двумя частями: на относительно постоянном фоне рисуют какие-то детали. Например, у тебя сложный чертеж, а ты добавляешь линию. Или нужно показать какой-то объект выделенным. Очевидно, что в этом случае неэффективно рисовать все целиком, чтобы добавить (или стереть) фрагмент линии. Тогда либо переменную часть рисуют прямо на экран, либо держат 2 буфера. Как-то так. Надеюсь, принцип понятен. |
| Автор: Dem_max 21.6.2013, 10:24 | ||
Сделай так
|
| Автор: Dem_max 21.6.2013, 18:35 |
| Херня какая то, завтра попробую на основе своего контрола попробовать типа как у тебя сделать, посмотрю что выйдет. |
| Автор: Earnest 24.6.2013, 07:13 |
| Dem_max, совет насчет стилей неправильный. Эти флаги отвечают за вызов перерисовки при изменении размеров (что почти всегда полезно), а не за то, КАК перерисовка происходит. MironenkoDima, я уже пару раз писала про стирание фона, что его нужно убрать. Оно вообще не нужно при двойной буферизации. |
| Автор: MironenkoDima 24.6.2013, 18:04 | ||
| Извините, что пропал.. Dem_max, спасибо за пробы! И, конечно, спасибо за приведенный код! Earnest, на счёт стилей: в моём случае это не критично, т.к. в WM_SIZE заново происходит инициализация контекста и последующее обновление экрана. Я наконец прислушался к Вашим словам на счёт стирания фона. Добавил в конец своей функции рисования следующее:
И в итоге получил то, что нужно было изначально! Всем большое спасибо за помощь! Пока остановлюсь на таком варианте! |
| Автор: GremlinProg 25.6.2013, 06:46 | ||||
Вот это жесть! Только ни кому больше не показывайте свой код. Это просто малина для троллей |
| Автор: MironenkoDima 25.6.2013, 15:47 |
| GremlinProg, если вы про всю программу, то спорить не буду) Первый опыт написания подобного, поэтому каждый новый шаг - неизвестность для меня. Приходится изучать так или иначе.. А если про UnInit и Init в WM_SIZE, то это обсуждалось выше.. Ну а UpdateWindow(hwnd) - единственное, что смог придумать. Ибо без него перерисовка с "тормозами", если так можно выразиться. |