【问题标题】:How to draw text with the default UI font in DirectWrite?如何在 DirectWrite 中使用默认 UI 字体绘制文本?
【发布时间】:2017-05-21 04:24:38
【问题描述】:

CreateTextFormat 方法需要一个 fontFamilyName 参数。如何创建使用默认 UI 字体的 IDWriteTextFormat?

【问题讨论】:

  • 你是指系统字体的“默认UI字体”还是你的应用程序中使用的字体?
  • 我的意思是系统字体(在本机 Windows 应用程序中用于 UI 元素的字体)
  • 使用 SPI_GETNONCLIENTMETRICS 调用 SystemParametersInfo 并使用其中返回的消息框字体。
  • 我也想说
  • 我假设您已经拥有来自SystemParametersInfo() 的 UI 字体;我不确定您之前使用的是什么 UI 字体。话虽如此,一旦您拥有LOGFONT,将其传递给IDWriteGdiInterop::CreateFontFromLOGFONT() 以获取IDWriteFont。从那里,您可以提取CreateTextFormat() 的大部分参数。它唯一没有给你的是字体大小,这有点复杂,因为字体大小以设备依赖的方式存储在LOGFONT结构中。

标签: c++ windows winapi fonts directwrite


【解决方案1】:

请注意,这里的所有代码都是在没有任何检查的情况下完成的(这里返回 HRESULT 的方法太多,会炸毁这个示例!)。

要获取系统范围的字体,您应该使用:

(这是来自另一个stackoverflow问题!)

NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
HFONT hFont = CreateFontIndirect(&(ncm.lfMessageFont)); //

现在用这个来作画:

HDC hdc = BeginPaint(...); //Creates a device context
SelectObject(hdc, hFont);
//Your font is now set for the current device context
//do something

DeleteObject(hFont); //Don't forget to do this at the end!

this问题有点不同!

这个解决方案真的很原始,在我看来很难看。

替代解决方案确实获得 IDWriteFont(看起来很丑但很好):

//just the same as above except the hfont, instead use
NONCLIENTMETRICS ncm;

ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);

IDWriteFactory *dwriteFactory_;
DWriteCreateFactory(
    DWRITE_FACTORY_TYPE_SHARED,
    __uuidof(IDWriteFactory),
    reinterpret_cast<IUnknown**>(&dwriteFactory_)
);

IDWriteGdiInterop* gdiInterop = NULL;
dwriteFactory_->GetGdiInterop(&gdiInterop);

IDWriteFont* sys_font = nullptr;
gdiInterop->CreateFontFromLOGFONT(&ncm.lfMessageFont, &sys_font); //Now we have it!

//The text format can now be aquired like this
//We need the font family of our font
IDWriteFontFamily* family = nullptr;
sys_font->GetFontFamily(&family);

//Now we have to get the "localized" name of our family
IDWriteLocalizedStrings* font_family_name = nullptr;
family->GetFamilyNames(&font_family_name);
UINT32 index = 0;
UINT32 length = 0;
BOOL exists = false;
font_family_name->FindLocaleName(L"en-us", &index, &exists);
font_family_name->GetStringLength(index, &length);
wchar_t* name = new wchar_t[length + 1];
font_family_name->GetString(index, name, length + 1);
wprintf(L"%s\n", name);

//Some user defined stuff
DWRITE_FONT_WEIGHT font_weight = DWRITE_FONT_WEIGHT_BLACK;
DWRITE_FONT_STYLE font_style = DWRITE_FONT_STYLE_ITALIC;
DWRITE_FONT_STRETCH font_stretch = DWRITE_FONT_STRETCH_EXPANDED;

IDWriteTextFormat* text_format = nullptr;
dwriteFactory_->CreateTextFormat(name, nullptr, font_weight, font_style, font_stretch, 10.0, L"en-us", &text_format);

即使没有检查,代码在我的计算机上运行也没有任何问题,并给我与第一个解决方案相同的结果(Windows 10,字体系列名称是 Segoe UI)。

来源: General Microsoft DirectWrite API documentation

CreateIndirectFont Documentation

How to enumerate font families, Microsoft documentation

【讨论】:

  • 这不能回答问题;使用 GDI 而不是 DirectWrite。
  • 答案的前半部分仍然是正确的,但现在我想知道为什么 OP 没有意识到这一点......使用 DirectWrite 有点复杂。
  • 是的,我也看到了。然后我必须纠正最后一半,谢谢信息
  • 我刚刚又读了一遍文档。使用此方法,必须有一个具有此字体系列的系统字体集合,因为方法 CreateFontFromLOGFONT(...) 依赖于此。所以这很好!
  • IDWriteGdiInterop::CreateFontFromLOGFONT 文档非常详细地说明了将 LOGFONT 中的 lfHeight 和 lfWidth 字段从逻辑单位转换为 DIP 时所做的假设(以及无论进程的 DPI 如何,这些假设是否有效)意识设置)。
猜你喜欢
  • 1970-01-01
  • 2011-05-03
  • 2016-02-23
  • 1970-01-01
  • 2014-12-17
  • 2013-06-08
  • 2013-07-30
  • 2017-06-03
  • 2019-05-17
相关资源
最近更新 更多