Характеристики окон

В этом обзоре рассматриваются функции окон, такие как типы окон, состояния, размер и положение.

Типы окон

Этот раздел содержит следующие разделы, описывающие типы окон.

Перекрывающиеся окна

Перекрывающееся окно — это окно верхнего уровня (не дочернее окно), которое имеет строку заголовка, границу и клиентную область; он служит окном main приложения. Он также может иметь меню окна, кнопки свернуть и развернуть, а также полосы прокрутки. Перекрывающееся окно, используемое в качестве окна main, обычно включает все эти компоненты.

Задав стиль WS_OVERLAPPED или WS_OVERLAPPEDWINDOW в функции CreateWindowEx , приложение создает перекрывающееся окно. Если вы используете стиль WS_OVERLAPPED , окно имеет строку заголовка и границу. Если вы используете стиль WS_OVERLAPPEDWINDOW , окно имеет заголовок окна, границу размера, меню окна, а также кнопки свернуть и развернуть.

Всплывающие окна

Всплывающее окно — это особый тип перекрывающихся окон, используемый для диалоговых окон, окон сообщений и других временных окон, которые отображаются за пределами окна main приложения. Заголовки являются необязательными для всплывающих окон; В противном случае всплывающие окна совпадают с перекрывающимися окнами стиля WS_OVERLAPPED .

Чтобы создать всплывающее окно, укажите стиль WS_POPUP в createWindowEx. Чтобы включить строку заголовка, укажите стиль WS_CAPTION . Используйте стиль WS_POPUPWINDOW для создания всплывающего окна с границей и меню окна. Стиль WS_CAPTION должен сочетаться со стилем WS_POPUPWINDOW , чтобы сделать меню окна видимым.

Дочерние окна

Дочернее окно имеет стиль WS_CHILD и ограничивается клиентской областью родительского окна. Приложение обычно использует дочерние окна для разделения клиентской области родительского окна на функциональные области. Чтобы создать дочернее окно, укажите стиль WS_CHILD в функции CreateWindowEx .

Дочернее окно должно иметь родительское окно. Родительским окном может быть перекрывающееся окно, всплывающее окно или даже другое дочернее окно. Родительское окно указывается при вызове CreateWindowEx. Если указать стиль WS_CHILD в CreateWindowEx , но не указать родительское окно, система не создаст окно.

В дочернем окне есть клиентская область, но нет других функций, если они не запрашиваются явным образом. Приложение может запросить заголовок окна, меню окна, кнопки свернуть и развернуть, границу и полосы прокрутки для дочернего окна, но в дочернем окне не может быть меню. Если приложение указывает дескриптор меню при регистрации класса дочернего окна или создает дочернее окно, дескриптор меню игнорируется. Если стиль границы не указан, система создает окно без границ. Приложение может использовать дочерние окна без границ, чтобы разделить клиентскую область родительского окна, сохраняя при этом невидимые для пользователя деления.

В этом разделе рассматриваются следующие аспекты дочерних окон:

Позиционирования

Система всегда размещает дочернее окно относительно левого верхнего угла клиентской области родительского окна. Никакая часть дочернего окна никогда не отображается за пределами его родительского окна. Если приложение создает дочернее окно, которое больше родительского окна, или размещает дочернее окно таким образом, чтобы некоторые или все дочерние окна выходят за границы родительского окна, система обрезает дочернее окно; то есть часть за пределами клиентской области родительского окна не отображается. Действия, влияющие на родительское окно, также могут повлиять на дочернее окно, как показано ниже.

Родительское окно Дочернее окно
Уничтожаются Удаляется перед уничтожением родительского окна.
Скрытый Скрытые перед скрытием родительского окна. Дочернее окно отображается только в том случае, если отображается родительское окно.
Переехал Перемещается вместе с клиентской областью родительского окна. Дочернее окно отвечает за рисование клиентской области после перемещения.
Показано Отображается после отображения родительского окна.

 

Усечение

Система не автоматически обрезает дочернее окно из клиентской области родительского окна. Это означает, что родительское окно выполняет рисование поверх дочернего окна, если оно выполняет рисование в том же расположении, что и дочернее окно. Однако система обрезает дочернее окно из клиентской области родительского окна, если родительское окно имеет стиль WS_CLIPCHILDREN . Если дочернее окно обрезано, родительское окно не может нарисовать его.

Дочернее окно может перекрывать другие дочерние окна в той же клиентской области. Дочернее окно, которое использует то же родительское окно, что и одно или несколько других дочерних окон, называется одноуровневым окном. Одноуровневые окна могут рисовать в клиентской области друг друга, если только одно из дочерних окон не имеет стиля WS_CLIPSIBLINGS . Если дочернее окно имеет этот стиль, любая часть его одноуровневого окна, расположенная в дочернем окне, обрезается.

Если окно имеет стиль WS_CLIPCHILDREN или WS_CLIPSIBLINGS , происходит небольшое снижение производительности. Каждое окно занимает системные ресурсы, поэтому приложение не должно использовать дочерние окна без разбора. Для обеспечения оптимальной производительности приложение, которому необходимо логически разделить main окно, должно сделать это в процедуре окна main, а не с помощью дочерних окон.

Связь с родительским окном

Приложение может изменить родительское окно существующего дочернего окна, вызвав функцию SetParent . В этом случае система удаляет дочернее окно из клиентской области старого родительского окна и перемещает его в клиентскую область нового родительского окна. Если SetParent указывает дескриптор NULL , окно рабочего стола становится новым родительским окном. В этом случае дочернее окно отрисовывается на рабочем столе за пределами любого другого окна. Функция GetParent извлекает дескриптор родительского окна дочернего окна.

Родительское окно возвращает часть клиентской области дочернему окну, а дочернее окно получает все входные данные из этой области. Класс окна не обязательно должен быть одинаковым для каждого из дочерних окон родительского окна. Это означает, что приложение может заполнить родительское окно дочерними окнами, которые выглядят по-разному и выполняют различные задачи. Например, диалоговое окно может содержать множество типов элементов управления, каждый из которых является дочерним окном, которое принимает различные типы данных от пользователя.

Дочернее окно имеет только одно родительское окно, но родительское может иметь любое количество дочерних окон. Каждое дочернее окно, в свою очередь, может иметь дочерние окна. В этой цепочке окон каждое дочернее окно называется потомком исходного родительского окна. Приложение использует функцию IsChild , чтобы определить, является ли данное окно дочерним окном или окном-потомком данного родительского окна.

Функция EnumChildWindows перечисляет дочерние окна родительского окна. Затем EnumChildWindows передает дескриптор каждому дочернему окну в определяемую приложением функцию обратного вызова. Также перечисляются дочерние окна заданного родительского окна.

Сообщения

Система передает входные сообщения дочернего окна непосредственно в дочернее окно; сообщения не передаются через родительское окно. Единственное исключение — если дочернее окно было отключено функцией EnableWindow . В этом случае система передает все входные сообщения, которые ушли бы в дочернее окно, в родительское окно. Это позволяет родительскому окну проверять входные сообщения и при необходимости включать дочернее окно.

Дочернее окно может иметь уникальный целочисленный идентификатор. Идентификаторы дочерних окон важны при работе с окнами управления. Приложение направляет действие элемента управления, отправляя ему сообщения. Приложение использует идентификатор дочернего окна элемента управления для направления сообщений в элемент управления . Кроме того, элемент управления отправляет уведомления в родительское окно. Сообщение уведомления содержит идентификатор дочернего окна элемента управления, который родительский элемент использует для определения того, какой элемент управления отправил сообщение. Приложение задает идентификатор дочернего окна для других типов дочерних окон, задавая для параметра hMenu функции CreateWindowEx значение, а не дескриптор меню.

Многоуровневые окна

Многослойное окно может значительно повысить производительность и визуальные эффекты для окна, которое имеет сложную форму, анимирует его форму или хочет использовать эффекты альфа-смешения. Система автоматически создает и перерисовывает многоуровневые окна и окна базовых приложений. В результате многослойные окна отрисовываются плавно, без мерцания, типичного для сложных оконных областей. Кроме того, многослойные окна могут быть частично полупрозрачными, то есть альфа-смешанными.

Чтобы создать многоуровневое окно, укажите стиль расширенного окна WS_EX_LAYERED при вызове функции CreateWindowEx или вызовите функцию SetWindowLong , чтобы задать WS_EX_LAYERED после создания окна. После вызова CreateWindowEx многоуровневые окна не станут видимыми, пока для этого окна не будет вызвана функция SetLayeredWindowAttributes или UpdateLayeredWindow .

Примечание

Начиная с Windows 8, WS_EX_LAYERED можно использовать с дочерними окнами и окнами верхнего уровня. Предыдущие версии Windows поддерживают WS_EX_LAYERED только для окон верхнего уровня.

 

Чтобы задать уровень непрозрачности или ключ цвета прозрачности для заданного многоуровневого окна, вызовите SetLayeredWindowAttributes. После вызова система по-прежнему может попросить окно закрасить при отображении окна или изменении его размера. Тем не менее, так как система хранит изображение многоуровневого окна, система не будет просить окно рисовать, если его части отображаются в результате относительного перемещения окна на рабочем столе. Устаревшим приложениям не нужно реструктурировать свой код рисования, если они хотят добавить эффекты прозрачности или прозрачности для окна, так как система перенаправляет рисование окон с именем SetLayeredWindowAttributes в память вне экрана и повторно компилирует его для достижения желаемого эффекта.

Для более быстрой и эффективной анимации или, если требуется альфа-канал для каждого пикселя, вызовите UpdateLayeredWindow. UpdateLayeredWindow следует использовать в основном в том случае, если приложение должно напрямую предоставлять форму и содержимое многоуровневого окна, не используя механизм перенаправления, который система предоставляет через SetLayeredWindowAttributes. Кроме того, использование UpdateLayeredWindow напрямую использует память более эффективно, так как системе не требуется дополнительная память, необходимая для хранения образа перенаправленного окна. Для максимальной эффективности анимации окон вызовите UpdateLayeredWindow , чтобы изменить положение и размер многоуровневого окна. Обратите внимание, что после вызова SetLayeredWindowAttributes последующие вызовыUpdateLayeredWindow завершатся ошибкой, пока бит стиля слоев не будет очищен и не будет снова задан.

Проверка попадания многослойного окна основана на форме и прозрачности окна. Это означает, что области окна с цветовой клавишей или альфа-значение которых равно нулю, будут пропускать сообщения мыши. Однако если многослойное окно имеет WS_EX_TRANSPARENT расширенный стиль окна, форма многослойного окна будет игнорироваться, а события мыши будут передаваться в другие окна под многослойным окном.

Message-Only Windows

Окно только для сообщений позволяет отправлять и получать сообщения. Он невидим, не имеет z-порядка, не может быть перечислен и не получает широковещательные сообщения. Окно просто отправляет сообщения.

Чтобы создать окно только для сообщений, укажите константу HWND_MESSAGE или дескриптор существующего окна только для сообщений в параметре hWndParent функции CreateWindowEx . Вы также можете изменить существующее окно на окно только для сообщений, указав HWND_MESSAGE в параметре hWndNewParent функции SetParent .

Чтобы найти окна только для сообщений, укажите HWND_MESSAGE в параметре hwndParent функции FindWindowEx . Кроме того, FindWindowEx выполняет поиск окон только для сообщений, а также окон верхнего уровня, если параметры hwndParent и hwndChildAfter имеют значение NULL.

Связи окон

Существует множество способов связи окна с пользователем или другим окном. Окно может быть собственным окном, окном переднего плана или фоновым окном. Окно также имеет Z-порядок относительно других окон. Дополнительные сведения см. в следующих разделах:

Окна переднего плана и фона

Каждый процесс может иметь несколько потоков выполнения, и каждый поток может создавать окна. Поток, создавший окно, с которым в данный момент работает пользователь, называется потоком переднего плана, а окно — окном переднего плана. Все остальные потоки являются фоновыми потоками, а окна, созданные фоновыми потоками, называются фоновыми окнами.

Каждый поток имеет уровень приоритета, который определяет количество времени ЦП, которое поток получает. Хотя приложение может задать уровень приоритета своих потоков, обычно поток переднего плана имеет несколько более высокий уровень приоритета, чем фоновые потоки. Так как он имеет более высокий приоритет, поток переднего плана получает больше времени ЦП, чем фоновые потоки. Поток переднего плана имеет обычный базовый приоритет 9; фоновый поток имеет обычный базовый приоритет 7.

Пользователь задает окно переднего плана, щелкнув окно или используя сочетание клавиш ALT+TAB или ALT+ESC. Чтобы получить дескриптор в окне переднего плана, используйте функцию GetForegroundWindow . Чтобы проверка, является ли окно приложения окном переднего плана, сравните дескриптор, возвращенный Командлетом GetForegroundWindow, с дескриптором окна приложения.

Приложение задает окно переднего плана с помощью функции SetForegroundWindow .

Система ограничивает, какие процессы могут задавать окно переднего плана. Процесс может задать окно переднего плана только в следующих случаях:

  • Выполняются все следующие условия:
    • Процесс, вызывающий SetForegroundWindow, принадлежит классическому приложению, а не приложению UWP или приложению Магазина Windows, предназначенному для Windows 8 или 8.1.
    • Процесс переднего плана не отключал вызовы SetForegroundWindow предыдущим вызовом функции LockSetForegroundWindow .
    • Истекло время ожидания блокировки переднего плана (см . SPI_GETFOREGROUNDLOCKTIMEOUT в SystemParametersInfo).
    • Меню не активны.
  • Кроме того, выполняется по крайней мере одно из следующих условий:
    • Вызывающий процесс является процессом переднего плана.
    • Вызывающий процесс был запущен процессом переднего плана.
    • В настоящее время отсутствует окно переднего плана и, следовательно, процесс переднего плана.
    • Вызывающий процесс получил последнее входное событие.
    • Выполняется отладка процесса переднего плана или вызывающего процесса.

Процесс может быть лишен права на настройку окна переднего плана, даже если он соответствует этим условиям.

Процесс, который может задать окно переднего плана, может позволить другому процессу задать окно переднего плана путем вызова функции AllowSetForegroundWindow или путем вызова функции BroadcastSystemMessage с флагом BSF_ALLOWSFW . Процесс переднего плана может отключить вызовы SetForegroundWindow , вызвав функцию LockSetForegroundWindow .

Принадлежащие windows

Перекрывающееся или всплывающее окно может принадлежать другому перекрывающимся или всплывающему окну. Владение устанавливает несколько ограничений на окно.

  • Принадлежащего окну всегда находится выше владельца в Z-порядке.
  • Система автоматически уничтожает принадлежащего окну при уничтожении его владельца.
  • Собственное окно скрывается, когда его владелец свернут.

Только перекрывающееся или всплывающее окно может быть окном-владельцем; дочернее окно не может быть окном-владельцем. Приложение создает собственное окно, указывая дескриптор окна владельца в качестве параметра hwndParentcreateWindowEx при создании окна со стилем WS_OVERLAPPED или WS_POPUP . Параметр hwndParent должен идентифицировать перекрывающееся или всплывающее окно. Если hwndParent определяет дочернее окно, система назначает права владения родительскому окну верхнего уровня дочернего окна. После создания собственного окна приложение не может передать права владения окном другому окну.

Диалоговые окна и окна сообщений являются собственными окнами по умолчанию. Приложение указывает окно владельца при вызове функции, которая создает диалоговое окно или окно сообщения.

Приложение может использовать функцию GetWindow с флагом GW_OWNER , чтобы получить дескриптор владельцу окна.

Z-порядок

Z-порядок окна указывает положение окна в стеке перекрывающихся окон. Этот стек окон ориентирован вдоль воображаемой оси, оси Z, простирающейся наружу от экрана. Окно, находящееся в верхней части z-порядка, перекрывает все остальные окна. Окно в нижней части z-порядка перекрывается всеми остальными окнами.

Система поддерживает z-порядок в одном списке. Он добавляет окна в Z-порядок в зависимости от того, являются ли они самыми верхними окнами, окнами верхнего уровня или дочерними окнами. Самое верхнее окно перекрывает все остальные окна, не являющиеся самыми верхними, независимо от того, является ли это активным окном или окном переднего плана. Самое верхнее окно имеет стиль WS_EX_TOPMOST . Все самые верхние окна отображаются в z-порядке перед любыми окнами, не являющиеся самыми верхними. Дочернее окно группируется с родительским окном в Z-порядке.

Когда приложение создает окно, система помещает его в начало z-порядка для окон того же типа. Вы можете использовать функцию BringWindowToTop , чтобы переместить окно в верхнюю часть z-порядка для окон того же типа. Вы можете изменить порядок z-порядка с помощью функций SetWindowPos и DeferWindowPos .

Пользователь изменяет z-порядок, активируя другое окно. Система размещает активное окно в верхней части z-порядка для окон того же типа. Когда окно попадает в верхнюю часть z-порядка, то и его дочерние окна. Функцию GetTopWindow можно использовать для поиска во всех дочерних окнах родительского окна и возврата дескриптора дочернему окну, который является самым высоким в Z-порядке. Функция GetNextWindow извлекает дескриптор следующего или предыдущего окна в z-порядке.

Отображение состояния окна

В любой момент времени окно может быть активным или неактивным; скрытые или видимые; и свернутые, развернутые или восстановленные. Эти качества в совокупности называются состоянием отображения окна. В следующих разделах рассматривается состояние отображения окна.

Активное окно

Активное окно — это окно верхнего уровня приложения, с которым в данный момент работает пользователь. Чтобы пользователь легко идентифицировать активное окно, система помещает его в верхнюю часть Z-порядка и изменяет цвет его заголовка и границы на определенные системой цвета активных окон. Только окно верхнего уровня может быть активным окном. Когда пользователь работает с дочерним окном, система активирует родительское окно верхнего уровня, связанное с дочерним окном.

Одновременно активируется только одно окно верхнего уровня в системе. Пользователь активирует окно верхнего уровня, щелкнув его (или одно из его дочерних окон) или используя сочетание клавиш ALT+ESC или ALT+TAB. Приложение активирует окно верхнего уровня, вызывая функцию SetActiveWindow . Другие функции могут привести к активации системы другого окна верхнего уровня, включая SetWindowPos, DeferWindowPos, SetWindowPlacement и DestroyWindow. Хотя приложение может активировать другое окно верхнего уровня в любое время, чтобы избежать путаницы пользователя, оно должно делать это только в ответ на действия пользователя. Приложение использует функцию GetActiveWindow для получения дескриптора в активное окно.

Когда активация изменяется из окна верхнего уровня одного приложения в окно верхнего уровня другого, система отправляет WM_ACTIVATEAPP сообщение обоим приложениям, уведомляя их об изменении. Когда активация меняется на другое окно верхнего уровня в том же приложении, система отправляет обоим окнам WM_ACTIVATE сообщение.

Отключенные окна

Окно можно отключить. Отключенное окно не получает ввода с клавиатуры или мыши от пользователя, но оно может получать сообщения из других окон, из других приложений и системы. Приложение обычно отключает окно, чтобы запретить пользователю использовать его. Например, приложение может отключить кнопку в диалоговом окне, чтобы запретить пользователю выбрать ее. Приложение может включить отключенное окно в любое время; Включение окна восстанавливает обычные входные данные.

По умолчанию окно включено при создании. Однако приложение может указать стиль WS_DISABLED , чтобы отключить новое окно. Приложение включает или отключает существующее окно с помощью функции EnableWindow . Система отправляет сообщение WM_ENABLE в окно, когда состояние включенной функции изменится. Приложение может определить, включено ли окно, с помощью функции IsWindowEnabled .

Когда дочернее окно отключено, система передает в родительское окно сообщения о входе с помощью мыши. Родительский объект использует сообщения, чтобы определить, следует ли включить дочернее окно. Дополнительные сведения см. в разделе Ввод с помощью мыши.

Только одно окно за раз может принимать ввод с клавиатуры; это окно, как говорят, имеет фокус клавиатуры. Если приложение отключает окно с фокусировкой клавиатуры с помощью функции EnableWindow , оно не только отключается, но и теряет фокус клавиатуры. Затем EnableWindow задает для фокуса клавиатуры значение NULL, что означает, что фокус отсутствует в окне. Если в дочернем окне или другом окне потомка есть фокус клавиатуры, то потомковое окно теряет фокус, когда родительское окно отключено. Дополнительные сведения см. в разделе Ввод с клавиатуры.

Видимость окна

Окно может быть видимым или скрытым. Система отображает видимое окно на экране. Он скрывает скрытое окно , не рисуя его. Если окно видимое, пользователь может производить ввод в окно и видеть вывод окна. Если окно скрыто, оно эффективно отключено. Скрытое окно может обрабатывать сообщения от системы или от других окон, но не может обрабатывать ввод от пользователя или отображать вывод. Приложение задает состояние видимости окна при создании окна. Позже приложение может изменить состояние видимости.

Окно отображается, когда для окна задан стиль WS_VISIBLE . По умолчанию функция CreateWindowEx создает скрытое окно, если приложение не задает стиль WS_VISIBLE . Как правило, приложение задает стиль WS_VISIBLE после создания окна, чтобы сведения о процессе создания были скрыты от пользователя. Например, приложение может скрывать новое окно, настраивая внешний вид окна. Если стиль WS_VISIBLE указан в createWindowEx, система отправляет сообщение WM_SHOWWINDOW в окно после создания окна, но перед его отображением.

Приложение может определить, отображается ли окно, с помощью функции IsWindowVisible . Приложение может отображать (делать видимым) или скрывать окно с помощью функции ShowWindow, SetWindowPos, DeferWindowPos, SetWindowPlacement или SetWindowLong . Эти функции показывают или скрывают окно, устанавливая или удаляя стиль WS_VISIBLE для окна. Они также отправляют сообщение WM_SHOWWINDOW в окно перед отображением или скрытием.

Если окно владельца свернуто, система автоматически скрывает связанные окна, принадлежащие ей. Аналогичным образом при восстановлении окна владельца система автоматически отображает связанные окна, принадлежащие ей. В обоих случаях система отправляет сообщение WM_SHOWWINDOW в собственные окна, прежде чем скрыть или показать их. Иногда приложению может потребоваться скрыть принадлежащие им окна, не сворачивая или не скрывая владельца. В этом случае приложение использует функцию ShowOwnedPopups . Эта функция задает или удаляет стиль WS_VISIBLE для всех принадлежащих окон и отправляет сообщение WM_SHOWWINDOW в принадлежащие окна перед их скрытием или отображением. Скрытие окна владельца не влияет на состояние видимости принадлежащих окон.

Когда отображается родительское окно, также отображаются связанные с ним дочерние окна. Аналогичным образом, когда родительское окно скрыто, его дочерние окна также скрыты. Минимизация родительского окна не влияет на состояние видимости дочерних окон; то есть дочерние окна свернуты вместе с родительским, но стиль WS_VISIBLE не изменяется.

Даже если окно имеет стиль WS_VISIBLE , пользователь может не видеть окно на экране; другие окна могут полностью перекрывать его или быть перемещены за пределы края экрана. Кроме того, к видимому дочернему окну применяются правила обрезки, установленные его отношением "родитель-потомок". Если родительское окно окна не отображается, оно также не будет видимым. Если родительское окно перемещается за край экрана, дочернее окно также перемещается, так как дочернее окно рисуется относительно левого верхнего угла родительского элемента. Например, пользователь может переместить родительское окно, содержащее дочернее окно, достаточно далеко от края экрана, чтобы пользователь не мог видеть дочернее окно, даже если дочернее окно и его родительское окно имеют стиль WS_VISIBLE .

Свернутые, развернутые и восстановленные окна

Развернутое окно — это окно со стилем WS_MAXIMIZE. По умолчанию система расширяет полноэкранное окно, и оно занимает весь экран или, если это дочернее окно, клиентскую область родительского окна. Хотя размер окна можно задать равным размеру развернутого окна, развернутое окно немного отличается. Система автоматически перемещает заголовок окна в верхнюю часть экрана или в верхнюю часть клиентской области родительского окна. Кроме того, система отключает границу размера окна и возможность позиционирования окна в строке заголовка (чтобы пользователь не может переместить окно, перетащив заголовок окна).

Свернутое окно — это окно со стилем WS_MINIMIZE. По умолчанию система уменьшает минимизированное окно до размеров кнопки панели задач и перемещает его на панель задач. Восстановленное окно — это окно, которое было возвращено к предыдущему размеру и положению, т. е. размеру, который он был до свернутого или развернутого.

Если приложение указывает стиль WS_MAXIMIZE или WS_MINIMIZE в функции CreateWindowEx , окно изначально разворачивается или свернуто. После создания окна приложение может использовать функцию CloseWindow , чтобы свернуть окно. Функция ArrangeIconicWindows упорядочивает значки на рабочем столе или упорядочивает свернутые дочерние окна родительского окна в родительском окне. Функция OpenIcon восстанавливает свернутое окно до предыдущего размера и положения.

Функция ShowWindow может свернуть, развернуть или восстановить окно. Он также может задавать состояния видимости и активации окна. Функция SetWindowPlacement включает те же функции, что и ShowWindow, но может переопределять свернутые, развернутые и восстановленные позиции окна по умолчанию.

Функции IsZoomed и IsIconic определяют, развернуто ли данное окно или свернуто соответственно. Функция GetWindowPlacement извлекает свернутые, развернутые и восстановленные позиции окна, а также определяет состояние отображения окна.

Когда система получает команду для развертывания или восстановления свернутого окна, она отправляет окну WM_QUERYOPEN сообщение. Если процедура окна возвращает значение FALSE, система игнорирует команду развернуть или восстановить.

Система автоматически устанавливает размер и положение развернутого окна в соответствии с заданными системой значениями по умолчанию для развернутого окна. Чтобы переопределить эти значения по умолчанию, приложение может вызвать функцию SetWindowPlacement или обработать WM_GETMINMAXINFO сообщение, полученное окном, когда система намерена развернуть окно. WM_GETMINMAXINFO содержит указатель на структуру MINMAXINFO , содержащую значения, которые система использует для установки максимального размера и положения. Замена этих значений переопределяет значения по умолчанию.

Размер и положение окна

Размер и положение окна выражаются в виде ограничивающего прямоугольника, заданного в координатах относительно экрана или родительского окна. Координаты окна верхнего уровня находятся относительно левого верхнего угла экрана; Координаты дочернего окна находятся относительно левого верхнего угла родительского окна. Приложение указывает начальный размер и положение окна при создании окна, но оно может изменить его размер и положение в любое время. Дополнительные сведения см. в разделе Заполненные фигуры.

В этом разделе рассматриваются следующие вопросы.

Размер и положение по умолчанию

Приложение может позволить системе вычислить начальный размер или положение окна верхнего уровня, указав CW_USEDEFAULT в CreateWindowEx. Если приложение задает координаты окна в CW_USEDEFAULT и не создало других окон верхнего уровня, система задает положение нового окна относительно левого верхнего угла экрана; в противном случае он задает позицию относительно позиции окна верхнего уровня, созданного приложением в последнее время. Если для параметров ширины и высоты задано значение CW_USEDEFAULT, система вычисляет размер нового окна. Если приложение создало другие окна верхнего уровня, система основывает размер нового окна на основе размера последнего созданного окна верхнего уровня приложения. Указание CW_USEDEFAULT при создании дочернего или всплывающего окна приводит к тому, что система установит минимальный размер окна по умолчанию.

Размер отслеживания

Система поддерживает минимальный и максимальный размер отслеживания для окна стиля WS_THICKFRAME ; Окно с этим стилем имеет границу размера. Минимальный размер для отслеживания — это наименьший размер окна, который можно получить, перетащив границу размера окна. Точно так же максимальный размер отслеживаемого окна — это самый большой размер окна, который можно получить, перетащив границу размера.

Минимальный и максимальный размеры отслеживания окна задаются как системные значения по умолчанию, когда система создает окно. Приложение может обнаружить значения по умолчанию и переопределить их, обрабатывая сообщение WM_GETMINMAXINFO . Дополнительные сведения см. в разделе Сообщения о размере и расположении.

Системные команды

Приложение с меню окна может изменять размер и положение этого окна, отправляя системные команды. Системные команды создаются, когда пользователь выбирает команды в меню окна. Приложение может эмулировать действие пользователя, отправляя WM_SYSCOMMAND сообщение в окно. Следующие системные команды влияют на размер и положение окна.

Get-Help Описание
SC_CLOSE Закрывает окно. Эта команда отправляет WM_CLOSE сообщение в окно. Окно выполняет все действия, необходимые для очистки и уничтожения себя.
SC_MAXIMIZE Разворачивает окно.
SC_MINIMIZE Сворачивает окно.
SC_MOVE Перемещает окно.
SC_RESTORE Восстанавливает свернутое или развернутое окно до предыдущего размера и положения.
SC_SIZE Запускает команду size. Чтобы изменить размер окна, используйте мышь или клавиатуру.

 

Функции размера и положения

После создания окна приложение может задать размер или положение окна, вызвав одну из нескольких различных функций, включая SetWindowPlacement, MoveWindow, SetWindowPos и DeferWindowPos. SetWindowPlacement задает свернутое положение окна, развернутое положение, восстановленный размер и положение, а также состояние отображения. Функции MoveWindow и SetWindowPos похожи; оба задают размер или положение одного окна приложения. Функция SetWindowPos включает набор флагов, влияющих на состояние отображения окна; MoveWindow не включает эти флаги. Используйте функции BeginDeferWindowPos, DeferWindowPos и EndDeferWindowPos , чтобы одновременно задать положение ряда окон, включая размер, положение, положение в z-порядке и состояние отображения.

Приложение может получить координаты ограничивающего прямоугольника окна с помощью функции GetWindowRect . GetWindowRect заполняет структуру RECT координатами верхнего левого и нижнего правого углов окна. Координаты находятся относительно левого верхнего угла экрана, даже для дочернего окна. Функция ScreenToClient или MapWindowPoints сопоставляет координаты экрана ограничивающего прямоугольника дочернего окна с координатами относительно клиентской области родительского окна.

Функция GetClientRect извлекает координаты клиентской области окна. GetClientRect заполняет структуру RECT координатами верхнего левого и нижнего правого углов клиентской области, но координаты находятся относительно самой клиентской области. Это означает, что координаты верхнего левого угла клиентской области всегда имеют значение (0,0), а координаты правого нижнего угла — это ширина и высота клиентской области.

Функция CascadeWindows каскадирует окна на рабочем столе или каскадирует дочерние окна указанного родительского окна. Функция TileWindows отображает окна на рабочем столе или дочерние окна указанного родительского окна.

Размер и положение сообщений

Система отправляет сообщение WM_GETMINMAXINFO в окно, размер или положение которого изменится. Например, сообщение отправляется, когда пользователь нажимает кнопку Переместить или Размер в меню окна или щелкает границу размера или строку заголовка. сообщение также отправляется, когда приложение вызывает SetWindowPos для перемещения или изменения размера окна. WM_GETMINMAXINFO содержит указатель на структуру MINMAXINFO , содержащую развернутый размер и положение окна по умолчанию, а также минимальные и максимальные размеры отслеживания по умолчанию. Приложение может переопределить значения по умолчанию, обрабатывая WM_GETMINMAXINFO и устанавливая соответствующие элементы MINMAXINFO. Для получения WM_GETMINMAXINFO окно должно иметь стиль WS_THICKFRAME или WS_CAPTION. Окно со стилем WS_THICKFRAME получает это сообщение во время создания окна, а также при его перемещении или размере.

Система отправляет WM_WINDOWPOSCHANGING сообщение в окно, размер которого, положение, положение в z-порядке или состояние отображения в этом окне изменится. Это сообщение содержит указатель на структуру WINDOWPOS , которая указывает новый размер окна, положение, положение в z-порядке и состояние отображения. Задавая элементы WINDOWPOS, приложение может повлиять на новый размер, положение и внешний вид окна.

После изменения размера, положения, положения окна в z-порядке или состояния отображения система отправляет WM_WINDOWPOSCHANGED сообщение в окно. Это сообщение содержит указатель на WINDOWPOS , который сообщает окну о новом размере, положении, позиции в z-порядке и состоянии отображения. Установка элементов структуры WINDOWPOS , передаваемой с помощью WM_WINDOWPOSCHANGED , не влияет на окно. Окно, которое должно обрабатывать WM_SIZE и WM_MOVE сообщений, должно передавать WM_WINDOWPOSCHANGED функции DefWindowProc ; В противном случае система не отправляет WM_SIZE и WM_MOVE сообщения в окно.

Система отправляет сообщение WM_NCCALCSIZE в окно при создании или изменении размера окна. Система использует сообщение для вычисления размера клиентской области окна и положения клиентской области относительно левого верхнего угла окна. Окно обычно передает это сообщение в процедуру окна по умолчанию; Однако это сообщение может быть полезно в приложениях, которые настраивают неклиентную область окна или сохраняют части клиентской области при размере окна. Дополнительные сведения см. в разделе Рисование и рисование.

Анимация окна

Вы можете создавать специальные эффекты при отображении или скрытии окон с помощью функции AnimateWindow . Если окно анимируется таким образом, система будет либо разворачиваться, скользить, либо исчезать окно в зависимости от флагов, указанных в вызове AnimateWindow.

По умолчанию система использует анимацию ролла. При таком эффекте окно открывается (отображается окно) или закрывается (скрывает окно). С помощью параметра dwFlags можно указать, будет ли окно разворачиваться по горизонтали, вертикали или по диагонали.

При указании флага AW_SLIDE система использует анимацию слайдов. При таком эффекте окно отображается для скольжения (с отображением окна) или выдвигается за пределы видимости (скрытие окна). С помощью параметра dwFlags можно указать, будет ли окно скользить по горизонтали, вертикали или по диагонали.

При указании флага AW_BLEND система использует альфа-смешанный затухание.

Вы также можете использовать флаг AW_CENTER , чтобы окно отображалось для сворачивания вовнутрь или расширения наружу.

Макет окна и зеркальное отображение

Макет окна определяет способ размещения текста и объектов интерфейса графических устройств Windows (GDI) в контексте окна или устройства (DC). Для некоторых языков, таких как английский, французский и немецкий, требуется макет слева направо (LTR). Для других языков, таких как арабский и иврит, требуется макет справа налево (RTL). Макет окна применяется к тексту, но также влияет на другие элементы GDI окна, включая растровые изображения, значки, расположение источника, кнопки, каскадные элементы управления деревом, а также увеличивается ли горизонтальная координата при переходе влево или вправо. Например, после того, как приложение настроит макет RTL, источник размещается в правом краю окна или устройства, а число, представляющее горизонтальную координату, увеличивается по мере перемещения влево. Однако макет окна влияет не на все объекты. Например, макет диалоговых окон, окон сообщений и контекстов устройств, не связанных с окном, таких как метафайл и принтер контроллеров домена, должен обрабатываться отдельно. Особенности этих компонентов упоминаются далее в этом разделе.

Оконные функции позволяют указать или изменить макет окна в версиях Windows на арабском и иврите. Обратите внимание, что изменение макета RTL (также называемого зеркальным отображением) не поддерживается для окон со стилем CS_OWNDC или для контроллера домена с GM_ADVANCED графическим режимом.

По умолчанию макет окна — слева направо (LTR). Чтобы задать макет окна RTL, вызовите CreateWindowEx со стилем WS_EX_LAYOUTRTL. Кроме того, по умолчанию дочернее окно (то есть созданное в стиле WS_CHILD и с допустимым родительским параметром hWnd в вызове CreateWindow или CreateWindowEx) имеет тот же макет, что и его родительский. Чтобы отключить наследование зеркального отображения для всех дочерних окон, укажите WS_EX_NOINHERITLAYOUT в вызове CreateWindowEx. Обратите внимание, что зеркальное отображение не наследуется собственными окнами (созданными без стиля WS_CHILD ) или созданными с родительским параметром hWnd в CreateWindowEx , для которого задано значение NULL. Чтобы отключить наследование зеркального отображения для отдельного окна, обработайте сообщение WM_NCCREATEс помощью команд GetWindowLong и SetWindowLong , чтобы отключить флаг WS_EX_LAYOUTRTL . Эта обработка является дополнением к любой другой обработке, необходимой. В следующем фрагменте кода показано, как это делается.

SetWindowLong (hWnd, 
               GWL_EXSTYLE, 
               GetWindowLong(hWnd,GWL_EXSTYLE) & ~WS_EX_LAYOUTRTL))

Для макета по умолчанию можно задать RTL, вызвав SetProcessDefaultLayout(LAYOUT_RTL). Все окна, созданные после вызова, будут зеркально отображаться, но существующие окна не затрагиваются. Чтобы отключить зеркальное отображение по умолчанию, вызовите SetProcessDefaultLayout(0).

Примечание . SetProcessDefaultLayout зеркально отражает контроллеры домена только для зеркальных окон. Чтобы зеркало любой контроллер домена, вызовите SetLayout(hdc, LAYOUT_RTL). Дополнительные сведения см. в описании контекстов зеркального отображения устройств, не связанных с окнами, которые будут приведены далее в этой статье.

Точечные изображения и значки в зеркальном окне также зеркально отображаются по умолчанию. Однако не все из них должны быть зеркальными. Например, те, с текстом, бизнес-логотипом или аналоговыми часами не должны быть зеркальными. Чтобы отключить зеркальное отображение растровых изображений, вызовите SetLayout с битом LAYOUT_BITMAPORIENTATIONPRESERVED, заданным в dwLayout. Чтобы отключить зеркальное отображение в контроллере домена, вызовите SetLayout(hdc, 0).

Чтобы запросить текущий макет по умолчанию, вызовите Метод GetProcessDefaultLayout. После успешного возврата pdwDefaultLayout содержит LAYOUT_RTL или 0. Чтобы запросить параметры макета контекста устройства, вызовите GetLayout. После успешного возврата GetLayout возвращает значение DWORD , указывающее параметры макета по параметрам LAYOUT_RTL и LAYOUT_BITMAPORIENTATIONPRESERVED битам.

После создания окна измените макет с помощью функции SetWindowLong . Например, это необходимо, когда пользователь изменяет язык пользовательского интерфейса существующего окна с арабского или иврита на немецкий. Однако при изменении макета существующего окна необходимо сделать окно недействительным и обновить его, чтобы убедиться, что все содержимое окна рисуется на одном макете. Следующий пример кода является примером кода, который изменяет макет окна по мере необходимости:

// Using ANSI versions of GetWindowLong and SetWindowLong because Unicode
// is not needed for these calls

lExStyles = GetWindowLongA(hWnd, GWL_EXSTYLE);

// Check whether new layout is opposite the current layout
if (!!(pLState -> IsRTLLayout) != !!(lExStyles & WS_EX_LAYOUTRTL))
{
    // the following lines will update the window layout

    lExStyles ^= WS_EX_LAYOUTRTL;        // toggle layout
    SetWindowLongA(hWnd, GWL_EXSTYLE, lExStyles);
    InvalidateRect(hWnd, NULL, TRUE);    // to update layout in the client area
}

При зеркальном отображении следует думать в терминах "близкий" и "дальний", а не "левый" и "правый". Если это не сделать, это может привести к проблемам. Одна из распространенных методик программирования, которая вызывает проблемы в зеркальном окне, возникает при сопоставлении между координатами экрана и клиентскими координатами. Например, приложения часто используют код, аналогичный следующему, для размещения элемента управления в окне:

// DO NOT USE THIS IF APPLICATION MIRRORS THE WINDOW

// get coordinates of the window in screen coordinates
GetWindowRect(hControl, (LPRECT) &rControlRect);  

// map screen coordinates to client coordinates in dialog
ScreenToClient(hDialog, (LPPOINT) &rControlRect.left); 
ScreenToClient(hDialog, (LPPOINT) &rControlRect.right);

Это вызывает проблемы при зеркальном отображении, так как левый край прямоугольника становится правым краем зеркального окна и наоборот. Чтобы избежать этой проблемы, замените вызовы ScreenToClient вызовом MapWindowPoints следующим образом:

// USE THIS FOR MIRRORING

GetWindowRect(hControl, (LPRECT) &rControlRect);
MapWindowPoints(NULL, hDialog, (LPPOINT) &rControlRect, 2)

Этот код работает потому, что на платформах, поддерживающих зеркальное отображение, MapWindowPoints изменяется для переключения координат левой и правой точек при зеркальном отображении клиентского окна. Дополнительные сведения см. в разделе Примечания статьи MapWindowPoints.

Другой распространенной практикой, которая может вызвать проблемы в зеркальных окнах, является размещение объектов в клиентском окне с использованием смещения в экранных координатах, а не клиентских координат. Например, следующий код использует разницу в координатах экрана в качестве позиции X в клиентских координатах для размещения элемента управления в диалоговом окне.

// OK if LTR layout and mapping mode of client is MM_TEXT,
// but WRONG for a mirrored dialog 

RECT rdDialog;
RECT rcControl;

HWND hControl = GetDlgItem(hDlg, IDD_CONTROL);
GetWindowRect(hDlg, &rcDialog);             // gets rect in screen coordinates
GetWindowRect(hControl, &rcControl);
MoveWindow(hControl,
           rcControl.left - rcDialog.left,  // uses x position in client coords
           rcControl.top - rcDialog.top,
           nWidth,
           nHeight,
           FALSE);

Этот код подходит, если диалоговое окно имеет макет слева направо (LTR) и режим сопоставления клиента MM_TEXT, так как новая позиция x в клиентских координатах соответствует разнице левого края элемента управления и диалогового окна в координатах экрана. Однако в зеркальном диалоговом окне слева и справа используются обратные значения, поэтому вместо этого следует использовать MapWindowPoints следующим образом:

RECT rcDialog;
RECT rcControl;

HWND hControl - GetDlgItem(hDlg, IDD_CONTROL);
GetWindowRect(hControl, &rcControl);

// MapWindowPoints works correctly in both mirrored and non-mirrored windows.
MapWindowPoints(NULL, hDlg, (LPPOINT) &rcControl, 2);

// Now rcControl is in client coordinates.
MoveWindow(hControl, rcControl.left, rcControl.top, nWidth, nHeight, FALSE)

Диалоговые окна зеркального отображения и окна сообщений

Диалоговые окна и окна сообщений не наследуют макет, поэтому макет необходимо задать явным образом. Чтобы зеркало окно сообщения, вызовите MessageBox или MessageBoxEx с параметром MB_RTLREADING. Чтобы создать макет диалогового окна справа налево, используйте расширенный стиль WS_EX_LAYOUTRTL в структуре шаблона диалогового окна DLGTEMPLATEEX. Листы свойств — это особый случай диалоговых окон. Каждая вкладка рассматривается как отдельное диалоговое окно, поэтому необходимо включить стиль WS_EX_LAYOUTRTL в каждую вкладку, на которой требуется зеркальное отображение.

Контексты зеркального отображения устройств, не связанные с окном

Контроллеры домена, которые не связаны с окном, например метафайл или принтер, не наследуют макет, поэтому необходимо задать макет явным образом. Чтобы изменить макет контекста устройства, используйте функцию SetLayout .

Функция SetLayout редко используется с окнами. Как правило, окна получают связанный контроллер домена только при обработке сообщения WM_PAINT . Иногда программа создает контроллер домена для окна путем вызова GetDC. В любом случае начальный макет для контроллера домена задается с помощью BeginPaint или GetDC в соответствии с флагом WS_EX_LAYOUTRTL окна.

На значения, возвращаемые GetWindowOrgEx, GetWindowExtEx, GetViewportOrgEx и GetViewportExtEx, вызов SetLayout не влияет.

Если макет имеет значение RTL, GetMapMode вернет MM_ANISOTROPIC вместо MM_TEXT. Вызов SetMapMode с MM_TEXT будет работать правильно; Затрагивается только возвращаемое значение из GetMapMode . Аналогичным образом вызов SetLayout(hdc, LAYOUT_RTL) при MM_TEXT приводит к изменению режима сопоставления на MM_ANISOTROPIC.

Уничтожение окна

Как правило, приложение должно уничтожить все окна, которые оно создает. Для этого используется функция DestroyWindow . При уничтожении окна система скрывает окно, если оно отображается, а затем удаляет все внутренние данные, связанные с окном. Это делает недействительным дескриптор окна, который больше не может использоваться приложением.

Приложение уничтожает многие окна, которые оно создает вскоре после их создания. Например, приложение обычно уничтожает диалоговое окно, как только у него будет достаточно входных данных от пользователя для продолжения выполнения задачи. В конечном итоге приложение удаляет окно main приложения (перед завершением).

Перед уничтожением окна приложение должно сохранить или удалить все данные, связанные с окном, и освободить все системные ресурсы, выделенные для окна. Если приложение не освобождает ресурсы, система освободит все ресурсы, не освобожденные приложением.

Уничтожение окна не влияет на класс окон, из которого создается окно. Новые окна по-прежнему можно создавать с помощью этого класса, и все существующие окна этого класса продолжают работать. Уничтожение окна также разрушает его потомки. Функция DestroyWindow отправляет сообщение WM_DESTROY сначала в окно, а затем в его дочерние окна и потомки окон. Таким образом, все потомки окна разрушаемого окна также уничтожаются.

Окно с меню окна получает WM_CLOSE сообщение, когда пользователь нажимает кнопку Закрыть. Обрабатывая это сообщение, приложение может запрашивать у пользователя подтверждение перед уничтожением окна. Если пользователь подтверждает, что окно должно быть уничтожено, приложение может вызвать функцию DestroyWindow , чтобы уничтожить окно.

Если уничтожаемое окно является активным, то и активное, и состояние фокуса переносятся в другое окно. Окно, которое становится активным, является следующим окном, которое определяется сочетанием клавиш ALT+ESC. Затем новое активное окно определяет, какое окно получает фокус клавиатуры.