GDI графика в режиме реального времени

Для неординарных вопросов. Если вы опытный программист, попавший в трудную ситуацию, — вам сюда.

Модератор: gaidar

Правила форума
Этот раздел не предназначен для того, чтобы вы адресовали свою проблему профессионалам.
Этот раздел предназначен для профессионалов, которые столкнулись с проблемой и не могут решить ее самостоятельно.
Если вы считаете себя профессионалом, а свою проблему сложной — вам сюда.
Если модератор посчитает, что вы ошиблись, то на первый раз он перенесет ваше сообщение в основной раздел без последствий для автора. Во второй раз тема будет закрыта, а автору будет выписано нарушение. В третий раз автор будет забанен.
Dion
Начинающий
Начинающий
 
Сообщения: 8
Зарегистрирован: 16.03.2008 (Вс) 16:03

GDI графика в режиме реального времени

Сообщение Dion » 13.05.2010 (Чт) 12:17

Уже достаточно давно пишу свой проект. Не буду вдаваться в подробности для чего он предназначен, перейдём к части в которой заключается проблема. А именно: есть PictureBox - так называемый "основной экран", на котором рисуются иконки (32х32), связи (линии), текст и геометрические фигуры. Всё это примерно выглядит как рабочий стол Windows, только иконки соединены линиями. И их может быть до 1000 на экране, и столько же линий. Они могут накладываться друг на друга. Механизм работы приложения достаточно прост, есть функция Redraw (перерисовка), есть массивы структур объектов и связей, которые хранят данные объектов, в том числе позицию на экране, какая именно иконка закреплена за объектом и т.д. В "Редраве" всё это дело рисуется обычным проходом цикла по списку структур.
Примерно это выглядит вот так:
Код: Выделить всё
' [*] Функция Redraw
'// [?] Легенда:
'         - iNumObj: кол-во объектов
'         - iNumLines: кол-во связей

'// Объекты
for i = 1 to iNumObj
GdiTransparentBlt данные из массива объектов(i)
TextOut ...(i) '// подпись объекта
'// + рамка для текста и дополнительные "примочки"
Next i

'// Связи
for i = 1 to iNumLines
MoveToEx ...(i)
LineTo ...(i)
Next i


При каких либо изменениях на экране - вызывается функция и перерисовывает всё, например, при таскании объекта мышкой. Кто-то скажет, что перерисовывать ВСЁ - глупо, особенно если изменения происходят только у одного объекта. Но нет, я пытался реализовать - что, только определённые объекты перерисовываются - например, тот, который перемещается и те которых он задел при перемещении, а также примыкающие и задетые линии. Но, а если объектов 200 и пользователь выделил 50 и таскает их? Получались те же тормоза, и пришлось отказаться от этого!
Вот это она и есть, основная проблема - медленность перерисовки в режиме реального времени.
Однократно это рисуется мгновенно, но при "таскании" объекта мышью (задействовано в событии MouseMove - ПикБокса) идёт непрерывная перерисовка, которая здорово тормозит... Причём, чем больше размер PictureBox - тем больше тормоза, в моём случае он занимает почти весь экран в развёрнутом виде *(минус) меню и панель инструментов.

Исследования:
по началу линии текст и фигуры рисовались обычными средствами VB6... Line, Print... Кроме Иконок, которые изначально рисовались двойным BitBlt (+маска прозрачности), который позже был заменён на GdiTransparentBlt. К сожалению, последняя функция в разы медленней, но по заданию, пользователь может сам добавлять иконки с каналом прозрачности по розовому цвету - пришлось отказаться от BitBlt.
Затем Line и Print - были заменены на их GDI-аналоги. Прироста производительности при этом не было. Убирая всё рисуемое кроме иконок - производительность была очень неплохой. Из чего я сделал вывод, что тормоза происходят из-за линий, фигур и текста. Как с этим бороться?
Необходимо чтобы при перемещении объектов они все двигались плавно и без тормозов.

Посоветуйте, пожалуйста, что можно придумать в данной ситуации? Может, есть смысл использовать DirectDraw - но даст ли это желаемой скорости?

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: GDI графика в режиме реального времени

Сообщение MIT » 13.05.2010 (Чт) 12:33

Когда нет желания улучшать логику, программисты требуют новые технологии. Яркий пример — IE9: все нормальные браузеры нормально обходятся GDIp`ом, а микросовтовцам лень оптимизировать было, они взяли и перенесли все вычисления на видеокарту и всякие там DirectX`ы и пр..
Так и здесь. Если перенести на DirectDraw, то производительность может быть лучше, однака через задницу можно сделать, использую любую технологию и любые средства разработки.

В конкретно твоём случае дело в том, что у тебя выполняется слишком много лишних действий. Например при каждой перерисовке создаются GDIp объекты, которые сразу удаляются и создаются заново, либо же проводятся вычисления, результаты которых можно было бы закешировать. Ну и конечно же перерисовка. Надо, ты верно отметил, перерисовывать только то, что реально требует перерисовки. Использовать Clip области, не отрисовывать то, что не будет обновлено. При этом важно, что бы алгоритм вычисления области перерисовки был оптимальным.

В общем и целом — пересматривай вычислительные алгоритмы.
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

FaKk2
El rebelde gurú
El rebelde gurú
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Re: GDI графика в режиме реального времени

Сообщение FaKk2 » 14.05.2010 (Пт) 6:28

MIT писал(а):Яркий пример — IE9: все нормальные браузеры нормально обходятся GDIp`ом, а микросовтовцам лень оптимизировать было, они взяли и перенесли все вычисления на видеокарту и всякие там DirectX`ы и пр..


Неожиданное заключение... Мне как пользователю начхать чем обходятся нормальные браузеры. Мне главное что оно быстро работает. Очень быстро.
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

Alec
Бывалый
Бывалый
 
Сообщения: 275
Зарегистрирован: 31.08.2008 (Вс) 0:15
Откуда: Ростов-на-Дону

Re: GDI графика в режиме реального времени

Сообщение Alec » 14.05.2010 (Пт) 20:08

Обязательно ли пользователю видеть все объекты во время перемещения?
Насколько я помню в Excel (2003 - точно) при перемещении достаточно большого количества объектов они не прорисовываются целиком, а обозначается область, их ограничивающая, а объекты перерисовываются уже после завершения перемещения (отпускания мышки). Тоже позволяет и Windows при перемещении окон - можно отключить прорисовку окна и будет перемещаться только контур.
Может есть смысл сделать аналогично?
Иногда лучше вовремя остановиться...
И начать заново!

Amed
Алфизик
Алфизик
 
Сообщения: 5346
Зарегистрирован: 09.03.2003 (Вс) 9:26

Re: GDI графика в режиме реального времени

Сообщение Amed » 22.05.2010 (Сб) 0:05

Dion писал(а):Но нет, я пытался реализовать - что, только определённые объекты перерисовываются - например, тот, который перемещается и те которых он задел при перемещении, а также примыкающие и задетые линии. Но, а если объектов 200 и пользователь выделил 50 и таскает их?


А что, если попробовать по-другому?
1. В хранилище 1 (Х1) помещать фоновое изображение + не выделенные элементы
2. В хранилище 2 (Х2) помещать выделенные элементы с маской прозрачности вокруг них
3. При перемещении рисовать в контейнере Х1 + Х2 (с соответствующим смещением)
4. При необходимости перерисовывать переместившиеся линии

Если я ничего не упускаю, то при большом числе объектов больше всего времени будет тратиться на рисование переместившихся линий (Х1, Х2 - зафиксированные единожды растры), а вывод растров будет практически мгновенный.

Dion
Начинающий
Начинающий
 
Сообщения: 8
Зарегистрирован: 16.03.2008 (Вс) 16:03

Re: GDI графика в режиме реального времени

Сообщение Dion » 22.05.2010 (Сб) 12:56

Alec писал(а):Насколько я помню в Excel (2003 - точно) при перемещении достаточно большого количества объектов они не прорисовываются целиком, а обозначается область, их ограничивающая, а объекты перерисовываются уже после завершения перемещения (отпускания мышки).

На данный момент реализовано близко к этому... При перемещении от объекта до настоящего положения курсора в реальном времени тянется пунктирная линия (которая показывает откуда и куда переместится объект), при отпускании кнопки мыши объекты перемещаются в нужную точку и однократно перерисовываются. Естественно это всё идеально и быстро работает, но начальник требует от меня, чтобы все объекты и связи таскались за мышкой в режиме реального времени :(
Кстати если на время непрерывной перерисовки в реальном времени у главного ПикБокса ставить Autoredraw=False, всё это очень быстро рисуется, правда, при этом возникает "эффект жуткого мигания". Поэтому это не годится... На счёт рамок, контуры объектов. (Как я понял вы предлагаете создавать программно массив Shape < со спец. стилем >, которые будут находиться внутри основного PictureBox) Идея очень неплохая, но незнаю как это будет себя вести на деле. Ведь одновременно выделенных объектов может быть больше 100 - 500 на экране...

Amed писал(а):Если я ничего не упускаю, то при большом числе объектов больше всего времени будет тратиться на рисование переместившихся линий (Х1, Х2 - зафиксированные единожды растры), а вывод растров будет практически мгновенный.
Абсолютно верно!!! Растры перерисовываются очень быстро, даже при 700 объектах на экране всё плавно перемещается. Но стоит только добавить Линии и Текст, как всё начинает страшно тормозить.

У меня была неплохая идея, но она не сработала из-за особенностей совместимости API-функций. Я сделал отдельную форму, задав ей родительским PictureBox. На этой форме рисовались объекты (которые выделены и их возможно будут перемещать), фон формы заливался цветом, который задавался прозрачным. Всё бы прекрасно, но эти 2 API функции оказались совместно несовместимы. Вместе они работали через "жо..."
Я решил делать без родительского окна... Но прозрачная форма с объектами начала гулять по всему экрану, я смог её корректно ограничивать в пределах ПикчуреБокса и пришлось отказаться от этой идеи :(

Вообще вся загвоздка кроется в связях, которая не даёт оптимизировать перерисовку каких-то конкретных элементов. Дело в том что по архитектуре, сначала рисуются все связи, а потом на них накладываются объекты. И часто бывает так, что от всех объектов идут связи к одному (основному) и скорее всего двигать будут именно его! А сдвинув его, это затрагивает всё что есть на экране... Тут не избежать перерисовки каких-то отдельных элементов :?

Adam Smith
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 175
Зарегистрирован: 25.04.2008 (Пт) 9:04
Откуда: ЧР. Грозный

Re: GDI графика в режиме реального времени

Сообщение Adam Smith » 23.05.2010 (Вс) 15:29

Ну если растр рисуется быстрее текста, то может заготовить сразу рисунки всех надписей?
Не совсем понял про иконки, но рисовать 32х битные можно просто DrawIcon DrawIconEx.

Sam777e
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 155
Зарегистрирован: 16.09.2010 (Чт) 4:33

Re: GDI графика в режиме реального времени

Сообщение Sam777e » 20.10.2010 (Ср) 16:38

Не знаю - актуальна ли ещё проблема; и не вникал в Ваше решение и советы коллег. Однако, вопрос: когда и как часто Вы вызываете Redrow? Если по MouseMove, то рекомендую вызывать НЕ ПО КАЖДОМУ событию, а, скажем, по 20-ому, 40-ому, и.т.д.
С уважением.
Здоровья и удачи

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: GDI графика в режиме реального времени

Сообщение FireFenix » 20.10.2010 (Ср) 19:36

Sam777e писал(а):Не знаю - актуальна ли ещё проблема; и не вникал в Ваше решение и советы коллег

Зачем работать археологом и не смотреть на пройденный путь?
Sam777e писал(а):Redrow

ReDraw
Sam777e писал(а):Если по MouseMove, то рекомендую вызывать НЕ ПО КАЖДОМУ событию, а, скажем, по 20-ому, 40-ому, и.т.д.

Дёргание объекта ~ Fail
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

Sam777e
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 155
Зарегистрирован: 16.09.2010 (Чт) 4:33

Re: GDI графика в режиме реального времени

Сообщение Sam777e » 07.11.2010 (Вс) 19:12

Ещё раз просмотрел всё - и снова рекомендую обратить внимание на ЧАСТОТУ обращения к ReDraw
Здоровья и удачи

c0de_in
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 1
Зарегистрирован: 26.08.2011 (Пт) 23:54

Re: GDI графика в режиме реального времени

Сообщение c0de_in » 27.08.2011 (Сб) 17:25

а не проще создать один маленький пикчербокс с нулевым индексом а в рантайме уже создавать нужное кол-во объектов функцией load?

Yabloko9393
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 6
Зарегистрирован: 19.12.2011 (Пн) 16:37
Откуда: Томск

Re: GDI графика в режиме реального времени

Сообщение Yabloko9393 » 20.12.2011 (Вт) 0:52

Если по MouseMove, то рекомендую вызывать НЕ ПО КАЖДОМУ событию, а, скажем, по 20-ому, 40-ому, и.т.д.

Дёргание объекта ~ Fail
ИЗВИНИТЕ....я конечно полный профан, но с подобной проблемой сталкивался....Перерисовывать надо не в событии движения мыши, и не через 20-40 прикселей перемещения мыши....когда начинаем тащить че-нибуть то Flag=да =)))...и ксли этотFlad=да, то таймер через каждые скажем 30 силисекунд вызывает перерисовку....ниче не дергается(если конечно успевает за это время все перерисовать)....это я когдато через по*у строил графики с обнаружением точек разрыва, благодаря таймеру получается гораздо лучше......Не замечали, когда рабочий стол завис, а мы таскаем окно, то от него следы остаются, но они остаются не через каждый пиксель и не через 20-40...а ровно через определенный промежуток времени :D

meh&vb
Начинающий
Начинающий
 
Сообщения: 8
Зарегистрирован: 14.07.2003 (Пн) 9:28
Откуда: Смоленская область

Re: GDI графика в режиме реального времени

Сообщение meh&vb » 06.10.2012 (Сб) 20:59

Мне кажется, если в качестве рисунков(иконок) и объектов(текста и фигур...) использовать готовые контролы, а потом, выделив их, таскать по PictureBox, то это будет быстрее. Но вот перемещаться будет только контур выделенных фигур, а сами объекты только после отпускания мышки(запомнить все контролы в массиве, а затем просто изменить их координаты).

ark
Бывалый
Бывалый
 
Сообщения: 216
Зарегистрирован: 18.07.2011 (Пн) 0:57

Re: GDI графика в режиме реального времени

Сообщение ark » 07.10.2012 (Вс) 5:47

Dion писал(а):Autoredraw=False, всё это очень быстро рисуется, правда, при этом возникает "эффект жуткого мигания"
Субклассинг на пропуск WM_ERASEBKGND должен помочь

burik
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 514
Зарегистрирован: 03.11.2005 (Чт) 22:04
Откуда: Беларусь, Рогачев

Re: GDI графика в режиме реального времени

Сообщение burik » 07.10.2012 (Вс) 18:13

Уважаемое сообщество некрофилов, вы поднадоели за последнее время.
Между слухов, сказок, мифов,
просто лжи, легенд сомнений
мы враждуем жарче скифов
за несходство заблуждений
Игорь Губерман


Вернуться в Раздел для Профессионалов

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

    TopList