Код
procedure TForm1.FormCreate(Sender: TObject);
procedure RenderFont(const AFont: TFont; const ADescription: String);
function FindSubstitute(const AFontName: String; const ACharset: Integer): String;
function StripCharset(const AFontName: String): String;
var
X: Integer;
begin
X := Pos(',', AFontName);
if X > 0 then
Result := Trim(Copy(AFontName, 1, X - 1))
else
Result := AFontName;
end;
var
Reg: TRegIniFile;
begin
Reg := TRegIniFile.Create(KEY_READ);
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKey('\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes', False) then
begin
if Reg.ValueExists(AFontName + ',' + IntToStr(ACharset)) then
Result := StripCharset(Reg.ReadString('', AFontName + ',' + IntToStr(ACharset), AFontName))
else
if Reg.ValueExists(AFontName + ',0') then
Result := StripCharset(Reg.ReadString('', AFontName + ',0', AFontName))
else
if Reg.ValueExists(AFontName) then
Result := StripCharset(Reg.ReadString('', AFontName, AFontName))
else
Result := AFontName;
end
else
Result := AFontName;
finally
FreeAndNil(Reg);
end;
end;
const
Line = '%s:'#9#9'%s (%s),'#9#9'%d, %d, DPI: %d, charset: %d, pitch: %d, quality: %d, orientation: %d';
begin
Memo1.Lines.Add(Format(Line, [ADescription, AFont.Name,
FindSubstitute(AFont.Name, Ord(AFont.Charset)),
AFont.Size, AFont.Height,
Ord(AFont.PixelsPerInch), Ord(AFont.Charset),
Ord(AFont.Pitch), Ord(AFont.Quality),
Ord(AFont.Orientation)]));
end;
procedure RenderStockFont(const AStackFont: Integer; const ADescription: String);
var
Font: TFont;
begin
Font := TFont.Create;
try
Font.Handle := GetStockObject(AStackFont);
RenderFont(Font, ADescription);
finally
FreeAndNil(Font);
end;
end;
procedure RenderLogFont(const ALogFont: TLogFont; const ADescription: String);
var
Font: TFont;
begin
Font := TFont.Create;
try
Font.Handle := CreateFontIndirect(ALogFont);
RenderFont(Font, ADescription);
finally
FreeAndNil(Font);
end;
end;
var
Metrics: TNonClientMetrics;
begin
Memo1.Lines.Clear;
RenderStockFont(ANSI_FIXED_FONT, 'ANSI_FIXED_FONT');
RenderStockFont(ANSI_VAR_FONT, 'ANSI_VAR_FONT');
RenderStockFont(DEVICE_DEFAULT_FONT, 'DEVICE_DEFAULT_FONT');
RenderStockFont(DEFAULT_GUI_FONT, 'DEFAULT_GUI_FONT');
RenderStockFont(OEM_FIXED_FONT, 'OEM_FIXED_FONT');
RenderStockFont(SYSTEM_FONT, 'SYSTEM_FONT');
RenderStockFont(SYSTEM_FIXED_FONT, 'SYSTEM_FIXED_FONT');
FillChar(Metrics, SizeOf(Metrics), 0);
Metrics.cbSize := Metrics.SizeOf; // := SizeOf(Metrics); - для старых Delphi
if not SystemParametersInfo(SPI_GETNONCLIENTMETRICS, Metrics.cbSize, @Metrics, 0) then
RaiseLastOSError;
RenderLogFont(Metrics.lfCaptionFont, 'CaptionFont');
RenderLogFont(Metrics.lfSmCaptionFont, 'SmCaptionFont');
RenderLogFont(Metrics.lfMenuFont, 'MenuFont');
RenderLogFont(Metrics.lfStatusFont, 'StatusFont');
RenderLogFont(Metrics.lfMessageFont, 'MessageFont');
end;
Историческая справкаНу и самое интересное:
Среди других вещей, которые вы можете запросить с помощью функцииGetStockObject, есть два шрифта, называемыеSYSTEM_FONTиDEFAULT_GUI_FONT. Что это такое?
Это шрифты, которые сегодня уже никем не используются.
В старые-добрые времена Windows 2.0, шрифт, используемый для диалоговых окон, был растровым шрифтом, называемым System. Это и есть шрифт, который возвращаетSYSTEM_FONT, и он же всё ещё является шрифтом по-умолчанию для диалогов по соображениям совместимости. Конечно же, никто сегодня не будет использовать для своих диалогов такой ужасный шрифт (помимо прочих вещей - он растровый, и поэтому плохо выглядит на высоких разрешениях и не может быть сглажен).
ИсторияDEFAULT_GUI_FONTещё менее примечательна. Он был создан во время разработки Windows 95 в надежде, что он станет новым шрифтом по-умолчанию для GUI, но в Июле 1994 Windows сама перестала его использовать, предпочитая ему шрифты, возвращаемые функциейSystemParametersInfo. Его существование теперь рудиментарное.
Шрифты в XP
(DPI экрана был 96)ANSI_FIXED_FONT: Courier (Courier New), -9, 12, DPI: 96, charset: 0, pitch: 2 ANSI_VAR_FONT: MS Sans Serif (MS Sans Serif), -9, 12, DPI: 96, charset: 0, pitch: 1 DEVICE_DEFAULT_FONT: System (System), -12, 16, DPI: 96, charset: 204, pitch: 1 DEFAULT_GUI_FONT: MS Shell Dlg (Microsoft Sans Serif), 8, -11, DPI: 96, charset: 204, pitch: 0 OEM_FIXED_FONT: Terminal (Terminal), -9, 12, DPI: 96, charset: 255, pitch: 2 SYSTEM_FONT: System (System), -12, 16, DPI: 96, charset: 204, pitch: 1 SYSTEM_FIXED_FONT: Fixedsys (Fixedsys), -12, 16, DPI: 96, charset: 204, pitch: 2 CaptionFont: Trebuchet MS (Trebuchet MS), 14, -19, DPI: 96, charset: 1, pitch: 0 SmCaptionFont: Tahoma (Tahoma), 9, -12, DPI: 96, charset: 1, pitch: 0 MenuFont: Tahoma (Tahoma), 10, -13, DPI: 96, charset: 1, pitch: 0 StatusFont: Tahoma (Tahoma), 10, -13, DPI: 96, charset: 1, pitch: 0 MessageFont: Tahoma (Tahoma), 10, -13, DPI: 96, charset: 1, pitch: 0
Шрифты в Vista/7
(DPI экрана был 120)ANSI_FIXED_FONT: Courier (Courier New), -7, 12, DPI: 120, charset: 0, pitch: 2 ANSI_VAR_FONT: MS Sans Serif (MS Sans Serif), -7, 12, DPI: 120, charset: 0, pitch: 1 DEVICE_DEFAULT_FONT: System (System), -12, 20, DPI: 120, charset: 204, pitch: 1 DEFAULT_GUI_FONT: MS Shell Dlg (Microsoft Sans Serif), 8, -13, DPI: 120, charset: 204, pitch: 0 OEM_FIXED_FONT: Terminal (Terminal), -12, 20, DPI: 120, charset: 255, pitch: 2 SYSTEM_FONT: System (System), -12, 20, DPI: 120, charset: 204, pitch: 1 SYSTEM_FIXED_FONT: Fixedsys (Fixedsys), -12, 20, DPI: 120, charset: 204, pitch: 2 CaptionFont: Segoe UI (Segoe UI), 9, -15, DPI: 120, charset: 1, pitch: 0 SmCaptionFont: Segoe UI (Segoe UI), 9, -15, DPI: 120, charset: 1, pitch: 0 MenuFont: Segoe UI (Segoe UI), 9, -15, DPI: 120, charset: 1, pitch: 0 StatusFont: Segoe UI (Segoe UI), 9, -15, DPI: 120, charset: 1, pitch: 0 MessageFont: Segoe UI (Segoe UI), 9, -15, DPI: 120, charset: 1, pitch: 0
Выводы
Из вышесказанного видно, что подходящим шрифтом для окон являетсяlfMessageFont от SystemParametersInfo, а подходящим шрифтом для моноширинного отображения - ANSI_FIXED_FONT от GetStockObject.Поскольку Delphi использует намертво зашитые в программу имена шрифтов (MS Sans Serif, Tahoma и MS Shell Dlg 2) - это не всегда самый удачный выбор, если вы хотите "идти в ногу со временем" (*): чтобы ваша программа использовала бы тот же шрифт, что и все остальные программы.
Чтобы исправить это, вы можете добавить в секцию uses такой модуль:
unit UseNewFonts;
interface
uses
Graphics;
function GUIFont: TFont;
function MonoFont: TFont;
implementation
uses
Windows,
SysUtils;
var
FGUIFont: TFont;
FMonoFont: TFont;
function GUIFont: TFont;
begin
Result := FGUIFont;
end;
function MonoFont: TFont;
begin
Result := FMonoFont;
end;
procedure InitDefFontData;
var
Metrics: TNonClientMetrics;
begin
FGUIFont := TFont.Create;
FMonoFont := TFont.Create;
FillChar(Metrics, SizeOf(Metrics), 0);
Metrics.cbSize := Metrics.SizeOf; // := SizeOf(Metrics); - для старых Delphi
if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, Metrics.cbSize, @Metrics, 0) then
begin
FGUIFont.Handle := CreateFontIndirect(Metrics.lfMessageFont);
DefFontData.Height := FGUIFont.Height;
DefFontData.Orientation := FGUIFont.Orientation;
DefFontData.Pitch := FGUIFont.Pitch;
DefFontData.Style := FGUIFont.Style;
DefFontData.Charset := FGUIFont.Charset;
DefFontData.Name := UTF8EncodeToShortString(FGUIFont.Name); // UTF8Encode или AnsiToUTF8 для старых Delphi
DefFontData.Quality := FGUIFont.Quality; // Только для Delphi XE и выше
end;
FMonoFont.Handle := GetStockObject(ANSI_FIXED_FONT);
end;
initialization
InitDefFontData;
finalization
FreeAndNil(FMonoFont);
FreeAndNil(FGUIFont);
end.
Плюс для каждой формы вы должны установить ей ParentFont = True. Вот и всё. Теперь ваша программа будет использовать шрифт для UI, установленный в системе.А если у вас есть элементы управления, которые нуждаются в моноширинном шрифте, то вместо изменения шрифта на фиксированные в инспекторе объектов в режиме проектирования - лучше не трогайте его (оставив
ParentFont = True для этого элемента управления), а напишите в FormCreate присвоение шрифта, например:
Memo1.Font := MonoFont;(разумеется, у вас должен быть подключен модуль
UseNewFonts).(*) Вообще-то шрифты вроде MS Shell Dlg 2 не являются строго фиксированными (в отличие от, скажем, Tahoma). Вместо MS Shell Dlg 2 в вашу программу будет подставляться шрифт, указанный в экранных настройках пользователя. Поэтому даже если вы установите своим элементам управления фиксированный шрифт MS Shell Dlg 2 - их вид всё ещё может меняться! Поэтому либо вы должны быть готовы к адаптации размеров своих элементов управления, либо ставить действительно конкретный шрифт.
Давно нечто подобное использую в своих программах (в OnCreate формы устанавливаю шрифт из параметров системы).
ОтветитьУдалитьМаленькая ремарка: если пользователь вдруг сменил шрифт в системе (ну например переключил тему оформления с Aero на классическую), то ОС отсылает всем окнам верхнего уровня сообщение WM_SETTINGCHANGE, у которого WParam = SPI_SETNONCLIENTMETRICS.
Если Вы хотите, чтобы приложение реагировало на такие изменения, то это можно сделать в обработчике Application.OnSettingChange. Здесь надо анализировать параметр Flag, и если он равен SPI_SETNONCLIENTMETRICS, то (самое простое что можно сделать) перебирать все формы Screen и устанавливать в них шрифт.
мм.. не очень внимательно просмотрел код UseNewFonts. В этом варианте достаточно в Application.OnSettingChange заново инициализировать DefFontData, нежели перебирать все формы приложения... но суть не в этом, суть в том, чтобы обрабатывать WM_SETTINGCHANGE.
ОтветитьУдалитьмысли вслух: для одинаковых DPI у шрифта Segoe UI (Vista/7) ширина символов больше, чем ширина символов у шрифта Tahoma (XP). Это приводит к тому, что текст в некоторых метках (TLabel) в Vista/7 уходит за границу окна/панели/другого компонента.
ОтветитьУдалить..подумываю о том, что надо масштабировать окна по горизонтали..
Просто интересно - это так и задумано, что текст (код) не копируется нормальным(нет sLineBreak) или я чего-то не вижу? :-)
ОтветитьУдалитьНет, должно копироваться нормально. С переносами строк и без их нумерации.
ОтветитьУдалитьЧто то или я или Delphi 7 не понимаем "AFont.Quality"
ОтветитьУдалитьЯ не имею желания адаптировать этот код под каждую версию Delphi. Я полагаю, что вы достаточно умны, чтобы сделать это самостоятельно.
ОтветитьУдалитьПодскажи а можно так линух под xp настроить - дело магарычовое.
ОтветитьУдалитьLazarus и Delphi выдают разный размер шрифта 12 и 9 соответственно. Всё сводится к вызову одной функции из одного места и там и там.
ОтветитьУдалитьfunction CreateFontIndirect(var _para1:LOGFONT):HFONT; external 'gdi32' name 'CreateFontIndirectA'; // Lazarus
function CreateFontIndirect; external gdi32 name 'CreateFontIndirectA'; // Delphi 2006
Значения шрифтов и DPI, которые получает программа, зависят от слоя обратной совместимости ОС. В частности, Windows может посчитать, что старое приложение не умеет работать с высоким DPI и поэтому подсунет ему DPI 96 и шрифт размера 8-9. Разные версии Windows имеют различные алгоритмы для такого масштабирования. Правила отличаются в XP и ниже, от Vista до 10, от 10 и выше.
УдалитьПриложение может обозначить, что оно в курсе про то, что бывают иные DPI и размеры шрифтов.