Компоновка и зеркалирование окна
Компоновка окна определяет, как текст и объекты Microsoft ® Интерфейс графических устройств Windows ® (
GDI) размещаются в окне или контексте устройства (DC). Некоторые языки, такие как английский, французский и немецкий, требуют компоновки слева направо (LTR). Другие языки, типа арабского и еврея языка, требуют компоновки справа налево макет (RTL). Компоновка окна применяется к тексту, и к тому же воздействует на другие элементы GDI окна, включая точечные рисунки, пиктограммы, место начала координат, кнопок, расположение каскадом просмотрщиков древовидных структур и увеличение горизонтальной координаты либо слева или справа. Например, после того, как приложение установило RTL компоновку, начало координат расположится с правого края окна или устройства, и число представляющее горизонтальную координату увеличивается по мере того, как Вы перемещаетесь влево. Однако не все объекты затрагиваются компоновкой окна. Например, компоновка диалоговых окон, окон сообщений и контекстов устройства, которые не связаны с окном, типа метафайла и DC принтера, должны обрабатываться отдельно. Специальные сообщения для них упомянуты позже в этой теме.Функции окна позволяют Вам устанавливать или изменять компоновку окна в версиях
Windows 98 и Windows Millennium Edition (Windows Me) и во всех версиях Windows 2000 или позже для арабского и еврейского языка.| Обратите внимание! что изменение на RTL компоновку (известное также как зеркалирование) не поддерживается для окон, которые имеют стиль CS_OWNDC или для DC с GM_ADVANCED графическим режимом. |
По умолчанию, компоновка окна - слева направо (LTR). Чтобы установить компоновку окна RTL, вызовите CreateWindowEx со стилем WS_EX_LAYOUTRTL. Также по умолчанию, дочернее окно (то есть созданное со стилем WS_CHILD и допустимым родительским параметром hWnd при вызове CreateWindow или CreateWindowEx) имеет ту же самую компоновку, как и его родитель. Чтобы отключить наследование зеркалирование всеми дочерними окнами, при вызове CreateWindowEx определите стиль WS_EX_NOINHERITLAYOUT.
| Обратите внимание!, зеркалирование не наследуется находящимися в собственности окнами (которые созданы без стиля 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 зеркалирует DC только зеркалированных окон. Чтобы зеркалировать какой-либо DC, вызовите функцию SetLayout (hdc, LAYOUT_RTL). Для получения дополнительной информации, см. обсуждение зеркалирования контекстов устройств не связанных с окнами, которое идет в этом разделе позже. |
Точечные рисунки и пиктограммы в зеркальном окне также зеркалируются по умолчанию. Однако не все они должны быть зеркалированы. Например, те, которые с текстом, деловой эмблемой, или аналоговыми часами не должны зеркалироваться. Чтобы отключить зеркалирование точечных рисунков, вызовите функцию SetLayout с установленным битом
LAYOUT_BITMAPORIENTATIONPRESERVED в параметре dwLayout. Чтобы отключать зеркалирование в DC, вызовите SetLayout (hdc, 0).Чтобы сделать запрос текущей заданной по умолчанию компоновки, вызовите функцию
GetProcessDefaultLayout. После успешного возврата значения, параметр pdwDefaultLayout содержит LAYOUT_RTL или 0. Чтобы сделать запрос параметров настройки компоновки контекста устройства, вызовите функцию GetLayout. После успешного возврата значения, GetLayout возвращает двойное слово (DWORD), которое указывает параметры компоновки установкой битов LAYOUT_RTL и LAYOUT_BITMAPORIENTATIONPRESERVED.После того, как окно было создано, Вы изменяете компоновку, используя функцию SetWindowLong. Например, это необходимо тогда, когда пользователь изменяет язык пользовательского интерфейса существующего окна из арабского или еврейского языка в немецкий. Однако при изменении компоновки существующего окна, Вы должны аннулировать и модифицировать окно, чтобы гарантировать, что все содержание окна перерисовывается в той же самой компоновке. Нижеследующий отрывок является типовым кодом, который изменяет компоновку окна как необходимо:
Демонстрационный пример
|
// Используем ANSI версию функций GetWindowLong и SetWindowLong, поскольку// версии Unicode не нужны для этих вызововlExStyles = GetWindowLongA(hWnd, GWL_EXSTYLE); // Проверьте, не является ли новая компоновка противоположной текущей// компоновкеif (!!(pLState -> IsRTLLayout) != !!(lExStyles & WS_EX_LAYOUTRTL)){ // строчки ниже обновляют компоновку окна lExStyles ^= WS_EX_LAYOUTRTL; // переключение компоновкиSetWindowLongA(hWnd, GWL_EXSTYLE, lExStyles); InvalidateRect(hWnd, NULL, TRUE); // обновляем компоновку рабочей области} |
В зеркалировании, Вы должны думать в понятиях "близко" и "далеко", вместо "слева" и "справа". Отказ делать так может стать причиной проблемы. Одна и та же стандартная практика кодирования это то, что вызывает проблемы в зеркалировании окна, которые происходят при отображении между экранной системой координат и рабочими координатами. Например, приложения часто используют код подобный нижеследующему, чтобы расположить орган управления в окне:
|
// НЕ ИСПОЛЬЗУЙТЕ ТАКИЕ ПРИЛОЖЕНИЕ ДЛЯ ЗЕРКАЛИРОВАНИЯ ОКНА// получим координаты окна в экранных координатахGetWindowRect (hControl, (LPRECT) &rControlRect);// преобразуем экранные координаты в рабочие координаты в диалоговом окнеScreenToClient (hDialog, (LPPOINT) &rControlRect.left);ScreenToClient(hDialog, (LPPOINT) &rControlRect.right); |
Это вызывает проблемы в зеркалировании, потому что левый край прямоугольника становится правым краем в зеркальном окне, и наоборот. Чтобы избежать этой проблемы, замените вызов функции ScreenToClient вызовом функции MapWindowPoints как ниже указано:
|
// ИСПОЛЗУЙТЕ ЭТО ДЛЯ ЗЕРКАЛИРОВАНИЯGetWindowRect (hControl, (LPRECT) &rControlRect);MapWindowPoints(NULL, hDialog, (LPPOINT) &rControlRect, 2) |
Этот код работает, потому что, на платформах, которые поддерживают зеркалирование, функция
MapWindowPoints модифицирована, чтобы менять левые и правые координаты точки, когда зеркалируется рабочее окно. Для получения дополнительной информации, см. раздел Замечаний в функции MapWindowPoints.Другая обычная практика, которая может стать причиной проблемы в зеркальных окнах, является занимаемое место объектом в рабочем окне, которое использует смещения в экранной системе координат вместо рабочих координат. Например, нижеследующий код использует разность в экранной системе координат как позицию
x в рабочих координатах, чтобы расположить орган управления в диалоговом окне.Демонстрационный пример
|
// OK если LTR компоновка и режим отображения рабочей области - MM_TEXT,// но НЕ ВЕРНО для диалогового окнаRECT rdDialog; RECT rcControl;HWND hControl = GetDlgItem(hDlg, IDD_CONTROL); GetWindowRect(hDlg, &rcDialog); // получим прямоугольник в // экранных координатахGetWindowRect (hControl, &rcControl);MoveWindow(hControl, // используем позицию x в рабочих координатах 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 работает правильно и зеркалированном и// не зеркалированном окне.MapWindowPoints (NULL, hDlg, (LPPOINT) &rcControl, 2);// Теперь rcControl находится в рабочих координатахMoveWindow (hControl, rcControl.left, rcControl.top, nWidth, nHeight, FALSE) |