Как конвертировать DLU в пиксели? - PullRequest
9 голосов
/ 29 июля 2011

Microsoft использует единицы измерения длины диалога (DLU) в своих рекомендациях по пользовательскому интерфейсу.Как я могу конвертировать их в пиксели?

Как я знаю, DLU зависит от размера системного шрифта.Можете ли вы посоветовать какой-нибудь простой способ такого преобразования в Delphi для Win32?

Ответы [ 3 ]

16 голосов
/ 22 мая 2012

Сначала мы начнем с что такое диалоговая единица.

Для этого я процитирую один из моих собственных неотвеченных вопросов :

Что такое диалоговая единица?

Диалог - это единица измерения, основанная на предпочитаемом пользователем размере шрифта.Диалоговая единица определяется так, что средний символ имеет ширину 4 диалоговых элемента и высоту 8 диалоговых блоков:

enter image description here

Это означает, что диалоговые единицы:

  • изменить с выбранным шрифтом
  • изменить с выбранной настройкой DPI
  • не квадратные

я также процитирую другой мои собственные неотвеченные вопросы :

Вы можете проверить Руководство по Windows UX , чтобы увидеть, откуда приходят эти измерения.Краткая версия:

  • dlu = диалоговое окно
  • dlu основано на размере шрифта ( элементы изменяются с размером шрифта пользователя )
  • a по горизонтали Длу отличается от по вертикали Длу ( Длу не квадратные )

Этопроисходит от определения диалоговой единицы: средний символ имеет высоту 8dlus и ширину 4dlus .

Georgia 14pt:

enter image description here

Если вы используете шрифт меньшего размера (т. Е. Стихи Тахомы 8pt, 14pt Georgia), dlus становится меньше:

Пользовательский интерфейс Segoe 9pt:

enter image description here

Примечание : Вы заметите, что разрешение (т.е. dpi) не влияет на обсуждение.

Так что вам нужно средний размер символа.У Microsoft есть официальный метод для расчета среднего размера символов.

  • средняя высота:

    GetTextMetrics(dc, {var}textMetrics);
    averageHeight := textMetrics.tmHeight;
    
  • средняя ширина:

    Измерьте строку ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz , используя GetTextExtentPoint32, и разделите на 52:

    GetTextExtentPoint32(dc,
          PChar('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 52, Size));
    averageWidth := size.cx / 52.0;
    

ТеперьВам нужен размер горизонтального и вертикального диалоговых блоков.Помните, что горизонтальная единица диалога равна 1/4 средней ширины символа, а вертикальная длина равна 1/8 средней высоты символа:

procedure GetDlus(dc: HDC; out HorizontalDluSize, VerticalDluSize: Real);
var
   tm: TTextMetric; 
   size: TSize;
begin
   GetTextMetric(dc, tm);
   VerticalDluSize := tm.tmHeight / 8.0;

   GetTextExtentPoint32(dc,
         PChar('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 52,
         size);
   HorizontalDluSize := size.cx / 52.0;
end;

Примечание : любой кодпубликуется в открытом доступе.Указание авторства не требуется.

10 голосов
/ 29 июля 2011

Вы должны использовать функцию MapDialogRect().

Передайте RECT в диалоговых единицах, и будет возвращен эквивалент RECT в пиксельных единицах. Обратите внимание, что вам нужен дескриптор для диалога, чтобы дать MapDialogRect() достаточный контекст. Функция должна знать шрифт, чтобы выполнить преобразование.


Если у вас возникнет соблазн использовать GetDialogBaseUnits(), помните, что сказал Раймонд Чен, GetDialogBaseUnits - это чудовище .

Как вы можете догадаться из заголовка этой записи, GetDialogBaseUnits является черепок. Поскольку в GetDialogBaseUnits отсутствует параметр HWND, он не знает, какие DLU диалогового окна вы хотите получить. Так что догадок.

И он всегда угадывает.

GetDialogBaseUnits возвращает базовые единицы диалога для диалоговых окон, которые используйте системный шрифт по умолчанию. Но никто не использует системный шрифт по умолчанию больше Кричит "старый и тупой". Но это остается по умолчанию для причины совместимости. (И поэтому то же самое делает GetDialogBaseUnits.)

Если вам нужно вычислить размеры в пикселях из DLU, и у вас нет дескриптора для диалога, то вы должны использовать метод, описанный здесь: Как вычислить базовые единицы диалога с несистемным шрифтом


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

0 голосов
/ 30 июля 2011

Для базового значения (и, естественно, системного шрифта) вызовите GetDialogBaseUnits.См. Также remarks параграф там для альтернативного метода перевода диалоговых единиц <-> пикселей с GetTextMetrics и / или GetTextExtentPoint32 без диалога HWND.

...