• 0
ruslan

Использование своего шрифта под Windows

Вопросы

Подскажите, знает ли кто как в FMX использовать свой шрифт не устанавливая его в в систему ?

под vcl было что-то вроде:

procedure LoadFont;
  var
    MyResStream: TResourceStream;
  begin
    MyResStream:= GetResStream('MyFont');
    MyResStream.SavetoFile('MyFont.ttf');
    AddFontResource(PChar('MyFont.ttf'));
    SendMessage(HWND_BROADCAST, WM_FONTCHANGE,0,0);
  end;

  procedure UnLoadFont;
  begin
    RemoveFontResource('MyFont.ttf') ;
    SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0) ;
  end;

в фаирманках, что удивительно(сарказм),  этот не работает. 

как я понимаю, шрифты подгружаются в момент запуска приложения, и рисуются средствами gdi...

 

хотел поправить юнит FMX.FontGlyphs.Win по аналогии с http://delphifmandroid.blogspot.com/2015/01/true-type.html

но TWinFontGlyphManager даже не создается( дебагер не попадает в конструктор ).

 

вопрос: как решить эту маленькую проблему ?

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 ответов на этот вопрос

  • 0

Уважаемые гуру! Вопрос больше к вам. Так как в VCL Windows-приложении использовать свой шрифт - проблем нет. А как быть с нашей замечательной FMX ?

 

Успользование своего шрифта в приложении. Варианты - либо временное, на время работы приложения, либо постоянное - установка приложением своего шрифта.

 

P.S. Варианты с Android и iOS не предлагать. Интересует только Windows.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Все приемы для Vcl лично у меня ни к чему не привели. Вам проще всего будет bat-файл для установки шрифта в систему написать, имхо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Друзья! Неужели никто еще не сталкивался с такой же проблемой?

Установка шрифта какими-то "экзотическими" методами (типа батников и "дополнительным софтом") - это, мягко говоря, некорректное решение.

Может кто-то подскажет программное решение?

А то Андрей Ефимов любезно подсказал как можно использовать шрифты на андроиде, а как быть в данном случе с виндой!?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

а подредактировать FMX.FontGlyphs.Win.pas и в нем изменить название шрифта при выполнении CreateFont пробовали? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

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

выход нашел только один - инсталятор. не хотелось, но будет инсталятор

Изменено пользователем sinuke

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

В общем можно сделать, конечно, установку шрифта в инсталлере программы. И это будет оптимальным решением.

Но можно обойтись и без него.

Не буду расписывать детали, просто закину приложение и фрагменты кода. Думаю разберетесь. Естественно изменив на свои шрифты и т.п.

Все нижеперечисленное - в файл проекта DPR, перед Application.Initialize;

const
  CKey = '\Software\Microsoft\Windows NT\CurrentVersion\Fonts';
  CFontFileName = 'spherelive.ttf';
  CFontName = 'spherelive (TrueType)';
procedure ExecuteWait(const sProgramm: string; const sParams: string = ''; fHide: Boolean = false);
var
  ShExecInfo: TShellExecuteInfo;
begin
  FillChar(ShExecInfo, sizeof(ShExecInfo), 0);
  with ShExecInfo do
  begin
    cbSize := sizeof(ShExecInfo);
    fMask := SEE_MASK_NOCLOSEPROCESS;
    lpFile := PChar(sProgramm);
    lpParameters := PChar(sParams);
    lpVerb := 'open';
    if (not fHide) then
      nShow := SW_SHOW
      else
      nShow := SW_HIDE
  end;
  try
    if (ShellExecuteEx(@ShExecInfo) and (ShExecInfo.hProcess <> 0)) then
    try
      WaitForSingleObject(ShExecInfo.hProcess, INFINITE)
    finally
      CloseHandle(ShExecInfo.hProcess);
    end;
  except
    On E : Exception do
      ShowMessage('font install Exception: ' + E.Message);
  end;
end;
  if not IsFontRegistered(TPath.Combine(ExtractFilePath(ParamStr(0)), CFontFileName), CFontName) then
    if FileExists(TPath.Combine(ExtractFilePath(ParamStr(0)), 'RegFontC.exe')) then
      ExecuteWait(TPath.Combine(ExtractFilePath(ParamStr(0)), 'RegFontC.exe'));

  Application.Initialize;

Где будет лежать файл со шрифтом - это уже ваше дело. Можно его куда угодно поместить. Хоть в ресурсы, хоть файлом просто, хоть с инета скачать.

P.S. Ну и конечно - это все именно под винду...

RegFont.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

В Berlin и Tokyo AddFontResource и RemoveFontResource прекрасно отрабатывают, только вызывать их надо до Application.Run.

Кстати, лучше использовать  AddFontResourceEx и RemoveFontResourceEx с флагом FR_NOT_ENUM - тогда надобность в SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0) отпадает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 01.05.2017 в 11:15, dnekrasov сказал:

В Berlin и Tokyo AddFontResource и RemoveFontResource прекрасно отрабатывают, только вызывать их надо до Application.Run.

Кстати, лучше использовать  AddFontResourceEx и RemoveFontResourceEx с флагом FR_NOT_ENUM - тогда надобность в SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0) отпадает.

Токио, Билдер... не работает

    AddFontResourceEx(L"4960.ttf", FR_PRIVATE , NULL);

    try {
        Application->Initialize();
        Application->CreateForm(__classid(TForm2), &Form2);
        Application->Run();
    }

проверка

 

  TStrings * FontList;
  HDC dContext;
  LOGFONT * LFont;

  dContext = GetDC(0);
  LFont = new LOGFONT();
  LFont->lfCharSet = DEFAULT_CHARSET;

  EnumFontFamiliesEx(dContext, LFont, (FONTENUMPROC)&EnumFontsList, LPARAM(Memo1->Lines), 0);
  ReleaseDC(0, dContext);
  Label55->TextSettings->Font->Family = "5x5 Dots";
 

в списке фонт появляется, но к контролам не применяется

если   делать через FR_NOT_ENUM, то в списке даже не появляется и тоже не работает

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 23.08.2018 в 02:20, vasilius сказал:

AddFontResourceEx(L"4960.ttf", FR_PRIVATE , NULL);

FR_PRIVATE не работает - используйте FR_NOT_ENUM или 0.

FR_NOT_ENUM и предназначен для того, чтобы он не попадал в список перечисления.

В 23.08.2018 в 02:20, vasilius сказал:

Label55->TextSettings->Font->Family = "5x5 Dots";

А у Label55 из StyledSettings убрали Family?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Вот скриншоты

В проекте перед всеми инитами делаю

#ifdef _WIN32
	int res = AddFontResourceEx(L"4960.ttf", FR_NOT_ENUM , NULL);
#endif

	try {
		Application->Initialize();
		Application->CreateForm(__classid(TForm2), &Form2);
		Application->Run();
	}
	catch (Exception &exception) {
		Application->ShowException(&exception);
	}
	catch (...) {
		try {
			throw Exception("");
		}
		catch (Exception &exception) {
			Application->ShowException(&exception);
		}
	}
	return 0;

на скриншоте показано, что res == 1 - тоесть ф-ция удачно выполнилась

дальше по нажатию на кнопку пытаюсь поменять шрифт

Label55->TextSettings->Font->Family = "5x5 Dots";

StyledSettings все выключены - показано на скрине - в результате ничего.... -(

b1dc25[1].jpg

b1c7ba[1].jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 29.08.2018 в 00:38, vasilius сказал:

AddFontResourceEx(L"4960.ttf", FR_NOT_ENUM , NULL);

Попробуйте указать полный путь к шрифту, а не только его имя файла. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
11 минут назад, dnekrasov сказал:

Попробуйте указать полный путь к шрифту, а не только его имя файла. 

скопировал шрифт в корень диска С

#ifdef _WIN32
	int res = AddFontResourceEx(L"C:\4960.ttf", FR_NOT_ENUM , NULL);
#endif

	try {
		Application->Initialize();
		Application->CreateForm(__classid(TForm2), &Form2);
		Application->Run();
	}
	catch (Exception &exception) {
		Application->ShowException(&exception);
	}
	catch (...) {
		try {
			throw Exception("");
		}
		catch (Exception &exception) {
			Application->ShowException(&exception);
		}
	}
	return 0;

все-равно не работает

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Похожий контент

    • От Вадим Смоленский
      Узнал, что в UWP API включены средства для получения уникального идентификатора компьютера. Это юнит Windows.System.Profile, класс HardwareIdentification, метод getPackageSpecificToken. Существуют ли способы обратиться к этим средствам из Delphi?
      Вообще, я привык считать, что такая идентификация компьютера в принципе невозможна, в отличие от мобильных устройств. Но прогресс, как известно, не остановить.
    • От Вадим Смоленский
      Для задач, связанных с вводом японского текста, мне нужно научиться перехватывать системное сообщение WM_IME_NOTIFY. Насколько могу судить, в FireMonkey эти вещи делаются (если вообще делаются) принципиально иначе, нежели в VCL. Конкретного ничего не нагуглил. Не поможет ли кто?
    • От slav_z
      У меня для приложений написанных на FireMonkey не вызывается меню игры windows. Для VCL все в порядке. XE8. Если у кого есть решение этой проблемы, поделитесь пожалуйста. (комбинация клавиш Win+G при запущенном приложении)
    • От POV
      Винда 10, два компа (рабочий ноут и планшет от мелкософта - у первого 100% экран, у другого 200%).
      Исходя из габаритов разных там компонентов и другой формы, рассчитываю Top и Left интересующей меня формы. На ноуте выводится где и хотел, а на планшете выше и левее. Смещение не кратно никак масштабу. В доступе планшета нет, как отлаживать не придумаю.
      Косяк всё же в в масштабе может быть или иное?
    • От Вадим Смоленский
      В феврале я сетовал, что мое Windows-приложение не хочет нормально запускаться в Linux под Wine 3.0. Но время идет, вышел Wine 3.6 - и теперь один из тестировщиков радостно сообщил, что всё заработало, за вычетом одного досадного момента. А именно: приложение способно сохранять фокус ввода лишь долю секунды, потом теряет. Соответственно, невозможно ничего ввести в текстовые боксы, разве только одну-две буквы. Можно щелкнуть по заголовку приложения, оно опять получит фокус - и через мгновение снова потеряет. Куда именно при этом переходит фокус, непонятно. Тестировщик утверждает, что только мое приложение ведет себя так, все остальные работают нормально.
      Нет ли у кого-нибудь идей? Что нужно проверить?
    • От Вадим Смоленский
      В декабре я задавал здесь вопрос о борьбе с перехватами нажатий клавиш компонентом TWebBrowser. Продвинутый пользователь Kami посоветовал тогда, раз уж меня интересует только Windows, поставить хук на клавиатуру. Поделился полезной ссылкой. Добавил, что можно еще много чего нагуглить. Что-то действительно нагуглилось - но не в том объеме, чтобы я смог четко понять, как это следует делать. Вопросов много. Куда именно должна быть воткнута функция KeyboardProc? Что в ней должно содержаться, чтобы управление передавалось уже написанному обработчику события FormKeyDown? Многие также упоминают о возникающих проблемах с юникодом, и хорошо было бы понять, как уберечься от них.
      Буду очень признателен, если кто-нибудь осветит эту темную для меня материю.
    • От Вадим Смоленский
      Как преобразовать тип HString в обычную строку?
      Нагуглил упоминания о функции TWindowsString.HStringToString, которая должна находиться в System.WinrtHelpers. Но такого юнита в поставке Delphi не наблюдаю. Может, его можно где-нибудь раздобыть? Или существуют иные способы?
    • От Вадим Смоленский
      Пытаясь разобраться с проблемой размещения файлов в UWP-приложениях, пришел к необходимости создать в своем коде объект класса ApplicationData. Этот класс описан на соответствующей странице майкрософтовской документации, где в самом начале обозначено следующее:
      Namespace:  Windows.Storage
      Assemblies:  Windows.Storage.dll, Windows.dll
      Юнита с именем Windows.Storage или Winapi.Windows.Storage я в поставке Delphi не наблюдаю. Неудивительно, что попытки вставить соответствующие идентификаторы в раздел uses ни к чему не ведут. Как в таких случаях поступают? Откуда берут необходимое?
    • От Вадим Смоленский
      Хочу еще раз обратиться к коллективному разуму в надежде все-таки разобраться с тем, как должен быть устроен пакет appx для размещения в Microsoft Store. А именно - как организовать размещение настроек и пользовательских файлов в специально отведенных для этого папках, а не в установочном каталоге, что запрещено.
      Вся информация, которую я смог к сегодняшнему дню накопать, размещена на этой странице майкрософтовской документации и сводится к тому, что при инсталляции пакета appx автоматически создается хранилище пользовательских данных из трех папок. Цитирую: one for local files, one for roaming files, and one for temporary files. В общем-то, это удобно - по крайней мере, не нужно заботиться о деинсталляции: ровно эти же папки при удалении программы и сотрутся.
      Вопрос в том, как к этому хранилищу обратиться. В идеале, конечно же, хотелось бы иметь возможность уже в Deployment Manager обозначить для некоторых файлов, что они должны быть положены в это хранилище, а не в установочный каталог. Но как это можно сделать и можно ли сделать вообще, мне понять не удалось. Списка констант для параметра Remote Path я найти не смог, а отдельные упоминаемые тут и там константы ('res', 'assets', 'classes', 'library') явно относятся к мобильным платформам, а не к Windows.
      Если так поступить нельзя, остается класть всё в установочный каталог, а при первом запуске приложения переносить в нужное место. Но опять же: как приложению заполучить полный адрес этого места? Ведь это вовсе не привычные нам CSIDL_APPDATA и не CSIDL_COMMON_APPDATA, это нечто новое, доселе невиданное, в документации называемое "local app data store". На той же странице есть пример соответствующего кода с использованием класса ApplicationData, но он написан на незнакомом мне C#. Там есть также ссылки на описание класса ApplicationData, но по ссылкам тоже C# и C++. Был бы очень признателен, если бы кто-нибудь показал мне, как заполучить адрес local app data store средствами Delphi.
    • От Вадим Смоленский
      Целый месяц бодаюсь с Microsoft Store, пытаясь разместить у них свое UWP-приложение в виде пакета appx. Получаю отлуп за отлупом. Проблема: приложение должно располагать папкой для пользователя, отличной от установочного каталога, где он мог бы сохранять файлы. Там же должны храниться файлы настроек. Раньше, создавая дистрибутив в InnoSetup, я всегда предусматривал создание такой папки по адресу <user>\AppData\Roaming\MyApp. Теперь всё полагается указывать в разделе Deployment - но как там указать такой адрес? Вроде бы, есть графа "Remote path", и логично существовать каким-то макросам для нее, вроде AppData - но никакой информации на эту тему я найти не смог. Видел лишь упоминания таких макросов, как res, assets, classes, library - однако все они, как я понял, относятся к мобильным платформам.
      Попытки обходных маневров не удались. Сначала я решил всё класть в установочный каталог, а при первом запуске создавать нужную папку и перебрасывать в нее несколько файлов. На моем компьютере это работает, но при тестировании в Microsoft Store отчего-то валится (присылают скриншот с сообщением "Access is denied"). То ли нельзя стирать файлы в установочном каталоге, то ли нельзя в таком режиме создавать новый каталог. Потом я прочитал где-то, что UWP-приложениям всё равно, где лежат файлы, они могут их менять даже в установочном каталоге. Попробовал всё валить в одну кучу и так работать. Увы, опять отрапортовали о падении ("The app tries to create a file under WindowsApps folder").
      Получается, что все-таки нужно как-то заставить appx-дистрибутив создавать при установке папку по адресу <user>\AppData\Roaming\MyApp. Но как?
      Спрашивал на experts-exchange, там знатоков не нашлось. Если и здесь нет, может, кто-нибудь хотя бы подскажет, в каких местах есть смысл спросить?
  • Последние посетители   0 пользователей онлайн

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