Компоновка и зеркалирование окна

Компоновка окна определяет, как текст и объекты 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,

rcControl.left - rcDialog.left, // используем позицию 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)

Назад в оглавление темы
На главную страницу темы

Hosted by uCoz