Занимаюсь написанием удобного класса по созданию и управлению popup окном. В частности интересует вопрос по изменению неклиентской части окна.
В этом вопросе есть у меня некоторое недопонимание и хотелось чтобы его развели знающие люди и подсказали что-нибудь интересное.
Насколько я понял, при изменение размера окна/положение окна с флагом — SWP_FRAMECHANGED, например написав так:
SetWindowPos hWnd, _
0&, 0&, 0&, 0&, 0&, _
SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOZORDER Or _
SWP_NOACTIVATE Or SWP_NOOWNERZORDER Or SWP_FRAMECHANGED
окну посылается сообщение — WM_NCCALCSIZE — которое говорит ему, что необходимо пересчитать размеры клиентской области относ. размеров окна. В параметре lParam это сообщения передаются размеры окна в виде:
Private Type NCCALCSIZE_PARAMS
rgrc(0 To 2) As RECT
lppos As Long 'WINDOWPOS
End Type
как написано в MSDN: 0 RECT — новые размеры окна, 1 RECT — старые размеры окна, 3 RECT — размеры КЛИЕНТ. части окна до изм.; lppos — указатель на структуру WINDOWPOS где опять же заданы размеры окна.
Вопервых непонятно, почему написано, что 0 RECT отвечает за размеры окна, тогда как опытным путем я выяснил, что именно его изменения влияют на размер КЛИЕНТской области, скроей его надо было назвать новый размер КЛИЕНТСКОЙ области. Во всех примерах инета меняют обычно именно 0 RECT.
Второе: я пытался изменить размеры клиентской части окна послав ему сообщение WM_NCCALCSIZE через SendMessage, и через Spy++ я видел что сообщение доходит до окна, но почему-то не принимается к действию. Вызвав после этого SetWindowPos.... который тоже порождает WM_NCCALCSIZE событие, я уже вижу что в нем опять передается старые значения окна. Т.е. он просто не принимает и не запоминает размеры окна (клиент. части), когда я ему посылаю их через SendMessage.
Я подумал что может он их просто не ждет и его сначала как-то подготовить к тому, что будет изменены внутр. размеры клиент. части. Тогда перед SendMessage ..WM_NCCALCSIZE.. я стал посылать SendMessage ..WM_WINDOWPOSCANGING.. на манер как это делает функ. SetWindowPos (с нулевыми размерами и флагами WP_NOSIZE Or SWP_NOMOVE Or WP_FRAMECHANGED Or...) — тоже облом.
Единственный способ который подошел, это когда я через SetWindowPos инициирую событие WM_NCCALCSIZE, которое перехватываю в обработчике WindowProc и уже меняю его LParam. Тогда все хорошо и я сразу вижу как клиентская часть окна изменилась.
Вопрос: почему? почему токо изменив посланное системой сообщение можно заставить его поменять размеры, а сообщение посланное напрямую через SendMessage игнорируется, что ему может не хватать? есть у кого-нибудь идеи? Буду благодарен за любую подсказку, хочется расширить свой горизон горизонт, а не оставаться с таким непонятками
P.S. прошу Вас не пугаться за представленный код, это VB, но на суть вопроса язык я думаю не должен влиять.
Здравствуйте, SergeySV2, Вы писали:
SSV>Насколько я понял, при изменение размера окна/положение окна с флагом — SWP_FRAMECHANGED, окну посылается сообщение — WM_NCCALCSIZE — которое говорит ему, что необходимо пересчитать размеры клиентской области относ. размеров окна.
Точно. Но это сообщение посылается окну только с целью _выяснить_ каких бы размеров ему хотелось иметь свою клиентскую область, оно обрабатывается либо окнной процедурой конкретного класса окон (или конкретного окна, если имел место subclassing), либо обрабатывается ::DefWindowProc(), которая расчитывает размер согласно системным метрикам и стилям окна, но в любом случае обработчик этого сообщения только расчитывает размеры, но ни применяет, ни сохраняет их.
Применением размеров занимает ТотКтоПослал сообщение WM_NCCALCSIZE (с точки зрения прикладника ::SetWindowPos()), а вот как он это делает может сильно зависеть от версии, поэтому вы сделать это впринципе сможете (благо доступен исходник Win2000 :) и книжка вроде есть, где внутренности такого рода рассматриваются), но только я бы вам не советовал терять на это время :). Резюмируя, можно посоветовать понимать WM_NCCALCSIZE как WM_{Get}NCCALCSIZE, а не как WM_{Set}NCCALCSIZE.
SSV>Вопервых непонятно, почему написано, что 0 RECT отвечает за размеры окна, тогда как опытным путем я выяснил [...]. Во всех примерах инета меняют обычно именно 0 RECT.
Что именно передается в lParam сильно зависит от значения wParam, так вот как раз когда (!wParam), то в lParam передается (LPRECT) на новый размер окна, в который надо записать новые координаты клиентской области. Но так как все программисты — ленивы, то все подумали и решили, что раз NCCALCSIZE_PARAMS — POD, а первым членом там RECT (первый из трех), то можно считать, что в lParam _всегда_ передается (LPNCCALCSIZE_PARAMS), но в случае (!wParam) использовать только rgrc[0], а остальные не трогать.
Большое спасибо за подробные объяснения, а то так вроде догадываешься, а твердой уверенности что все делаешь правильно и главное почему именно так надо делать — нет
Хотел только для себя уточнить последний непонятный момент в описании: >>Возвращаемые значения
Если параметр fCalcValidRects — ЛОЖЬ(FALSE), прикладная программа должна возвратить нуль. Если fCalcValidRects — ИСТИНА (TRUE), прикладная программа может возвратить нуль или допустимую комбинацию следующих значений:
WVR_ALIGNTOP, WVR_ALIGNLEFT, WVR_ALIGNBOTTOM, WVR_ALIGNRIGHT — Эти значения, используемые в комбинаци-ях, определяют, что рабочая область окна должна сохраниться и выравниваться соот-ветственно относительно новой позиции окна. Например, чтобы выровнять рабочую область по левому нижнему углу, возвратите значения WVR_ALIGNLEFT и WVR_ALIGNTOP.
............
..........
Вопрос как я могу вернуть эти значения? Класс окна я использую стандартный "STATIC", а окнную процедуру перегружаю используя subclassing, в конце обработки сообщений я соотв. пишу:
WindowProc = CallWindowProc(lpPrevWndProc, hWnd, uMsg, wParam, LParam) — передаю сообщению в окон. процедуру по умолч.
Если я хочу вернуть какую-то конкретную константу, это мне надо делать так что-ли?:
......
Case WM_NCCALCSIZE
WindowProc = WVR_ALIGNLEFT
Call CallWindowProc(lpPrevWndProc, hWnd, uMsg, wParam, LParam)
End Function
Не посоветуете ли хорошую книгу или обзор статей по созданию/управлению окнами в windows
Здравствуйте, SergeySV2, Вы писали:
SSV>Если я хочу вернуть какую-то конкретную константу, это мне надо делать так что-ли?:
SSV> Case WM_NCCALCSIZE
SSV> WindowProc = WVR_ALIGNLEFT
SSV> Call CallWindowProc(lpPrevWndProc, hWnd, uMsg, wParam, LParam)
SSV>End Function
Именно.
SSV>Не посоветуете ли хорошую книгу или обзор статей по созданию/управлению окнами в windows.
Да в общем в MSDN'е вполне достаточно информации (и где общие слова, и где описание функций). Особые тонкости можно посмотреть в книжках у Anatolix'а, те, что первая и последняя.
Здравствуйте, Frostbitten, Вы писали:
SSV>>Не посоветуете ли хорошую книгу или обзор статей по созданию/управлению окнами в windows. F>Да в общем в MSDN'е вполне достаточно информации (и где общие слова, и где описание функций). Особые тонкости можно посмотреть в книжках у Anatolix'а, те, что первая и последняя.