![]() |
|
|
![]()
|
|
| vaddsm |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 128 Регистрация: 30.6.2007 Репутация: нет Всего: нет |
Приветствую всех! Необходимо сделать возможность ресайза окна, но по некоторым причинам не могу использовать WM_NCHITTEST, поэтому делаю данную возможность самостоятельно через функцию SetWindowPos. Беда в том, что при такой реализации окно оставляет следы, они конечно исчезают но с некоторой задержкой, которой хватает, чтобы лицезреть неприятный эффект виде хвоста тянущегося за окном во время его ресайза пользователем.
В случае же когда используется стандартный подконтрольный Windows ресайз через WM_NCHITTEST, таких артефактов не наблюдается. Подскажите пожалуйста, откуда появляется такая проблема и по возможности как ее решить. Вот пример формы. Если зажать кнопку мыши в произвольной точке формы и вести мышь окно будет пропорционально меняться в размерах, но при этом виден “хвост”.
Это сообщение отредактировал(а) vaddsm - 1.8.2008, 15:06 |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: нет Всего: 106 |
возможно имелось ввиду WM_MOVING и WM_SIZING, а не WM_NCHITTEST
если не сложно, выложи скомпилировыанный пример, так проблема будет найдена быстрее -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Paspartu |
|
|||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 67 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
Если нет возможности использовать WM_NCHITTEST ??? Его в принципе можно использовать всегда, но да ладно если есть необходимось сделать свой HANDMADE resize я поступал следующим образом делаешь 9 прямоугольников (4 угла, 4 бордюра, + заголовок) при нажатии левой кнопки проверяешь их т.е. полная оналогия WM_NCHITTEST … если точка в RECT-е (кроме заголовка т.к. за заголовок можно только перетаскивать) то запоминаешь положение курсора в static POINT устанавливаешь флаг изменения размеров, т.е. когда мышь двигается и этот флаг установлен то берешь новое положение мыши и т.д. короче resize в действии далее определяешь новые размеры окна и
MoveWindow(hWnd,ptNewWndPos.x,ptNewWndPos.y,nNewWidth,nNewHeight,1); или SetWindowPos(...) И будет тебе счастье… извини, возможно все сумбурно, но думаю идея ясна… а если не секрет почему не можешь использовать WM_NCHITTEST ??? |
|||
|
||||
| vaddsm |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 128 Регистрация: 30.6.2007 Репутация: нет Всего: нет |
Paspartu ты реально жжешь, я в примере как раз про этот метод писал, если обратишь внимание на исходник, так вообще удивишься, да, да, там как раз то самое.
Надеюсь понятно, что функция SetBounds как раз и использует API SetWindowPos. Вот только проблема в том что при этом методе окно размазывается по окнам находящимся ниже по уровню. Вот здесь вот у человека та же проблема была. http://forum.sources.ru/index.php?showtopic=238376&hl= В своем случае я уже решил проблему в сторону WM_NCHITTEST, но все же остается загадкой какой алгоритм применяется при обработке системой WM_NCHITTEST во время изменения размеров окна. Тот же самый SetWindowPos? Тогда почему такая разница? Это сообщение отредактировал(а) vaddsm - 4.8.2008, 06:28 |
||||
|
|||||
| Paspartu |
|
|||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 67 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
MoveWindow(....,1); последний параметр 1(TRUE), посылает команду на перерисовку окон нижнего уровня, если остаются следы, значит, окна нижнего уровня соответственно не перерисовываются...
|
|||
|
||||
| vaddsm |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 128 Регистрация: 30.6.2007 Репутация: нет Всего: нет |
Пробовал с MoveWindow, думал она быстрее работает, но нет эффект тот же. Ок, я вижу нужно релиз выкинуть, так как не понимание зависло в воздухе.
Они перерисовываются но с задержкой. От этого след, хвост, размывание окна: http://forum.sources.ru/index.php?showtopic=238376&hl= |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: нет Всего: 106 |
очевидно, проблема в использовании API, но опять же, повторяю, выложи пример.
ни кто не будет так глубоко вникать в проблему, чтобы писать приложение, кроме тебя самого, тем более в билдере могу только предположить, что где-то упущен вызов UpdateWindow -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| vaddsm |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 128 Регистрация: 30.6.2007 Репутация: нет Всего: нет |
Запустите пример и:
Замечательно если под этим окно сейчас находится парочка других окон. Воспользуйтесь левой кнопкой мыши в любой точке окна, чтобы изменять его размер по средствам вызова MoveWindow. Особенно обратите внимание на процесс уменьшения размеров окна. Затем воспользуйтесь стандартным ресайзом потянув за край окна. Сравните визуальный результат. Это сообщение отредактировал(а) vaddsm - 7.8.2008, 01:22 Присоединённый файл ( Кол-во скачиваний: 10 )
HandMadeResizing.rar 200,03 Kb |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: нет Всего: 106 |
чесно говоря, не нашел ничего, что могло бы отличать обычное изменение размеров окна (за его края) и ручное (по клику), в обоих случаях под твоим окном находилось несколько других окошек эксплорера, кроме случая с VS: если под окном находится распахнутая VS, то скролл бары VS перерисовываются не сразу, с некоторым запозданием, т.е. в их области еще некоторое время остается отпечаток твоего окна, но в клиентской области все нормально, причем эффект наблюдается независимо от того, каким способом я меняю размеры окна (разница лишь в том, что при ресайзе за края окна, на VS остается белая полоска, а не отпечаток окна)
причина такой заторможенности при прорисовке окон заднего плана в том, что эти окна сложны сами по себе, их отрисовка требует больше времени, чем обычные окна эксплорера. поскольку эффект наблюдается в обоих случаях, а твое внедрение в WM_SIZING я незаметил, проблема кроется в реализации обертки API билдером, но решить проблему, скорее всего, можно с помощью вызова в WM_MOUSEMOVE( либо в SetBounds ) метода ProcessMessages (это в Delphi, в билдере очевидно есть аналог этого метода), либо вызвать UpdateWindow в том же месте, либо скомбинировать оба метода, что-то должно помочь (хотя я и не сторонник таких методов) -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| vaddsm |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 128 Регистрация: 30.6.2007 Репутация: нет Всего: нет |
Здорово, что наконец появился проблеск понимания. Сразу скажу:
Это не так, так как обертки по сути и нет вовсе, если обратить внимание на код в архиве:
Вместо SetBounds(Left, Top, w, h); используется API MoveWindow. Никакие UpdateWindow нам здесь и не помогут, так как обновлять нам не свое окно надо а окна лежащие под… Более того, судя по всему перерисовка регионов окон осуществляется посредствам механизма пост-отправки (PostMessage) сообщений так, как это происходит не моментально а после завершения SetWindowPos или MoveWindow. Эмпирически это подтверждается тем, что если увеличить приоритет процесса до высокого, след на прочих окнах становится заметнее и убирается еще с большим запозданием. Признаюсь, я даже свою функцию писал, которая после вызова SetWindowPos c флагом SWP_NOREDRAW определяла регионы окон подлежащих перерисовке и отправляла InvalidateRgn каждому из них. В итоге по скорости получилось ровно тоже, что и без флага SWP_NOREDRAW. Это все очень похоже на никчемный бред, но ни я первый столкнулся с этой проблемой (смотрите ссылку на форум) и жутко интересно как Windows реализует изменение размеров окна когда пользователь применяет стандартный ресайз за рамку окна. Надо в ядро копать. Может у кого есть исходник User32.dll чтобы Defwindowproc глянуть. Это сообщение отредактировал(а) vaddsm - 7.8.2008, 17:12 |
||||
|
|||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: нет Всего: 106 |
это заняло около 5 минут,
я все же решил написать точно такой же тест, идеологию не менял, как надо это писать здесь расписывать не буду, дело было всего лишь в одном флаге SWP_FRAMECHANGED, который просто заставляет посылать сообщение WM_NCCALCSIZE, тем самым обновляя неклиентскую область Добавлено через 13 минут и 52 секунды единственное неудобство в том, что SetWindowPos с таким параметром посылает WM_NCCALCSIZE всегда, независимо от того, изменились ли размеры окна или нет, такое поведение загружает систему по-полной (загляни в диспетчер задач при изменении размеров окна), поэтому, перед вызовом необходимо проверить это самому, например так:
и все таки ProcessMessages нужно вставить после вызова SetWindowPos Присоединённый файл ( Кол-во скачиваний: 6 )
ResizeTest.rar 59,35 Kb-------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: нет Всего: 106 |
а втот уж совсем идеальный вариант,
в приложении тот же пример, но уже без лишних вызовов и флагов. суть этого апгрейда в том, чтобы проредить число вызовов SetWindowPos по отношению к числу вызовов WM_MOUSEMOVE, т.е. сделать так, чтобы на несколько вызовов (3-5) WM_MOUSEMOVE вызывался только один SetWindowPos. это отношение задает переменная k, сейчас k = 3, с ней еще можно поэкспериментировать Это значительно снижает нагрузку на методы прорисовки всех окон-участников, кстати, при изменении размеров окна обычным способом, за края, система похоже так же имеет аналогичный цикл обработки сообщений, поскольку она фиксирует эти временные точки сообщениями WM_ENTERSIZEMOVE и WM_EXITSIZEMOVE дополнительно добавил захват мыши: SetCapture, просто для удобства флаги оставил без изменений: SWP_NOMOVE | SWP_NOZORDER
PS: код не содержит необходимых проверок и оптимизаций Это сообщение отредактировал(а) GremlinProg - 7.8.2008, 19:17 Присоединённый файл ( Кол-во скачиваний: 9 )
ResizeTest.rar 60,01 Kb-------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| vaddsm |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 128 Регистрация: 30.6.2007 Репутация: нет Всего: нет |
Может дело в производительности системы, может у тебя комп покруче, но такое ощущение, что ты не видишь то, что вижу я. Твой последний пример в сборке дает незначительный прирост только за счет пропуска сообщений мыши, а пропускать сообщения мыши, ну это уж совсем не юзерфрендли.
Не в том направлении идет дискуссия. Смотри. Предположим окно без фрейма и оно WS_POPUP, у него есть возможность ресайза а по правой стороне у него хендмейд скроллбар, который меняет свою позицию по мере изменения размеров окна, так чтобы всегда быть строго справа. (К сути это мало относится, но я красок добавил, Пользователь начинает ресайзить такое окно (в сторону уменьшения его ширины) этим злополучным способом. SetWindowPos до своего завершения посылает окну ряд сообщений WM_WINDOWPOSCHANGING, WM_NCCALCSIZE, WM_WINDOWPOSCHANGED, WM_SIZE… и наконец WM_ERASEBKGND, WM_PAINT. Все, наше окно на данный момент изменило свой размер, перепозиционировало дочерние окна и перерисовала клиентскую область и рамку (если она есть). Назовем это действием №1. К этому моменту у нас получается нарисованное окно с новым размером и артефакт, назовем его так, справа от окна, следующая задача оси заставить окна лежащие в области этого артефакта перерисовать свои клиентские и не клиентские части попадающие в эту область. Такая перерисовка происходит уже после завершения SetWindowPos. Назовем операцию по удалению артефакта – действие №2. Так вот, все что, делаешь (в том числе ProcessMessages) направлено на увеличение производительности действия №1. И никоем образом не помогает в решении проблемы, единственное, что вполне логично сокращение числа WM_MOUSEMOVE несколько снижает нагрузку, но это просто страшный кастыль какой то. Ось справляется с задачей и без этого, когда обрабатывает WM_NCHITTEST ресайз. Это сообщение отредактировал(а) vaddsm - 8.8.2008, 02:19 |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: нет Всего: 106 |
ты похоже так и не понял отчего за окном тянется шлейф
вот еще пример, сам подумай, почему здесь нет шлейфа, а позиционирование окна не заторможено как в предыдущем случае
сейчас я использовал самое тормозное (по графике) окно заднего плана, какое у меня только есть - восьмой промт на нем даже обычный ресайз оставляет след (есть еще пара схожих вариантов, например: любое JRE-окно или Winamp) тем не менее, мой вариант не оставляет на нем след. (Prescott 2.4 RAM-1024MB GF-FX5200 не такой уж и мощный, согласись) костылей тут никаких нет, ни одно сообщение не пропускается, некоторые просто откладывается, нужно понимать разницу! a += 3; a -= 2; равнозначно a += 1; не так ли? здесь, с ресайзом, точно такой же принцип PS: TRACKMOUSEEVENT эмулируется системой, ComCtl подключать не надо Это сообщение отредактировал(а) GremlinProg - 8.8.2008, 12:12 Присоединённый файл ( Кол-во скачиваний: 20 )
ResizeTest.rar 60,70 Kb-------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| vaddsm |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 128 Регистрация: 30.6.2007 Репутация: нет Всего: нет |
У тебя в предыдущем примере пропускались сообщения, там ты TrackMouseEvent не использовал, я по этому и написал. Сейчас вижу в этом отношении все в порядке.
Да, следов не остается, однако визуально разница между изменением размера за рамку и произвольным способом все же есть. Одновременно на экране присутствует окно в новом размере и часть окна в старом размере, если уменьшать его с право на лево. Так или иначе твой вариант неплохо справляется с частью проблемы, молодец )! |
|||
|
||||
![]()
|
| Правила форума "С++ Builder" | |
|
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C++ Builder | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |