Использование Windows
В примерах в этом разделе описывается выполнение следующих задач:
- Создание главного окна
- Создание, перечисление и изменение размера дочерних окон
- Уничтожение окна
- Использование многоуровневой оси Windows
Создание главного окна
Первое окно, которое создает приложение, обычно является основным окном. Главное окно создается с помощью функции CreateWindowEx , указывая класс окна, имя окна, стили окна, размер, положение, дескриптор меню, дескриптор экземпляра и данные создания. Главное окно принадлежит классу окна, определяемому приложением, поэтому необходимо зарегистрировать класс окна и предоставить процедуру окна для класса перед созданием главного окна.
Большинство приложений обычно используют стиль WS_OVERLAPPEDWINDOW для создания главного окна. Этот стиль предоставляет окно заголовку, меню окна, границу размера и свернуть и развернуть кнопки. Функция CreateWindowEx возвращает дескриптор, который однозначно идентифицирует окно.
В следующем примере создается главное окно, принадлежащее классу окна, определяемому приложением. Имя окна, главное окно, появится в строке заголовка окна. Сочетая стили 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
hinst, // 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 после создания главного окна. Это делается, так как система не отображает главное окно после его создания автоматически. Передав флаг SW_SHOWDEFAULT в ShowWindow, приложение позволяет программе, запускающей приложение, задать начальное состояние главного окна. Функция UpdateWindow отправляет окно его первого WM_PAINT сообщения.
Создание, перечисление и изменение размера дочерних окон
Клиентскую область окна можно разделить на разные функциональные области с помощью дочерних окон. Создание дочернего окна похоже на создание главного окна— используйте функцию CreateWindowEx . Чтобы создать окно определенного приложением класса окна, необходимо зарегистрировать класс окна и предоставить процедуру окна перед созданием дочернего окна. При создании окна необходимо предоставить дочернему окну стиль WS_CHILD и указать родительское окно для дочернего окна.
В следующем примере клиентская область основного окна приложения делится на три функциональные области, создавая три дочерних окна равных размеров. Каждое дочернее окно совпадает с высотой клиентской области главного окна, но каждая из них составляет одну треть ее ширины. Главное окно создает дочерние окна в ответ на сообщение WM_CREATE , которое главное окно получает во время собственного процесса создания окна. Так как каждое дочернее окно имеет стиль WS_BORDER , каждая из них имеет тонкую границу линии. Кроме того, поскольку стиль WS_VISIBLE не указан, каждое дочернее окно изначально скрыто. Обратите внимание, что каждое дочернее окно назначается идентификатором дочернего окна.
Размеры основного окна и положение дочерних окон в ответ на сообщение WM_SIZE , которое получает главное окно при изменении его размера. В ответ на WM_SIZE основное окно извлекает измерения своей клиентской области с помощью функции GetClientRect, а затем передает измерения функции EnumChildWindows. EnumChildWindows передает дескриптор каждому дочернему окну, в свою очередь, в функцию обратного вызова EnumChildProc . Размеры и позиции каждого дочернего окна, вызывая функцию MoveWindow ; размер и положение основаны на измерениях клиентской области главного окна и идентификатора дочернего окна. После этого EnumChildProc вызывает функцию ShowWindow, чтобы сделать окно видимым.
#define ID_FIRSTCHILD 100
#define ID_SECONDCHILD 101
#define ID_THIRDCHILD 102
LONG APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 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.
GetClientRect(hwnd, &rcClient);
EnumChildWindows(hwnd, EnumChildProc, (LPARAM) &rcClient);
return 0;
// Process other messages.
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
BOOL CALLBACK EnumChildProc(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;
}
Уничтожение окна
Функцию DestroyWindow можно использовать для уничтожения окна. Как правило, приложение отправляет сообщение WM_CLOSE перед уничтожением окна, предоставляя окне возможность запрашивать подтверждение пользователя до того, как окно будет уничтожено. Окно, включающее меню окна, автоматически получает сообщение WM_CLOSE, когда пользователь нажимает кнопку "Закрыть" в меню окна. Если пользователь подтверждает, что окно должно быть уничтожено, приложение вызывает DestroyWindow. Система отправляет сообщение WM_DESTROY в окно после его удаления с экрана. В ответ на WM_DESTROY окно сохраняет свои данные и освобождает все выделенные ресурсы. Главное окно завершает обработку WM_DESTROY путем вызова функции PostQuitMessage, чтобы выйти из приложения.
В следующем примере показано, как запрашивать подтверждение пользователя перед уничтожением окна. В ответ на WM_CLOSE отображается диалоговое окно с кнопками "Да", "Нет" и "Отмена ". Если пользователь нажимает кнопку "Да", вызывается DestroyWindow ; в противном случае окно не уничтожается. Так как приложение обрабатывает сообщение WM_CLOSE , 0
возвращается во всех случаях. Так как разрушенное окно является главным окном, в примере вызывается PostQuitMessage в ответ на WM_DESTROY.
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);
return 0;
case WM_DESTROY:
// Post the WM_QUIT message to
// quit the application terminate.
PostQuitMessage(0);
return 0;
Использование многоуровневой оси Windows
Чтобы диалоговое окно появилось как полупрозрачное окно, сначала создайте диалоговое окно как обычно. Затем на WM_INITDIALOG задайте многоуровневый бит расширенного стиля окна и вызовите SetLayeredWindowAttributes с нужным альфа-значением. Код может выглядеть следующим образом:
// Set WS_EX_LAYERED on this window
SetWindowLong(hwnd,
GWL_EXSTYLE,
GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// Make this window 70% alpha
SetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);
Обратите внимание, что третий параметр SetLayeredWindowAttributes — это значение, которое варьируется от 0 до 255, при этом окно полностью прозрачно и 255 делает его полностью непрозрачным. Этот параметр имитирует более универсальный BLENDFUNCTION функции AlphaBlend.
Чтобы сделать это окно полностью непрозрачным, удалите WS_EX_LAYERED бит, вызвав SetWindowLong, а затем попросите окно перенакрасить. Удаление бита требуется, чтобы система знала, что она может освободить некоторую память, связанную с слоем и перенаправлением. Код может выглядеть следующим образом:
// Remove WS_EX_LAYERED from this window styles
SetWindowLong(hwnd,
GWL_EXSTYLE,
GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
// Ask the window and its children to repaint
RedrawWindow(hwnd,
NULL,
NULL,
RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
Чтобы использовать многоуровневые дочерние окна, приложение должен объявить себя в манифесте с поддержкой Windows 8.
Для Windows 10/11 этот фрагмент совместимости можно включить в него app.manifest
, чтобы сделать его Windows 10 с поддержкой:
...
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 GUID -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
...
Дополнительные сведения об изменении манифеста приложения см. здесь: манифесты приложений