開發自繪 GUI 框架(支援 GDI/Direct2D 雙引擎切換)時,自動佈局系統必須精準測量文字尺寸。GDI 有 GetTextExtentPoint32 等現成 API,但 Direct2D 無直接對應函數,官方文檔也語焉不詳,網上甚至流傳「辦不到」的謬論。經遍歷 MSDN,找到基於 IDWriteTextLayout 的標準解法。
IDWriteFactory* dwriteFactory = GetDirectWriteFactory();
IDWriteTextFormat* format = nullptr;
HRESULT hr = dwriteFactory->CreateTextFormat(
fontFamily, // 字體名稱 (L"Microsoft YaHei")
nullptr, // 字體集合(null 為系統預設)
fontWeight, // DWRITE_FONT_WEIGHT_NORMAL/BOLD
fontStyle, // DWRITE_FONT_STYLE_NORMAL/ITALIC
DWRITE_FONT_STRETCH_NORMAL, // 字寬
fontSize, // 點陣大小 (FLOAT)
L"", // 語系(空字串為使用者預設)
&format // 輸出介面
);
if (SUCCEEDED(hr)) {
format->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); // 禁止自動換行
// format 現在可作為 ID2D1RenderTarget::DrawText 的字體參數
}
IDWriteTextLayout* textLayout = nullptr;
hr = dwriteFactory->CreateTextLayout(
textBuffer, // 文字內容 (WCHAR*)
textLength, // 字元數
textFormat, // 上一步建立的 IDWriteTextFormat
0, // 排版寬度(0 為不限制)
0, // 排版高度(0 為不限制)
&textLayout
);
if (SUCCEEDED(hr)) {
DWRITE_TEXT_METRICS metrics;
hr = textLayout->GetMetrics(&metrics);
if (SUCCEEDED(hr)) {
// 關鍵尺寸:含尾隨空白的寬度、高度
Size textSize(
(int)ceil(metrics.widthIncludingTrailingWhitespace),
(int)ceil(metrics.height)
);
// textSize 即為所需文字區域大小
}
textLayout->Release(); // 記得釋放 COM 介面
}
GetMetrics、HitTest、Draw 等豐富功能。widthIncludingTrailingWhitespace 包含行尾空白,佈局計算通常應用此值;width 則不含尾隨空白。作者構建了類 WPF 的 Vczh Library++ 3.0,支援:
TableLayoutPanel/Grid)
Candidate\GUI\GuiDemo\GuiDemo.sln,按 F5 即可體驗。專案已指定 DXSDK 路徑,若編譯失敗請調整為本機安裝路徑。
Direct2D 文字測量的正規路徑:IDWriteFactory → CreateTextFormat → CreateTextLayout → GetMetrics。雖比 GDI 繞彎,但功能更強(複雜排版、OpenType 特性、Hit Testing),且為現代 Windows 圖形堆疊基石。掌握此模式,即可構建高效能、高保真、DPI 感知的文字渲染系統。