Системные команды, определяющие размер и расположение окна:
Команда
Описание
SC_CLOSE
Закрывает окно. Эта команда
посылает окну сообщение WM_CLOSE. При этом окно может выполнить любые
действия, которые необходимо совершить перед уничтожением окна.
SC_MAXIMIZE
Разворачивает окно.
SC_MINIMIZE
Сворачивает окно.
SC_RESTORE
Восстанавливает предыдущую
позицию и размер свернутого или развернутого окна.
SC_SIZE
Генерирует команду Size.
Пользователь может изменить размер окна с помощью мыши или клавиатуры.
35. Функции, управляющие размером и позицией окна
После создания окна приложение может изменить его размер и позицию с
помощью функций SetWindowPlacement(),
MoveWindow(), SetWindowPos() или DeferWindowPos(). С помощью функции SetWindowPlacement() можно
задать позицию свернутого и развернутого окна, размер и позицию
восстановленного окна, а также состояние развернутости (show state).
Функции MoveWindow() и SetWindowPos() очень
похожи, обе позволяют установить размер и позицию отдельного окна
приложения. Однако при этом функция SetWindowPos() включает набор флагов,
с помощью которых можно установить состояние развернутости окна, а
функция MoveWindow()
не содержит этих флагов. С помощью функций BeginDeferWindowPos(), DeferWindowPos()
и EndDeferWindowPos()
можно установить размер, позицию, положение в Z-порядке и состояние
развернутости сразу для нескольких окон.
Приложение может получить координаты прямоугольника, ограничивающего
окно, с помощью функции GetWindowRect().
Эта функция помещает в структуру типа RECT координаты верхнего левого и
нижнего правого углов прямоугольника, ограничивающего окно. Координаты
вычисляются относительно верхнего левого угла экрана, даже для дочернего
окна. С помощью функции ScreenToClient()
или MapWindowPoints()
можно преобразовать экранные координаты дочернего окна в координаты,
вычисленные относительно верхнего левого угла клиентской области
родительского окна.
Функция GetClientRect()
позволяет получить координаты клиентской области окна. Эта функция
помещает в структуру типа RECT координаты верхнего левого и нижнего
правого углов клиентской области окна, но координаты вычисляются
относительно самой клиентской области. Это означает, что координаты
верхнего левого угла клиентской области всегда будут равны (0, 0), а
координаты нижнего правого угла будут равны ширине и высоте клиентской
области.
Функция CascadeWindows()
располагает каскадом окна на рабочем столе или располагает каскадом
дочерние окна определенного родительского окна. Функция TileWindows() располагает окна на
рабочем столе или дочерние окна на поверхности родительского окна таким
образом, чтобы окна не перекрывали друг друга.
36.
Сообщения, связанные с размером и позицией окна
Windows посылает окну сообщение WM_GETMINMAXINFO прежде чем изменить
его размер или позицию. Например, это сообщение посылается окну, если
пользователь выбирает команду Move или Size из системного меню, а также
если пользователь кликает на рамку или заголовок окна. Сообщение
WM_GETMINMAXINFO также генерируется, если приложение вызывает функцию SetWindowPos(), чтобы
изменить размер или позицию окна. Сообщение WM_GETMINMAXINFO содержит
указатель на структуру типа MINMAXINFO, в которой хранятся позиция и
размер развернутого окна по умолчанию, а также минимальный и
максимальный размеры окна (minimum and maximum tracking sizes).
Приложение может изменить значения по умолчанию, обрабатывая сообщение
WM_GETMINMAXINFO и изменяя нужное поле структуры MINMAXINFO. Только
окна, имеющие стиль WS_THICKFRAME или WS_CAPTION, могут получать
сообщение WM_GETMINMAXINFO. Окно стиля WS_THICKFRAME получает это
сообщение во время создания окна или при изменении его позиции или
размера.
Windows посылает окну сообщение WM_WINDOWPOSCHANGING прежде чем
изменить его размер, позицию, положение в Z-порядке или состояние
развернутости. Сообщение WM_WINDOWPOSCHANGING содержит указатель на
структуру типа WINDOWPOS, которая определяет новый рамер, позицию,
положение в Z-порядке и состояние развернутости окна.
После изменения рамера, позиции, положения в Z-порядке или состояния
развернутости окна Windows посылает окну сообщение WM_WINDOWPOSCHANGED.
Это сообщение содержит указатель на структуру типа WINDOWPOS, которая
информирует о новом рамере, позиции, положении в Z-порядке и состоянии
развернутости окна. Изменение значений полей структуры, на которую
указывает указатель сообщения WM_WINDOWPOSCHANGED, никак не влияет на
характеристики окна. Окно, которое обрабатывает сообщения WM_SIZE и
WM_MOVE должно передавать сообщение WM_WINDOWPOSCHANGED функции DefWindowProc(). В
противном случае Windows не будет посылать данному окну сообщения
WM_SIZE и WM_MOVE.
При создании окна или изменении его размеров Windows посылает окну
сообщение WM_NCCALCSIZE. Windows использует это сообщение для вычисления
размера клиентской области окна и ее позиции относительно верхнего
левого угла окна. Обычно окно передает это сообщение функции DefWindowProc(), однако,
оно может быть полезным для приложений, которые настраивают неклиентскую
область окна или
сохраняют части клиентской области при изменении размеров окна.
37.
Уничтожение окна
Приложение может уничтожить все окна, которые оно создает. Для
уничтожения окон используется функция DestroyWindow(). Когда окно
уничтожается, система скрывает его, если оно было видимым, и затем
удаляет все внутренние данные, связанные с этим окном. В результате
дескриптор окна становится недействительным и приложение больше не может
его использовать.
Приложение уничтожает множество окон вскоре после их создания.
Например, приложение обычно уничтожает диалоговые окна, как только
получает от пользователя удовлетворительный ответ, позволяющий
продолжать работу. Перед завершением работы приложение уничтожает
главное окно программы.
Перед уничтожением окна приложение должно сохранить или удалить все
данные, связанные с ним, а также освободить все системные ресурсы,
выделенные под это окно. Если приложение не освободит ресурсы, Windows
освободит любые ресурсы, не освобожденные приложением.
Уничтожение окна никак не влияет на класс окна, с помощью которого оно
было создано. С помощью этого класса по-прежнему можно создавать окна, и
все существующие окна этого класса продолжают работать. Уничтожение окна
приводит к уничтожению всех его потомков. Функция DestroyWindow() посылает сообщение
WM_DESTROY сначала самому окну, затем всем его дочерним окнам и потомкам.
Окно, которое имеет системное меню, получает сообщение WM_CLOSE, когда
пользователь выбирает команду "Закрыть". Обрабатывая это сообщение, окно
может запросить у пользователя подтверждение на закрытие окна. Если
пользователь подтвердит свое намерение закрыть данное окно, приложение
может вызвать функцию DestroyWindow(),
чтобы уничтожить окно.
Если уничтожаемое окно является активным, то после его уничтожения
активным становится другое окно. Какое именно окно станет активным,
можно определить с помощью комбинации клавиш ALT+ESC. Окно, которое
становится активным, затем определяет, какое окно получит фокус ввода с
клавиатуры (keyboard focus).
38.
Как создать главное окно
Как правило, первое окно, создаваемое приложением, является главным
окном. Для создания главного окна следует использовать функцию CreateWindowEx(), которая
определяет класс окна, имя окна, стили, размер и позицию окна,
дескриптор меню, дескриптор копии приложения (instance handle) и
дополнительные данные (creation data). Главное окно принадлежит к
определяемому приложением классу окна, поэтому Вы должны
зарегистрировать класс окна и написать функцию окна прежде чем создавать
главное окно.
Большинство приложений используют для главного окна стиль
WS_OVERLAPPEDWINDOW. Окна этого стиля имеют заголовок, системное меню,
рамку, позволяющую изменять размер окна, кнопки свертывания и
развертывания. Функция CreateWindowEx()
возвращает дескриптор (handle), который идентифицирует окно уникальным
образом.
В приведенном ниже примере создается окно, принадлежащее к
определяемому приложением классу окна. Имя окна, "Main Window", появится
в заголовке окна. Путем комбинации стилей WS_VSCROLL и WS_HSCROLL со
стилем WS_OVERLAPPEDWINDOW приложение создает главное окно с
вертикальной и горизонтальной полосами прокрутки в добавление к тем
компонентам, которые обеспечивает стиль WS_OVERLAPPEDWINDOW. С помощью
константы CW_USEDEFAULT устанавливаются заданные системой по умолчанию
позиция и размер окна. Поскольку вместо дескриптора меню указывается
NULL, окно будет иметь меню, определенное для класса окна.
HINSTANCE hinst; HWND hwndMain;
// Create the main window. hwndMain = CreateWindowEx( 0, // no extended styles "MainWClass", // class name "Main Window", // window name WS_OVERLAPPEDWINDOW | // overlapped window WS_HSCROLL | // horizontal scroll bar WS_VSCROLL, // vertical scroll bar CW_USEDEFAULT, // default horizontal position
CW_USEDEFAULT, // default vertical position CW_USEDEFAULT, // default width CW_USEDEFAULT, // default height (HWND) NULL, // no parent or owner window (HMENU) NULL, // class menu used hinstance, // instance handle NULL); // no window creation data
if (!hwndMain) return FALSE;
// Show the window using the flag specified by the program // that started the application, and send the application // a WM_PAINT message. ShowWindow(hwndMain, SW_SHOWDEFAULT); UpdateWindow(hwndMain);
Обратите внимание, что после создания главного окна вызывается функция ShowWindow(). Это
необходимо сделать, т.к. Windows не отображает автоматически окно после
его создания. Передавая флаг SW_SHOWDEFAULT функции ShowWindow(), приложение позволяет
программе, которая запустила данное приложение, самой устанавливать
начальное состояние развернутости (show state) главного окна. Функция UpdateWindow() посылает
окну сообщение WM_PAINT.
39.
Работа с дочерними окнами
Вы можете разделить клиентскую область окна на различные функциональные
области с помощью дочерних окон. Создание дочернего окна напоминает
создание главного окна: Вы должны использовать функцию CreateWindowEx(). Чтобы создать окно
определенного приложением класса окна (application-defined window
class), Вы должны зарегистрировать класс окна и указать функцию окна
перед созданием самого дочернего окна. Для дочернего окна Вы должны
задать стиль WS_CHILD. Кроме того, при создании дочернего окна для него
необходимо указать родительское окно.
В приведенном ниже примере клиентская область главного окна приложения
делится на три функциональных области путем создания трех дочерних окон
одинакового размера. Каждое дочернее окно имеет ту же высоту, что и
клиентская область главного окна, но занимает только третью часть его
ширины. Главное окно создает дочерние окна при получении сообщения
WM_CREATE (которое оно получает в процессе своего собственного
создания). Поскольку каждое дочернее окно имеет стиль WS_BORDER, его
граница представляет собой тонкую линию. Кроме того, поскольку не
определен стиль WS_VISIBLE, каждое дочернее окно изначально является
скрытым. Также обратите внимание, что каждому дочернему окну назначается
собственный идентификатор.
Главное окно изменяет размеры и расположение дочерних окон при
получении сообщения WM_SIZE (главное окно получает это сообщение, когда
изменяется его собственный размер). При этом главное окно получает
размеры своей клиентской области, используя функцию GetWindowRect(), и затем передает их
функции EnumChildWindows(). EnumChildWindows(), в свою
очередь, передает дескриптор каждого дочернего окна определенной
приложением функции обратного вызова EnumChildProc(). Эта функция
изменяет размеры и расположение каждого дочернего окна, вызывая функцию MoveWindow(). Производимые
изменения зависят от размеров клиентской области главного окна и
идентификатора дочернего окна. В заключение EnumChildProc() вызывает функцию ShowWindow(), чтобы
сделать окно видимым.
LONG APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam) HWND hwnd; UINT uMsg; UINT wParam; LONG lParam; { RECT rcClient; int i;
switch(uMsg) { case WM_CREATE: // creating main window // Create three invisible child windows. for (i = 0; i < 3; i++) CreateWindowEx(0, "ChildWClass", (LPCTSTR) NULL, WS_CHILD | WS_BORDER, 0,0,0,0, hwnd, (HMENU) (int) (ID_FIRSTCHILD + i), hinst, NULL); return 0;
case WM_SIZE: // main window changed size // Get the dimensions of the main window's client // area, and enumerate the child windows. Pass the // dimensions to the child windows during enumeration.
BOOL CALLBACK EnumChildProc(hwndChild, lParam) HWND hwndChild; LPARAM lParam; { LPRECT rcParent; int i, idChild;
// Retrieve the child-window identifier. Use it to set the // position of the child window. idChild = GetWindowLong(hwndChild, GWL_ID); if (idChild == ID_FIRSTCHILD) i = 0; else if (idChild == ID_SECONDCHILD) i = 1; else i = 2;
// Size and position the child window. rcParent = (LPRECT) lParam; MoveWindow(hwndChild, (rcParent->right / 3) * i, 0, rcParent->right / 3, rcParent->bottom, TRUE);
// Make sure the child window is visible. ShowWindow(hwndChild, SW_SHOW); return TRUE; }
40.
Как уничтожить окно
Для уничтожения окна Вы можете использовать функцию DestroyWindow(). Как правило,
приложение посылает сообщение WM_CLOSE перед уничтожением окна,
предоставляя окну возможность запросить у пользователя подтверждение на
завершение работы с окном. Окно, у которого есть системное меню,
автоматически получает сообщение WM_CLOSE, когда пользователь выбирает
из меню команду Close. Если пользователь подтверждает, что окно должно
быть уничтожено, приложение вызывает функцию DestroyWindow(). Windows посылает
окну сообщение WM_DESTROY после его удаления с экрана. При получении
сообщения WM_DESTROY окно должно сохранить нужные данные и освободить
все ресурсы, которые были для него выделены. В завершение обработки
сообщения WM_DESTROY главное окно вызывает функцию PostQuitMessage(), чтобы завершить
работу приложения.
Приведенный ниже пример показывает, как запросить у пользователя
подтверждение перед уничтожением окна. При получении сообщения WM_CLOSE
в примере отображается диалоговое окно, которое содержит кнопки Yes, OK
и Cancel. Если пользователь нажимает кнопку Yes, вызывается функция DestroyWindow(); в
противном случае окно не уничтожается. Поскольку разрушаемое окно
является главным окном, при обработке сообщения WM_DESTROY вызывается
функция PostQuitMessage().
case WM_CLOSE: // Create the message box. If the user clicks // the Yes button, destroy the main window. if (MessageBox(hwnd, szConfirm, szAppName, MB_YESNOCANCEL) == IDYES) DestroyWindow(hwndMain); else return 0;
case WM_DESTROY: // Post the WM_QUIT message to // quit the application terminate. PostQuitMessage(0); return 0;