Размеры окна
Как узнать текущий размер окна? Как узнать установленный максимальный и минимальный я нашел - это при помощи структуры MINMAXINFO, а наоборот, т.е. установить?
Как узнать установленный максимальный и минимальный я нашел - это при помощи структуры MINMAXINFO, а наоборот, т.е. установить?
Отрабатывать сообщение WM_GETMINMAXINFO?
GetWindowPlacement,SetWindowPlacement
Спасибо.
Freeman - я же говорю, это как раз наоборот от требуемого.
Обрабатывать сообщение WM_SIZE, или есть более простые пути?
Еще один вопрос из той же оперы: как осуществить привязку размеров дочерних окон к родительскому? Например я хочу, что бы окно при изменении размера родительского тянулось не за верхней гранью, а за нижней, или за обоими.
Обрабатывать сообщение WM_SIZE, или есть более простые пути?
Придется обрабатывать ручками после получения родительским окном данного сообщения.
Придется обрабатывать ручками после получения родительским окном данного сообщения.
Ясненько. "Наша работа и опасна и трудна..." :)
1) Создаем дочернее окно, создаем на нем кнопку, присваеваем ей id. Как теперь ловить сообщения от этой кнопки оконной функцией? case WM_COMMAND - ноль реакции на все щелчки.
Обобщу - как обрабатывать сообщения от дочерних окон: изменение размера и т.п.
2) Как создать дочернее окно "фрейм" (или как его правильно назвать)? Т.е. нечто вроде панели истории в браузерах.
Не хочу создавать новую тему.
1) Создаем дочернее окно, создаем на нем кнопку, присваеваем ей id. Как теперь ловить сообщения от этой кнопки оконной функцией? case WM_COMMAND - ноль реакции на все щелчки.
Обобщу - как обрабатывать сообщения от дочерних окон: изменение размера и т.п.
2) Как создать дочернее окно "фрейм" (или как его правильно назвать)? Т.е. нечто вроде панели истории в браузерах.
1)
Заглянем в MSDN и там найдем:
The WM_COMMAND message is sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.
Syntax
WM_COMMAND
WPARAM wParam
LPARAM lParam;
Parameters
wParam
The high-order word specifies the notification code if the message is from a control. If the message is from an accelerator, this value is 1. If the message is from a menu, this value is zero.
The low-order word specifies the identifier of the menu item, control, or accelerator.
lParam
Handle to the control sending the message if the message is from a control. Otherwise, this parameter is NULL.
Return Value
If an application processes this message, it should return zero.
Т.е. для родительского(главного) окна имеется функция - обработчик,в ней к примеру имеется
case WM_COMMAND:
switch(HIWORD(wParam))//выбираем сообщение от контролов
{
case BN_CLICKED://кнопка нажата
switch(LOWORD(wParam))//выбираем id кнопки
{
case IDOK:
//кнопка с id = IDOK нажата
return 0;
}
}
Для каждого контрола свой набор notification message.
Такие сообщения как BN_CLICKED и другие являются notification message(сообщениями уведомления контролов) и посылаются в обработчик родительского окна данного контрола,а чтобы поймать сообщения от контролов не являющиеся уведомительными такие как WM_SIZE и др необходимо использовать субклассинг(подмену стандартного обработчика WndProc на свой собственный) либо если данное child окно непосредственно создано вами с вашим собственным классом то использовать WndProc непосредственно назначенный данному окну и в нем уже или подмененом обработчике отлавливать такие сообщения.
2) IMHO при программировании на чистом win32 api нет такого понятия как фрейм. Придется самому создавать свой глобальный класс интерфейса и уже через него эмулировать функциональность фреймов.
Хотя в MFC или WTL скорее всего есть что то подобное,не заню не увлекался этим.
1)
Заглянем в MSDN и там найдем...
Заглядывали... И находили это, но это не то. Пожалуйста, обработчик:
{
static CLIENTCREATESTRUCT client;
static HWND mdi_win, btn;
switch(messg)
{
case WM_CREATE:
client.hWindowMenu=NULL;
client.idFirstChild=0;
mdi_win=CreateWindow("MDICLIENT",NULL,
WS_CHILD|WS_VISIBLE|WS_DLGFRAME|WS_SIZEBOX,
5,35,200,100,win,NULL,h_inst,&client);
btn=CreateWindow("button","йМНОЙЮ",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|
NULL,50,50,70,20,mdi_win,(HMENU)BTN_CLOSE,h_inst,NULL);
return 0;
case WM_COMMAND:
OK_MSG("OK");//макрозамена MessageBox'а
//так вот, при щелчке на btn ни каких ОК не выскакивает :(
//т.е. главному окну (win) не идет сообщение WM_COMMAND,
//оно идет окну (mdi_win)
//выход вижу пока только в создании отдельного обработчика
//для mdi_win
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(win, messg, wparam, lparam);
}
Есть еще варианты, или у меня все же что-то не правильно?
btn=CreateWindow("button","йМНОЙЮ",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON| NULL,50,50,70,20,[COLOR=red]mdi_win[/COLOR] ,(HMENU)BTN_CLOSE,h_
inst,NULL);
замени здесь хэндл mdi_win на реальный родительский хэндл,в данном случае win.Получаем
btn=CreateWindow("button","йМНОЙЮ",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON| NULL,50,50,70,20,win,(HMENU)BTN_CLOSE,h_
inst,NULL);
Правда тогда кнопка будет создаваться не на mdi_win а на win. А если требуется чтоб кнопка отображалась на mdi_win,то тогда необходимо делать отдельный обработчик для mdi_win.
Если все же нужно добиться чтобы кнопка принадлежащяя mdi_win обрабатывалась в процедуре win то необходимо сделать субклассинг и там перенаправлять сообщения в нужное окно,только зачем этот геморой.
Естественно оно идет не в этот обработчик а в обработчик для mdi_win так как ты при создании кнопки указал что родителем данной кнопки будет mdi_win. взгляни на свой код...
Спасибо :D Давным давно взглянул. Я как-то привык сперва сам задумываться и рассматривать свой код, а только затем выкладывать его на форум.
Просто предпологал, что сообщения от дочерних окон можно обработать в родительском без дополнительных наворотов. Теперь вижу, что нельзя.
Правда тогда кнопка будет создаваться не на mdi_win а на win.
Ага, вот в этом и проблема.
Если все же нужно добиться чтобы кнопка принадлежащяя mdi_win обрабатывалась в процедуре win то необходимо сделать субклассинг и там перенаправлять сообщения в нужное окно,только зачем этот геморой.
А есть варианты расположения кнопки на родительском окне, да так, что бы при перемещении дочернего одновременно перемещалась и наша кнопка на родительском окне (без еще большЕго гемора)? Или, например мне нужно спрятать дочернее окно - тогда мне нужно будет отдельно прятать все кнопочки которые как-бы находятся на нем (а реально - на родительском).
Кстати, если сперва создать дочернее окно, а затем кнопочку, то она оказывается под ним (по логике вещей - должно быть наоборот) и из-за этого оказывается недоступной. Т.е. ее видно, а щелкнуть по ней не получается. Нужно либо строго соблюдать порядок создания окон - сперва все контроллы, а затем дочернее окно; либо вытягивать их дополнительным набором функций на передний план уже после создания. Что-то мне кажется, что это еще больший гемор, чем создание дополнительной оконной функции. Во всяком случае о структуре программы тогда можно будет забыть.
Видимо других вариантов пока нет. Значит будем делать так.
ЗЫ Я человек тёмный: субклассинг - это что такое: Создание дочернего окна при помощи WNDCLASS? Где про это можно почитать?
имеем класс CInterface который будет служить для базовых операций (т.е. управлением менюшками и общими кнопками а также созданием отдельных оконных модулей(т.е. окон с доп контролами,обработка которых ложится исключительно на данные модули а не главный Wndproc,желательно чтобы модуль был классом) и т.д. Т.е. данный класс обединяет все модули в единое целое,здесь же соответсвенно осуществляется управление расположением,перемещением одних модулей относительно других,их отображение и скрытие. Но здесь не обрабатываются сообщения из контролов относящихся к отдельному модулю.
Конечно реализовать не так то просто,зато все будет потом логически ясным и проще что-то будет изменять,и уже не надо будет лезть в глобальное состояние всего интерфейса а скажем только обратится к классу отдельного модуля.
Хотя существуют библиотеки о которых ты знаеш типа MFC,WTL и т.д которые могут упростить всю архитектуру,но я ими не пользуюсь. Мне пока и чистого winapi хватает,поэтому по этим библиотекам нмчего сказать не могу.
Хотя конечно интерфейс простой то не стоит так заморачиваться,а просто писать как пишеш обычно.
Про субклассинг почитай из мсдн: (если непонятно будет обясню с примером)
Subclassing Defined
Subclassing is a technique that allows an application to intercept messages destined for another window. An application can augment, monitor, or modify the default behavior of a window by intercepting messages meant for another window. Subclassing is an effective way to change or extend the behavior of a window without redeveloping the window. Subclassing the default control window classes (button controls, edit controls, list controls, combo box controls, static controls, and scroll bar controls) is a convenient way to obtain the functionality of the control and to modify its behavior. For example, if a multiline edit control is included in a dialog box and the user presses the ENTER key, the dialog box closes. By subclassing the edit control, an application can have the edit control insert a carriage return and line feed into the text without exiting the dialog box. An edit control does not have to be developed specifically for the needs of the application.
When an application subclasses a window, it can take three actions with the message: (1) pass the message to the original window procedure; (2) modify the message and pass it to the original window procedure; (3) not pass the message.
The application subclassing a window can decide when to react to the messages it receives. The application can process the message before, after, or both before and after passing the message to the original window procedure.
Types of Subclassing
The two types of subclassing are instance subclassing and global subclassing.
Instance subclassing is subclassing an individual window's information structure. With instance subclassing, only the messages of a particular window instance are sent to the new window procedure.
The subclassing process may not use the original window procedure address directly.
In Win16, an application could use the window procedure address returned from SetWindowLong or SetClassLong to call the procedure directly. After all, the return value is simply a pointer to a function, so why not just call it? In Win32, this is a definitive no-no. The value returned from SetWindowLong and GetClassLong may not be a pointer to the previous window procedure at all. Win32 may return a pointer to a data structure that it can use to call the actual window procedure. This occurs in Windows NT™ when an application subclasses a Unicode™ window with a non-Unicode window procedure, or a non-Unicode window with a Unicode window procedure. In this case, the operating system must perform a translation between Unicode and ANSI for the messages the window receives. If an application uses the pointer to this structure to directly call the window procedure, the application will immediately generate an exception. The only way to use the window procedure address returned from SetWindowLong or SetClassLong is as a parameter to CallWindowProc.
Instance Subclassing
The SetWindowLong function is used to subclass an instance of a window. The application must have the address of the subclass function. The subclass function is the function that receives the messages from Windows and passes the messages to the original window procedure. The subclass function must be exported in the application's or the DLL's module definition file.
The application subclassing the window calls SetWindowLong with the handle to the window the application wants to subclass, the GWL_WNDPROC option (defined in WINDOWS.H), and the address of the new subclass function. SetWindowLong returns a DWORD, which is the address of the original window procedure for the window. The application must save this address to pass the intercepted messages to the original window procedure and to remove the subclass from the window. The application passes the messages to the original window procedure by calling CallWindowProc with the address of the original window procedure and the hWnd, Message, wParam, and lParam parameters used in Windows messaging. Usually, the application simply passes the arguments it receives from Windows to CallWindowProc.
The application also needs the original window procedure address for removing the subclass from the window. The application removes the subclass from the window by calling SetWindowLong again. The application passes the address of the original window procedure with the GWL_WNDPROC option and the handle to the window being subclassed.
The following code subclasses and removes a subclass to an edit control:
LONG FAR PASCAL SubClassFunc(HWND hWnd,UINT Message,WPARAM wParam,
LONG lParam);
FARPROC lpfnOldWndProc;
HWND hEditWnd;
//
// Create an edit control and subclass it.
// The details of this particular edit control are not important.
//
hEditWnd = CreateWindow("EDIT", "EDIT Test",
WS_CHILD | WS_VISIBLE | WS_BORDER ,
0, 0, 50, 50,
hWndMain,
NULL,
hInst,
NULL);
//
// Now subclass the window that was just created.
//
lpfnOldWndProc = (FARPROC)SetWindowLong(hEditWnd,
GWL_WNDPROC, (DWORD) SubClassFunc);
.
.
.
//
// Remove the subclass for the edit control.
//
SetWindowLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldWndProc);
//
// Here is a sample subclass function.
//
LONG FAR PASCAL SubClassFunc( HWND hWnd,
UINT Message,
WPARAM wParam,
LONG lParam)
{
//
// When the focus is in an edit control inside a dialog box, the
// default ENTER key action will not occur.
//
if ( Message == WM_GETDLGCODE )
return DLGC_WANTALLKEYS;
return CallWindowProc(lpfnOldWndProc, hWnd, Message, wParam,
lParam);
}
When an application subclasses a subclassed window, the subclasses must be removed in reverse of the order in which they were performed.
Global Subclassing
Global subclassing is similar to instance subclassing. The application calls SetClassLong to globally subclass a window class. As it does with instance subclassing, the application needs the address of the subclass function, and the subclass function must be exported in the application's or the DLL's module definition file.
To globally subclass a window class, the application must have a handle to a window of that class. To get a handle to a window in the desired class, most applications create a window of the class to be globally subclassed. When the application removes the subclass, it needs a handle to a window of the type the application wants to subclass, so creating and keeping a window for this purpose is the best technique. If the application creates a window of the type it wants to subclass, the window is usually hidden. After obtaining a handle to a window of the correct type, the application calls SetClassLong with the window handle, the GCL_WNDPROC option (defined in WINDOWS.H), and the address of the new subclass function. SetClassLong returns a DWORD, which is the address of the original window procedure for the class. The original window procedure address is used in global subclassing in the same way it is used in instance subclassing. Messages are passed to the original window procedure in the same way as in instance subclassing, by calling CallWindowProc.
The following code globally subclasses and removes a subclass to an edit control:
LONG FAR PASCAL SubClassFunc(HWND hWnd,UINT Message,WORD wParam,
LONG lParam);
FARPROC lpfnOldClassWndProc;
HWND hEditWnd;
hEditWnd = CreateWindow("EDIT", "EDIT Test",
WS_CHILD,
0, 0, 50, 50,
hWndMain,
NULL,
hInst,
NULL);
lpfnOldClassWndProc =
(FARPROC)SetClassLong(hEditWnd, GCL_WNDPROC, (DWORD)
SubClassFunc);
.
.
.
//
// To remove the subclass:
//
SetClassLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldClassWndProc);
DestroyWindow(hEditWnd);
Если честно то я не догоняю нахрена тебе это нужно отображать кнопки которые как бы относятся к одному окну а отображаются на другом. Зачем?
Гы-гы-гы :) Я вижу мы решительно друг-друга не понимаем. Нужно сделать как раз наоборот.
Можеш описать или показать концепцию твоего интерфейса,т.е. что должно получиться или привести пример того где ты это видел.
Да ничего особенного - считай нечто вроде браузера с боковой панелью истории. Для начала мне с головой хватит.
В обычных случаях данные методы как ты хочеш не требуются по крайней мере для контролов(т.е. управление расположение контролов в зависимости от расположения сторонних окон).
Мням... Я снова не догнал. Например имеем боковую панель истории в файерфоксе. В ней есть эдит-контрол "найти". При изменении размера (ширины) этой боковой панели у нас меняется: 1 - ширина этого контрола; 2 - размер области вкладок. Я про это, как это все можно нормально реализовать? Т.е. как можно обработать сообщение WM_SIZE посылаемое именно боковой панели, а не главному окну. Ведь размер главного окна не изменяется. И еще: я поковырял через Spy++ файерфокс: можешь мне объяснить - зачем у него главное меню, панель инструментов и эта же панель истории находятся не непосредственно на главном окне, а на дочернем, которое занимает практически всю клиентскую область главного?
имеем класс CInterface который будет служить для базовых операций (т.е. управлением менюшками и общими кнопками а также созданием отдельных оконных модулей(т.е. окон с доп контролами,обработка которых ложится ------------------------------
изменять,и уже не надо будет лезть в глобальное состояние всего интерфейса а скажем только обратится к классу отдельного модуля.
Понял пока только на уровне теории.
Хотя конечно интерфейс простой то не стоит так заморачиваться,а просто писать как пишеш обычно.
По моему у меня он простой. Просто голова пока как-то неправильно работает :)
Ладно, будем разбираться.
Пришел в 3 ночи с моря и кажется всё понял. :)
Что понял?