Как заставить мой графический интерфейс вести себя хорошо, когда масштабирование шрифтов Windows превышает 100%
при выборе больших размеров шрифта в панели управления Windows (например, 125% или 150%), то есть проблемы в приложении VCL, каждый раз, когда что-то было установлено по пикселям.
взять TStatusBar.Panel
. Я поставил его ширину так, чтобы он содержал ровно одну метку, теперь с большими шрифтами надпись "переполнение". Та же проблема и с другими компонентами.
некоторые новые ноутбуки от Dell поставляются уже с настройкой 125% по умолчанию, поэтому в прошлом эта проблема была довольно редкой это действительно важно.
что можно сделать, чтобы преодолеть эту проблему?
4 ответа:
Примечание: пожалуйста, смотрите другие ответы, поскольку они содержат очень ценные методы. Мой ответ здесь дает только предостережения и предостережения против предположения, что DPI-осведомленность проста.
Я обычно избегаю масштабирования с поддержкой DPI с помощью
TForm.Scaled = True
. Осведомленность DPI важна для меня только тогда, когда она становится важной для клиентов, которые звонят мне и готовы заплатить за нее. Техническая причина этой точки зрения заключается в том, что DPI-осознание или нет, вы открываете окно в мир боли. Много стандартные и сторонние элементы управления VCL не работают хорошо в высоком разрешении. Заметное исключение, что части VCL, которые обертывают общие элементы управления Windows, работают замечательно хорошо при высоком разрешении на дюйм. Огромное количество сторонних и встроенных пользовательских элементов управления Delphi VCL не работают хорошо, или вообще, при высоком DPI. Если вы планируете включить TForm.Масштабирование не забудьте протестировать на 96, 125 и 150 точек на дюйм для каждой отдельной формы в вашем проекте и каждого отдельного стороннего и встроенного элемента управления, который вы используете.сам Delphi написано на Delphi. Он имеет флаг высокой осведомленности DPI включен, для большинства форм, хотя даже недавно, как в Delphi XE2, сами авторы IDE решили не включать этот флаг манифеста высокой осведомленности DPI. Обратите внимание, что в Delphi XE4 и более поздних версиях флаг High DPI awareness включен, и IDE выглядит хорошо.
Я предлагаю вам не использовать TForm.Scaled=true (что является значением по умолчанию в Delphi, поэтому, если вы его не изменили, большинство ваших форм Scaled=true) с высоким Флаги с поддержкой DPI (как показано в ответах Дэвида) с приложениями VCL, построенными с использованием встроенного конструктора форм delphi.
Я пытался в прошлом, чтобы сделать минимальную выборку вида поломки вы можете ожидать, чтобы увидеть, когда TForm.Масштабирование истинно, и когда масштабирование формы Delphi имеет сбой. Эти сбои не всегда и только вызваны значением DPI, отличным от 96. Я не смог определить полный список других вещей, который включает размер шрифта Windows XP изменения. Но так как большинство из этих сбоев появляются только в моих собственных приложениях, в довольно сложных ситуациях, я решил показать вам некоторые доказательства, которые вы можете проверить сами.
Delphi XE выглядит так, когда вы устанавливаете масштабирование DPI на "шрифты @ 200%" в Windows 7, а Delphi XE2 аналогично нарушается в Windows 7 и 8, но эти глюки, похоже, исправлены с Delphi XE4:
это в основном стандартные VCL элементы управления, которые плохо себя ведут при высоком разрешении. Обратите внимание, что большинство вещей не были масштабированы вообще, поэтому разработчики Delphi IDE решили игнорировать осведомленность DPI, а также отключить виртуализацию DPI. Такой интересный выбор.
выключите виртуализацию DPI только если хотите этот новый дополнительный источник боли и трудный выбор. Я предлагаю вам оставить его в покое. Обратите внимание, что общие элементы управления Windows в основном работают нормально. Обратите внимание, что элемент управления Delphi data-explorer является C# WinForms обертка вокруг стандартного дерева Windows общий элемент управления. Это чистый сбой microsoft, и для его исправления может потребоваться Embarcadero переписать чистый собственный элемент управления .NET tree для своего проводника данных или написать код DPI-check-and-modify-properties для изменения высоты элемента в элементе управления. Даже microsoft WinForms не может обрабатывать высокий DPI чисто, автоматически и без пользовательского кода kludge.
Update: интересный факт: в то время как IDE delphi, похоже, не существует "виртуальных", не используя явного содержания показал Дэвид, чтобы достичь "не-точек на дюйм-виртуализации". Возможно, он использует некоторые функции API во время выполнения.
обновление 2: в ответ на то, как я буду поддерживать 100%/125% DPI, я бы придумал двухфазный план. Фаза 1 заключается в инвентаризации моего кода для пользовательских элементов управления, которые должны быть исправлены для высокого DPI, а затем составить план их исправления или поэтапного отказа от них. Фаза 2 будет принимать некоторые области моего кода, которые разработаны как формы без управление макетом и измените их на формы, которые используют какое-то управление макетом, чтобы изменения высоты DPI или шрифта могли работать без отсечения. Я подозреваю, что эта работа по компоновке "между элементами управления" будет намного сложнее в большинстве приложений, чем работа "внутри элемента управления".
обновление: в 2016 году последняя версия Delphi 10.1 Berlin хорошо работает на моей рабочей станции 150 dpi.
настройки в .dfm файл будет правильно масштабироваться, пока
Scaled
иTrue
.если вы устанавливаете размеры в коде, то вам нужно масштабировать их на
Screen.PixelsPerInch
разделить наForm.PixelsPerInch
. ИспользуйтеMulDiv
для этого.function TMyForm.ScaleDimension(const X: Integer): Integer; begin Result := MulDiv(X, Screen.PixelsPerInch, PixelsPerInch); end;
это то, что делает структура персистентности формы, когда
Scaled
иTrue
.фактически, вы можете сделать убедительный аргумент для замены этой функции версией, которая жестко кодирует значение 96 для знаменателя. Это позволяет использовать абсолютные значения размеров и не беспокоиться об изменении значения, если вы измените масштабирование шрифта на своей машине разработки и повторно сохраните его .dfm-файл. Причина дело в том, что
PixelsPerInch
свойство хранится в.dfm файл-это значение машины, на которой находится .DFM-файл был сохранен в последний раз.const SmallFontsPixelsPerInch = 96; function ScaleFromSmallFontsDimension(const X: Integer): Integer; begin Result := MulDiv(X, Screen.PixelsPerInch, SmallFontsPixelsPerInch); end;
Итак, Продолжая тему, еще одна вещь, которую следует опасаться, заключается в том, что если ваш проект разрабатывается на нескольких машинах с различные значения DPI, вы обнаружите, что масштабирование, которое Delphi использует при сохранении .dfm-файлы приводят к тому, что элементы управления блуждают по ряду изменений. На моем месте работы, чтобы избежать этого, у нас есть строгая политика, что формы редактируются только на 96dpi (100% масштабирование).
на самом деле моя версия
ScaleFromSmallFontsDimension
также учитывает возможность шрифта формы, отличающегося во время выполнения от этого набора во время разработки. На машинах XP формы моего приложения используют 8pt Tahoma. На Vista и выше 9pt Используется пользовательский интерфейс Segoe. Это дает еще одну степень свободы. Масштабирование должно учитывать это, поскольку абсолютные значения измерений, используемые в исходном коде, предполагаются относительно базовой линии 8pt Tahoma на 96dpi.если вы используете какие-либо изображения или символы в пользовательском интерфейсе, то они должны тоже шкале. Общим примером могут быть глифы, которые используются на панелях инструментов и меню. Вы захотите предоставить эти глифы в качестве ресурсов значков, связанных с вашим исполняемым файлом. Каждый значок должен содержать диапазон размеров, а затем во время выполнения вы выбираете наиболее подходящий размер и загружаете его в список изображений. Некоторые подробности по этой теме можно найти здесь: как загрузить значки из ресурса, не страдая от сглаживания?
еще один полезный трюк заключается в определении размеров в относительных единицах, относительно
TextWidth
илиTextHeight
. Итак, если вы хотите, чтобы что-то было размером около 10 вертикальных линий, вы можете использовать10*Canvas.TextHeight('Ag')
. Это очень грубая и готовая метрика, потому что он не учитывает межстрочный интервал и так далее. Тем не менее, часто все, что вам нужно сделать, это быть в состоянии организовать, что GUI масштабируется правильно сPixelsPerInch
.вы также должны отметить свое приложение как высокий DPI aware. Лучший способ сделать это через манифест приложения. Поскольку инструменты сборки Delphi не позволяют настраивать манифест, который вы используете, это заставляет вас связывать свой собственный ресурс манифеста.
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <dpiAware>true</dpiAware> </asmv3:windowsSettings> </asmv3:application> </assembly>
скрипт ресурса выглядит так это:
1 24 "Manifest.txt"
здесь
Manifest.txt
содержит фактический манифест. Вам также нужно будет включить раздел comctl32 v6 и установитьrequestedExecutionLevel
доasInvoker
. Затем вы связываете этот скомпилированный ресурс с вашим приложением и убедитесь, что Delphi не пытается сделать то же самое с его манифестом. В современном Delphi вы достигаете этого, установив параметр проекта темы выполнения в None.манифест-это право способ объявить ваше приложение, чтобы быть высоким DPI в курсе. Если вы просто хотите попробовать его быстро, не возясь с манифестом, позвоните
SetProcessDPIAware
. Делать так, как самое первое, что вы делаете, когда ваше приложение запускается. Предпочтительно в одном из ранних разделов инициализации блока, или как первое в вашем .файл ДНР.если вы не объявите свое приложение с высоким разрешением DPI, Vista и up будут отображать его в устаревшем режиме для любого масштабирования шрифта выше 125%. Это выглядит довольно ужасно. Постарайтесь не попасть в это ловушка.
Windows 8.1 на обновление DPI монитора
начиная с Windows 8.1, теперь есть поддержка ОС для каждого монитора настройки DPI (http://msdn.microsoft.com/en-ca/magazine/dn574798.aspx это большая проблема для современных устройств, которые могут иметь разные дисплеи, прикрепленные с очень разными возможностями. У вас может быть очень высокий экран ноутбука DPI и внешний проектор с низким разрешением. Поддержка такого сценария требует даже больше работы, чем описанный выше.
также важно отметить, что соблюдение DPI пользователя-это только подмножество вашей реальной работы:
соблюдая размер шрифта пользователя
на протяжении десятилетий Windows решила эту проблему с понятием выполнения макета с помощью Диалогового Окна, а не в пикселях. А "dialog unit" определяется так, что шрифт персонаж и
- 4 диалоговых блока (dlus) широкий, и
- 8 диалоговых единиц (clus) high
Delphi действительно поставляется с (багги) понятием
Scaled
, где форма пытается автоматически настроить на основе
- Windows DPI настройки пользователя, стихи
- настройка DPI на машине разработчика, который последним сохранил форму
это не решает проблему, когда пользователь использует шрифт, отличный от того, что вы разработали форма с, например:
- разработчик разработал форму с MS Sans Serif 8pt (где средний символ
6.21px x 13.00px
, в 96 точек на дюйм)пользователь работает с Tahoma 8pt (где средний символ
5.94px x 13.00px
, в 96 точек на дюйм)как и в случае с любым разработчиком приложения для Windows 2000 или Windows XP.
или
- застройщик оформил форма с * * Tahoma 8pt* (где средний символ
5.94px x 13.00px
, в 96 точек на дюйм)- пользователь работает с Segoe UI 9pt (где средний символ
6.67px x 15px
, в 96 точек на дюйм)как хороший разработчик, вы собираетесь почтить шрифта пользователя. Это означает, что вам также необходимо масштабировать все элементы управления в форме в соответствии с новым размером шрифта:
- развернуть все по горизонтали на 12.29% (6.67/5.94)
- растянуть все по вертикали на 15,38% (15/13)
Scaled
не будет обрабатывать это для вас.это еще хуже, когда:
- разработал свою форму в Segoe UI 9pt (ОС Windows Vista, ОС Windows 7, Windows 8 по умолчанию)
- пользователь Segoe UI 14pt (например, мои предпочтения), которое
10.52px x 25px
теперь вы должны масштабировать все
- по горизонтали на 57,72%
- вертикально 66.66%
Scaled
не будет обрабатывать это для вас.
если вы умны, вы можете видеть, как почитание DPI является безвозвратным:
- форма спроектирована с 9 кегль, шрифт Segoe UI с @ 96 точек на дюйм (15px 6.67 РХ х)
- пользователь работает с 9 кегль, шрифт Segoe Ui В @ 150 точек на дюйм (10.52 РХ х 25 пикселей)
вы не должны смотреть на настройки DPI пользователя, вы надо смотреть на их размер шрифта. Два пользователя работают
- шрифт Segoe UI для 14пт @ 96 точек на дюйм (10.52 РХ х 25 пикселей)
- шрифт Segoe UI с 9 кегль @ 150 точек на дюйм (10.52 РХ х 25 пикселей)
работает тот же шрифт. DPI-это просто один то, что влияет на размер шрифта; предпочтения пользователя-это другое.
StandardizeFormFont
Кловис заметил, что я ссылаюсь на функцию
StandardizeFormFont
это фиксирует шрифт в форме и масштабирует его до нового размера шрифта. Это не стандартная функция, а целый набор функций, которые выполняют простую задачу, с которой Борланд никогда не справлялся.function StandardizeFormFont(AForm: TForm): Real; var preferredFontName: string; preferredFontHeight: Integer; begin GetUserFontPreference({out}preferredFontName, {out}preferredFontHeight); //e.g. "Segoe UI", Result := Toolkit.StandardizeFormFont(AForm, PreferredFontName, PreferredFontHeight); end;
Windows имеет 6 различных шрифтов; в Windows нет одной "настройки шрифта".
Но мы знаем по опыту, что наши формы должны следовать Шрифт Заголовка Значка заданиеprocedure GetUserFontPreference(out FaceName: string; out PixelHeight: Integer); var font: TFont; begin font := Toolkit.GetIconTitleFont; try FaceName := font.Name; //e.g. "Segoe UI" //Dogfood testing: use a larger font than we're used to; to force us to actually test it if IsDebuggerPresent then font.Size := font.Size+1; PixelHeight := font.Height; //e.g. -16 finally font.Free; end; end;
как только мы узнаем размер шрифта мы будем масштабировать форму до, мы получаем текущую высоту шрифта формы (в точках), и масштабируется по этому фактору.
например, если я устанавливаю форму
-16
, и форма в настоящее время составляет-11
, тогда нам нужно масштабировать всю форму по:-16 / -11 = 1.45454%
стандартизация происходит в два этапа. Сначала масштабируйте форму по соотношению новых и старых размеров шрифта. Затем фактически измените элементы управления (рекурсивно) для использования новый шрифт.
function StandardizeFormFont(AForm: TForm; FontName: string; FontHeight: Integer): Real; var oldHeight: Integer; begin Assert(Assigned(AForm)); if (AForm.Scaled) then begin OutputDebugString(PChar('WARNING: StandardizeFormFont: Form "'+GetControlName(AForm)+'" is set to Scaled. Proper form scaling requires VCL scaling to be disabled, unless you implement scaling by overriding the protected ChangeScale() method of the form.')); end; if (AForm.AutoScroll) then begin if AForm.WindowState = wsNormal then begin OutputDebugString(PChar('WARNING: StandardizeFormFont: Form "'+GetControlName(AForm)+'" is set to AutoScroll. Form designed size will be suseptable to changes in Windows form caption height (e.g. 2000 vs XP).')); if IsDebuggerPresent then Windows.DebugBreak; //Some forms would like it (to fix maximizing problem) end; end; if (not AForm.ShowHint) then begin AForm.ShowHint := True; OutputDebugString(PChar('INFORMATION: StandardizeFormFont: Turning on form "'+GetControlName(AForm)+'" hints. (ShowHint := True)')); if IsDebuggerPresent then Windows.DebugBreak; //Some forms would like it (to fix maximizing problem) end; oldHeight := AForm.Font.Height; //Scale the form to the new font size // if (FontHeight <> oldHeight) then For compatibility, it's safer to trigger a call to ChangeScale, since a lot of people will be assuming it always is called begin ScaleForm(AForm, FontHeight, oldHeight); end; //Now change all controls to actually use the new font Toolkit.StandardizeFont_ControlCore(AForm, g_ForceClearType, FontName, FontHeight, AForm.Font.Name, AForm.Font.Size); //Return the scaling ratio, so any hard-coded values can be multiplied Result := FontHeight / oldHeight; end;
вот работа по фактическому масштабированию формы. Он работает вокруг ошибок в собственном Борланде
Form.ScaleBy
метод. Сначала он должен отключить все якоря на форме, затем выполнить масштабирование, а затем снова включить якоря:TAnchorsArray = array of TAnchors; procedure ScaleForm(const AForm: TForm; const M, D: Integer); var aAnchorStorage: TAnchorsArray; RectBefore, RectAfter: TRect; x, y: Integer; monitorInfo: TMonitorInfo; workArea: TRect; begin if (M = 0) and (D = 0) then Exit; RectBefore := AForm.BoundsRect; SetLength(aAnchorStorage, 0); aAnchorStorage := DisableAnchors(AForm); try AForm.ScaleBy(M, D); finally EnableAnchors(AForm, aAnchorStorage); end; RectAfter := AForm.BoundsRect; case AForm.Position of poScreenCenter, poDesktopCenter, poMainFormCenter, poOwnerFormCenter, poDesigned: //i think i really want everything else to also follow the nudging rules...why did i exclude poDesigned begin //This was only nudging by one quarter the difference, rather than one half the difference // x := RectAfter.Left - ((RectAfter.Right-RectBefore.Right) div 2); // y := RectAfter.Top - ((RectAfter.Bottom-RectBefore.Bottom) div 2); x := RectAfter.Left - ((RectAfter.Right-RectAfter.Left) - (RectBefore.Right-RectBefore.Left)) div 2; y := RectAfter.Top - ((RectAfter.Bottom-RectAfter.Top)-(RectBefore.Bottom-RectBefore.Top)) div 2; end; else //poDesigned, poDefault, poDefaultPosOnly, poDefaultSizeOnly: x := RectAfter.Left; y := RectAfter.Top; end; if AForm.Monitor <> nil then begin monitorInfo.cbSize := SizeOf(monitorInfo); if GetMonitorInfo(AForm.Monitor.Handle, @monitorInfo) then workArea := monitorInfo.rcWork else begin OutputDebugString(PChar(SysErrorMessage(GetLastError))); workArea := Rect(AForm.Monitor.Left, AForm.Monitor.Top, AForm.Monitor.Left+AForm.Monitor.Width, AForm.Monitor.Top+AForm.Monitor.Height); end; // If the form is off the right or bottom of the screen then we need to pull it back if RectAfter.Right > workArea.Right then x := workArea.Right - (RectAfter.Right-RectAfter.Left); //rightEdge - widthOfForm if RectAfter.Bottom > workArea.Bottom then y := workArea.Bottom - (RectAfter.Bottom-RectAfter.Top); //bottomEdge - heightOfForm x := Max(x, workArea.Left); //don't go beyond left edge y := Max(y, workArea.Top); //don't go above top edge end else begin x := Max(x, 0); //don't go beyond left edge y := Max(y, 0); //don't go above top edge end; AForm.SetBounds(x, y, RectAfter.Right-RectAfter.Left, //Width RectAfter.Bottom-RectAfter.Top); //Height end;
и тогда мы должны рекурсивно на самом деле использовать новый шрифт:
procedure StandardizeFont_ControlCore(AControl: TControl; ForceClearType: Boolean; FontName: string; FontSize: Integer; ForceFontIfName: string; ForceFontIfSize: Integer); const CLEARTYPE_QUALITY = 5; var i: Integer; RunComponent: TComponent; AControlFont: TFont; begin if not Assigned(AControl) then Exit; if (AControl is TStatusBar) then begin TStatusBar(AControl).UseSystemFont := False; //force... TStatusBar(AControl).UseSystemFont := True; //...it end else begin AControlFont := Toolkit.GetControlFont(AControl); if not Assigned(AControlFont) then Exit; StandardizeFont_ControlFontCore(AControlFont, ForceClearType, FontName, FontSize, ForceFontIfName, ForceFontIfSize); end; { If a panel has a toolbar on it, the toolbar won't paint properly. So this idea won't work. if (not Toolkit.IsRemoteSession) and (AControl is TWinControl) and (not (AControl is TToolBar)) then TWinControl(AControl).DoubleBuffered := True; } //Iterate children for i := 0 to AControl.ComponentCount-1 do begin RunComponent := AControl.Components[i]; if RunComponent is TControl then StandardizeFont_ControlCore( TControl(RunComponent), ForceClearType, FontName, FontSize, ForceFontIfName, ForceFontIfSize); end; end;
С рекурсивно отключенными якорями:
function DisableAnchors(ParentControl: TWinControl): TAnchorsArray; var StartingIndex: Integer; begin StartingIndex := 0; DisableAnchors_Core(ParentControl, Result, StartingIndex); end; procedure DisableAnchors_Core(ParentControl: TWinControl; var aAnchorStorage: TAnchorsArray; var StartingIndex: Integer); var iCounter: integer; ChildControl: TControl; begin if (StartingIndex+ParentControl.ControlCount+1) > (Length(aAnchorStorage)) then SetLength(aAnchorStorage, StartingIndex+ParentControl.ControlCount+1); for iCounter := 0 to ParentControl.ControlCount - 1 do begin ChildControl := ParentControl.Controls[iCounter]; aAnchorStorage[StartingIndex] := ChildControl.Anchors; //doesn't work for set of stacked top-aligned panels // if ([akRight, akBottom ] * ChildControl.Anchors) <> [] then // ChildControl.Anchors := [akLeft, akTop]; if (ChildControl.Anchors) <> [akTop, akLeft] then ChildControl.Anchors := [akLeft, akTop]; // if ([akTop, akBottom] * ChildControl.Anchors) = [akTop, akBottom] then // ChildControl.Anchors := ChildControl.Anchors - [akBottom]; Inc(StartingIndex); end; //Add children for iCounter := 0 to ParentControl.ControlCount - 1 do begin ChildControl := ParentControl.Controls[iCounter]; if ChildControl is TWinControl then DisableAnchors_Core(TWinControl(ChildControl), aAnchorStorage, StartingIndex); end; end;
и якоря рекурсивно повторно включено:
procedure EnableAnchors(ParentControl: TWinControl; aAnchorStorage: TAnchorsArray); var StartingIndex: Integer; begin StartingIndex := 0; EnableAnchors_Core(ParentControl, aAnchorStorage, StartingIndex); end; procedure EnableAnchors_Core(ParentControl: TWinControl; aAnchorStorage: TAnchorsArray; var StartingIndex: Integer); var iCounter: integer; ChildControl: TControl; begin for iCounter := 0 to ParentControl.ControlCount - 1 do begin ChildControl := ParentControl.Controls[iCounter]; ChildControl.Anchors := aAnchorStorage[StartingIndex]; Inc(StartingIndex); end; //Restore children for iCounter := 0 to ParentControl.ControlCount - 1 do begin ChildControl := ParentControl.Controls[iCounter]; if ChildControl is TWinControl then EnableAnchors_Core(TWinControl(ChildControl), aAnchorStorage, StartingIndex); end; end;
С работой по фактическому изменению шрифта элементов управления слева:
procedure StandardizeFont_ControlFontCore(AControlFont: TFont; ForceClearType: Boolean; FontName: string; FontSize: Integer; ForceFontIfName: string; ForceFontIfSize: Integer); const CLEARTYPE_QUALITY = 5; var CanChangeName: Boolean; CanChangeSize: Boolean; lf: TLogFont; begin if not Assigned(AControlFont) then Exit; {$IFDEF ForceClearType} ForceClearType := True; {$ELSE} if g_ForceClearType then ForceClearType := True; {$ENDIF} //Standardize the font if it's currently // "MS Shell Dlg 2" (meaning whoever it was opted into the 'change me' system // "MS Sans Serif" (the Delphi default) // "Tahoma" (when they wanted to match the OS, but "MS Shell Dlg 2" should have been used) // "MS Shell Dlg" (the 9x name) CanChangeName := (FontName <> '') and (AControlFont.Name <> FontName) and ( ( (ForceFontIfName <> '') and (AControlFont.Name = ForceFontIfName) ) or ( (ForceFontIfName = '') and ( (AControlFont.Name = 'MS Sans Serif') or (AControlFont.Name = 'Tahoma') or (AControlFont.Name = 'MS Shell Dlg 2') or (AControlFont.Name = 'MS Shell Dlg') ) ) ); CanChangeSize := ( //there is a font size (FontSize <> 0) and ( //the font is at it's default size, or we're specifying what it's default size is (AControlFont.Size = 8) or ((ForceFontIfSize <> 0) and (AControlFont.Size = ForceFontIfSize)) ) and //the font size (or height) is not equal ( //negative for height (px) ((FontSize < 0) and (AControlFont.Height <> FontSize)) or //positive for size (pt) ((FontSize > 0) and (AControlFont.Size <> FontSize)) ) and //no point in using default font's size if they're not using the face ( (AControlFont.Name = FontName) or CanChangeName ) ); if CanChangeName or CanChangeSize or ForceClearType then begin if GetObject(AControlFont.Handle, SizeOf(TLogFont), @lf) <> 0 then begin //Change the font attributes and put it back if CanChangeName then StrPLCopy(Addr(lf.lfFaceName[0]), FontName, LF_FACESIZE); if CanChangeSize then lf.lfHeight := FontSize; if ForceClearType then lf.lfQuality := CLEARTYPE_QUALITY; AControlFont.Handle := CreateFontIndirect(lf); end else begin if CanChangeName then AControlFont.Name := FontName; if CanChangeSize then begin if FontSize > 0 then AControlFont.Size := FontSize else if FontSize < 0 then AControlFont.Height := FontSize; end; end; end; end;
это гораздо больше кода, чем вы думали, что это будет; я знаю. Самое печальное, что на земле нет разработчика Delphi, кроме меня, который на самом деле делает свои приложения правильными.
Уважаемый Разработчик Delphi: установите шрифт Windows в Segoe UI 14pt, и исправить багги приложения
Примечание: любой код передается в общественное достояние. Атрибуция не требуется.
вот мой подарок. Функция, которая может помочь вам с горизонтальным расположением элементов в макетах графического интерфейса. Бесплатный для всех.
function CenterInParent(Place,NumberOfPlaces,ObjectWidth,ParentWidth,CropPercent: Integer): Integer; {returns formated centered position of an object relative to parent. Place - P order number of an object beeing centered NumberOfPlaces - NOP total number of places available for object beeing centered ObjectWidth - OW width of an object beeing centered ParentWidth - PW width of an parent CropPercent - CP percentage of safe margin on both sides which we want to omit from calculation +-----------------------------------------------------+ | | | +--------+ +---+ +--------+ | | | | | | | | | | +--------+ +---+ +--------+ | | | | | | | +-----------------------------------------------------+ | |<---------------------A----------------->| | |<-C->|<------B----->|<-----B----->|<-----B---->|<-C->| | |<-D>| |<----------E------------>| A = PW-C B = A/NOP C=(CP*PW)/100 D = (B-OW)/2 E = C+(P-1)*B+D } var A, B, C, D: Integer; begin C := Trunc((CropPercent*ParentWidth)/100); A := ParentWidth - C; B := Trunc(A/NumberOfPlaces); D := Trunc((B-ObjectWidth)/2); Result := C+(Place-1)*B+D; end;