Поделиться через


Использование 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, при этом 0 делает окно полностью прозрачным и 255 делает его полностью непрозрачным. Этот параметр имитирует более универсальную функцию BLENDFUNCTIONAlphaBlend.

Чтобы сделать это окно снова полностью непрозрачным, уберите бит 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>
...

Дополнительные сведения об изменении манифеста приложения см. здесь: манифесты приложений