![]() |
|
|
![]()
|
|
| voov |
|
|||
![]() Патамушта мы пилоты ![]() ![]() Профиль Группа: Участник Сообщений: 460 Регистрация: 29.11.2007 Репутация: 8 Всего: 8 |
У меня есть дллка, в которой класс, рисующий график.
Ранее это был класс, унаследованный от CObject. Ему передавался контекст утройства, на котором он и рисовал график. Теперь это класс, унаследованный от окна. Отрисовка та же, но в своей клиентской области. Эту библиотеку использую в МДИ приложении в одном из видов. Ранее, при необходимости перерисовать вид, в класс графика передавался указатель на CDC. Теперь в вид добавлено дочернее окно, которому просто сообщается, что нужно выполнить перерисовку. Код отрисовки графика тот же, но новый вариант (с окном) занимает процесорного времени примерно в 2 раза больше. Почему так происходит? Неужели столько ресурсов отнимает обрабтка сообщений еще одного окна? |
|||
|
||||
| voov |
|
|||
![]() Патамушта мы пилоты ![]() ![]() Профиль Группа: Участник Сообщений: 460 Регистрация: 29.11.2007 Репутация: 8 Всего: 8 |
Если непонятно объяснил или нужна еще какаято информация, спрашивайте.
Никак не могу понять почему так происходит... |
|||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Вряди ли, если конечно, ты там не наворотил что-нибудь. Откуда ты знаешь, что именно занимает больше вермени. Просто по ощущению? Возможен вариант, что происходит 2 перерисовки вместо одной (какой-нибудь лишний Invalidate невовремя). Для начала нужно убедиться, что это не так. Кстати, бороться с этим непросто (с лишними обновлениями), да и не нужно. Лучше (для кода) отделить перерисовку от обновления окна, разделить их. Т.е. отрисовку делать во внеэкранном буфере, а на обновление просто выплевывать его содержимое на экно. Контролировать внеэкранный буфер нет проблем. А вот контролировать инвалидэйты сложно. Их ведь еще и система генерирует. Вообще, если перерисовка не тривиальна, лучше всегда ее делать в буфер. Кстати, для этого прекрасно бы подошел твой первый вариант, с объектом, рисующим в переданный контекст. -------------------- ... |
|||
|
||||
| voov |
|
||||
![]() Патамушта мы пилоты ![]() ![]() Профиль Группа: Участник Сообщений: 460 Регистрация: 29.11.2007 Репутация: 8 Всего: 8 |
Может и наворотил, но не вижу где... Помоги разобраться. Возможно архитектура не оптимальная, но вроде не должна давать такую разницу. Во фрейме лежит окно, у которого несколько детей-видов. Задача этого окна переключать виды. Одним из детей есть вид графика, у которого в свою очередь теперь есть дочернее окно - сам график. Возможно лучше было бы убрать из этой цепочки вид, но хотелось бы сохранить функциональность, которую он предоставляет (доступ к документу и OnUpdate).
Смотрю загрузку процессора данным процессом. Дело в том, что график обновляется раз в секунду, поэтому заргузку хорошо видно. Вариант без окна примерно 8%, а с окном 15-17%. Основная программа при этом выполняет одни и те же действия, потому не может давать такой разброс.
убедился в первую очередь. провел массу тестов и экспериментов. отрисовка вызывается раз в секунду (к тому же перерисовывается не все окно, а только некоторые области). Еще один подтверждающий симптом. Когда рисуется голый график, т.е. без данных, только оси, сетка, подписи и пр., то вариант без окна процессорного времени занимает очень мало, а с окном все те же 15% Возможно действительно нужно чтото переделать, но нужно хорошо продумать. На данный момент я и рисую во временный буфер (двойная буферизация), но в момент обновления окна. Буфер не храню, так как график плывет - приходят новые данные, меняется масштаб, меняются значения на линейках, т.е. нет постоянной картинки. Перерисовка не тривиальна, но она одинакова в обоих вариантах. А сделать окно пришлось изза необходимости инкапсулировать в класс графика обработку мыши и еще коекаких мелочей. |
||||
|
|||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Т.е. не время у тебя страдает, а загрузка процессора?
Насчет однократной перерисовки - не убедил. Как я поняла, основная перерисовка вызывается по таймеру раз в секунду (т.е. Invalidate вызывается). Но где гарантия, что другие Invalidate не происходят? Может, и не в этом причина, но я бы все же отделила код рисования графика от кода обновления и хранила буфер. Получиться дизайн более четкий. Раз в секунду (или по другому поводу) обновляется внеэкранный буфер (и вызывается Invalidate), а по OnPaint просто копируется содержимое буфера.
Угу, знакомая картина. Только полноценное окно сюда не стоит приплетать (оболочка с ним бурно общается). Я делаю так: есть окно-вид, со станартным набором функций. И есть сменный агент-инструмент (тоже наследник CWnd, как бы двойник вида, с тем же хандлом). Поскольку это типа окно, можно вызывать все оконные процедуры и использовать карты. Но поскольку оболочка про него ничего не знает, оно получает только то, что ему передает основной вид. Преимуществ масса: управляемость, можно менять агента (разные режимы работы окна) и т.д., сразу не вспомнить, но очень удобно, поверь. Единственно, поскольку MFC не хочет присваивать один и тот же хандл разным объектам (ругается), приходится делать это аккуратно руками (т.е. вызывать Attach\Detach). И вообще, лучший дизайн - это когда поделено все что можно. Надо пресекать расползание набора функций, иначе потом умаешься поддерживать. Возвращаясь к твоей проблеме: попробуй задействовать профайлер и посмотри, кто жрет время. Вряд ли практически один и тот же код отрисовки модет работать с такими отличиями. Еще раз уточни, в чем разница между вариантами. Сейчас у тебя фрейм - вид - его дочернее окно, которое и рисует график на OnPaint (сначала в буфер, потом на экран). Так? А раньше как было? -------------------- ... |
|||
|
||||
| voov |
|
|||
![]() Патамушта мы пилоты ![]() ![]() Профиль Группа: Участник Сообщений: 460 Регистрация: 29.11.2007 Репутация: 8 Всего: 8 |
Уточняю. В обоих случаях рисуется сначала в буфер, потом на экран. Ранее: фрейм - окно (переключатель видов) - вид графика (для перерисовки вызывался метод объекта с указателем на контекст). Сейчас: фрейм - окно (переключатель видов) - вид графика - окно графика (рисует график на OnPaint). Еще раз отмечу, что класс графика (и оконный и просто объект) находятся в отдельной длл. Может в этом причина? Я ставил трэйс с текущим временем в OnPaint - по выводу было видно, что OnPaint вызывается раз в секунду.
Да, наверное стоит это сделать, пусть даже из соображений дизайна. Профайлером пока не доводилось пользоваться, потому подскажи на что там обратить внимание. Сделал пару прогонов, их самари прикрепил файлом. Про сменный агент-инструмент. Уточню для полного понимания. Применительно к моему случаю должно получиться следующее: - класс графика наследуется от окна, т.е. так как и сделано сейчас. - в виде создается экземпляр графика, но не создается окно для него (Create не делаем) - объекту графика делается Attach к HWND вида. Другими словами в классе графика менять ничего не нужно, а нужно просто по другому использовать его? После аттача все сообщения вида получит график, а вид ничего (будто у него нет окна)? При этом из вида остается доступ к документу и OnUpdate будет отрабатывать точно так же? Присоединённый файл ( Кол-во скачиваний: 5 )
perfomance_test.jpg 100,78 Kb |
|||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Насчет профайлера, нужно пробовать. Это как с отладкой: на текущем шаге понимаешь, что нужно смотреть на следующем. Я бы сравнила для начала время, затрачиваемое на обработку сообщений в обоих случаях.
Немного соврала. Не Attach, а руками присваиваем. Attach проверяет, что дескриптор "свободен". Соответственно, в деструкторе обнуляем hwnd, тоже ручками. Этот объект является "недоокном": с точки зрения оболочки его нет (и никакие сообщения сами для него не дойдут), но с нашей точки зрения для него работают карты сообщений и всякие Invalidate и прочие обертки над АПИ, что очень удобно. Нет, само так не получится. Все сообщения будет по прежнему получат вид (ибо именно он является представителем HWND с точки зрения оболочки). А агент получает только то, что транслирует ему вид. Таких точек может быть несколько: OnWndMsg, OnCmdMsg, OnSetCursor ... в зависимости от потребностей. Я делаю так. В OnWndMsg делю все сообщения на 3 категории: обрабатываемые исключительно видом (они агенту не передаются), обрабатываемые и видом тоже (они обрабатываются видом вне зависимости от агента), обратываемые либо агентом либо видом. Примерно так:
OnCmdMsg нужно делить, т.к. есть команды (у меня), обрабатываемые видом, и есть те, которые может обработать только агент (смысл его в том, что он сменный). Ну и т.д. WM_PAINT у меня обрабатывает вид и вызывает какой-нибудь Draw агента. -------------------- ... |
|||
|
||||
| voov |
|
|||
![]() Патамушта мы пилоты ![]() ![]() Профиль Группа: Участник Сообщений: 460 Регистрация: 29.11.2007 Репутация: 8 Всего: 8 |
Но разрабатывается этот агент как обычный наследник окна с единственной поправкой на возможность установки hwnd руками. Так? И еще. Если у агента будут дочерние окна, они смогут обрабатывать свои карты? Это сообщение отредактировал(а) voov - 18.6.2009, 14:03 |
|||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Не очень понимаю, что ты имеешь в виду. Я пишу все руками, все поправки в голове держу. Дочерние окна будут у вида - он ведь настоящее окно. Даже если ты создашь дочернее окно, передав ему в качестве парента указатель на агента, то, во-первых, MFC может ругнуться, обнаружив несоответствие, а во-вторых, при запросе у этого чайлда парента вернет тебе таки вид. Не нужно думать об агенте как об окне. Здесь смысл в разделении окно - содержимое. Представь, что ты пишешь логику агента, сделав его не окном, а, скажем CmdTarget. С точки зрения логической модели, это более правильно: есть окно и есть некто, модифицирующий отдельные аспекты поведения окна (любые). Причем этого некта можно менять по ходу дела (тип окна так просто не поменяешь - нужно удалять, создавать и т.д.), гладко не получится. Но тогда, с точки зрения реализации, придется передавать ему управление в большом числе мест + карты сообщений будут работать ограниченно (только команды) + придется передавать ему ссылку на вид (наверняка агенту потребуется что-то узнать или что-то послать). Смысл мухлежа с окном именно в удобстве реализации: сокращение числа точек передачи управления, не надо передавать вид (есть hWnd), полноценные карты... Но помнить о том, что это не совсем окно, необходимо. -------------------- ... |
|||
|
||||
| voov |
|
|||
![]() Патамушта мы пилоты ![]() ![]() Профиль Группа: Участник Сообщений: 460 Регистрация: 29.11.2007 Репутация: 8 Всего: 8 |
Блин, когда уже наконец освою эту телепатию... Я имел ввиду, что, если я напишу класс унаследованный от окна и добавлю к нему метод для установки hwnd, то потом смогу использовать этот класс и как окно и как агент для вида. Люблю универсальные штуки, в разумных пределах конечно. Теперь вижу, что так гладко не получится. Хотя если трошки поднаворотить, то должно получиться. А чтобы дочерние окна нормально работали придется давать им указатель на вид (как парент). |
|||
|
||||
![]()
|
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Visual C++/MFC/WTL | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |