Как определить, установлен ли в семействе определенный стиль семейства шрифтов?
В некоторых проектах VCL у меня есть пользовательский интерфейс, использующий Roboto Bold. Если у пользователя установлен Roboto, но нет конкретного шрифта в стиле Roboto Bold, система заменит Roboto и сделает его жирным, что приводит к немного большему интервалу, что иногда приводит к неожиданному переносу строк.
Я могу легко определить, установлен ли Roboto с помощью Screen.Fonts.IndexOf('Roboto'), но это возвращает true, даже если Roboto Bold не установлен. А Roboto Bold не отображается в Screen.Fonts, поскольку в этом списке показаны только фамилии.
Как я могу детализировать семейство, чтобы увидеть, какие фактические шрифты установлены?
Поскольку Screen.Fonts сжимает список во избежание дублирования, вам придется вызвать функцию Win32 EnumFontFamiliesEx() напрямую, чтобы получить полный список шрифтов или даже просто выполнить поиск определенного шрифта.
Спасибо, Реми. Посмотрим, смогу ли я это сделать.





Я использовал это:
function CheckFontCB(const lf:TLogFont;const tm:TTextMetric;ft:DWORD;lParam:NativeInt):integer; stdcall;
begin
Result:=0;//found one! EnumFontFamiliesEx can stop enumerating now, and will return 0
end;
function IsFontInstalled(const x:string):boolean;
var
i,l:integer;
lf:TLogFont;
begin
ZeroMemory(@lf,SizeOf(TLogFont));
lf.lfCharSet:=DEFAULT_CHARSET;
l:=Length(x);
if l>=LF_FACESIZE then raise Exception.Create('Invalid font name length');
for i:=0 to l-1 do lf.lfFaceName[i]:=x[i+1];
lf.lfFaceName[l]:=#0;
Result:=EnumFontFamiliesEx(GetDC(0),lf,@CheckFontCB,0,0)=0;
end;
Стейн, Спасибо. Я только что попробовал это и получаю сообщение об ошибке в строке результата IsFontInstalled. Ошибка: несовместимые типы логических и целых чисел. Есть ли шанс, что опечатка?
Спасибо, да, я ошибся. Не знаю почему, думаю, у меня может быть автоматическое преобразование из LongBool в логическое значение или что-то в этом роде.
работая над ответом Стейна, я немного отредактировал, чтобы он работал на меня. Шрифт установлен, если IsFontInstalled возвращает 0.
function CheckFontCB(const lf:TLogFont;const tm:TTextMetric;ft:DWORD;lParam:NativeInt):integer; stdcall;
begin
Result:=0;//found one! EnumFontFamiliesEx can stop enumerating now, and will return 0
end;
function IsFontInstalled(const x:string):integer;
var
i,l:integer;
lf:TLogFont;
begin
ZeroMemory(@lf,SizeOf(TLogFont));
lf.lfCharSet:=DEFAULT_CHARSET;
l:=Length(x);
if l>=LF_FACESIZE then raise Exception.Create('Invalid font name length');
for i:=0 to l-1 do lf.lfFaceName[i]:=x[i+1];
lf.lfFaceName[l]:=#0;
Result:=EnumFontFamiliesEx(GetDC(0),lf,@CheckFontCB,0,0);
end;
Спасибо!
Скотт
Лучшим решением было бы оставить IsFontInstalled, возвращающим логическое значение, и изменить последнюю строку на Result := EnumFontFamiliesEx(GetDC(0),lf,@CheckFontCB,0,0) = 0;. IsFontInstalled должен возвращать значение True или False, соответствующее его имени. Кроме того, его проще использовать как if IsFontInstalled then, а не как if (IsFontInstalled = 0) then.
Определенно лучше, да. Спасибо. Я стал ленивым и был просто счастлив, что у меня есть что-то, что работает.
Кен, спасибо, но, к сожалению, это не работает. Это на самом деле проблема. Roboto Bold никогда не присутствует в Screen.Fonts, поскольку система сжимает список до только Roboto. Результат равен -1 независимо от того, есть ли Roboto Bold или нет.