首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Windows 7 開發實作:高 DPI 感知 - Win32 Native (C++) 篇

     編輯:關於.NET

實驗概覽

同 WinForms 篇,高 DPI 環境日益普及,原生 C++ 應用程式若無 DPI 感知會面臨模糊、截斷、版面破裂。本實驗示範如何透過資訊清單宣告 DPI 感知、使用 CDPI 輔助類縮放 UI 元素、主題文字繪製 API 達成真正的高 DPI 相容。

學習目標

  • 確保電腦處於高 DPI 模式 (144 DPI / 150%)
  • 比較 144 DPI 與 96 DPI 下的 UI 元素表現
  • 以資訊清單宣告應用程式為 DPI 感知
  • 縮放按鈕大小與版面配置
  • 縮放視窗大小,使用預設主題文字 API 繪製文字

系統需求

  • Microsoft Visual Studio 2008
  • Windows 7

練習 #1:確保高 DPI 模式

同 WinForms 篇:控制台 > 顯示 > 選擇「較大 - 150%」(144 DPI)。

練習 #2:在 144 DPI 下執行原生應用程式並比較

  1. VS 2008 開啟 HighDPIApp.sln,設定 HighDPINativeApp 為啟動專案。
  2. 建置、執行 (預設無資訊清單,依賴 DPI 虛擬化)。

96 DPI vs 144 DPI 對照 (預設 DPI 虛擬化)

UI 元素144 DPI 外觀
視窗大小較大 (虛擬化放大)
按鈕大小較大
文字大小較大
按鈕文字截斷是
視窗文字截斷是
模糊效果是 (整體 bitmap 伸縮)

原因: 預設啟用 DPI 虛擬化 (Vista 引入),整個視窗內容以 bitmap 形式放大,導致模糊、文字截斷、版面不精確。

練習 #3:宣告 DPI 感知 (關閉虛擬化)

  1. 專案 > 屬性 > 組態屬性 > 資訊清單工具 > 輸入和輸出 > 其他資訊清單檔案 輸入 DeclareDPIAware.manifest。
  2. 該檔案內容:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
         xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
  <asmv3:application>
    <asmv3:windowsSettings xmlns="https://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>
  1. 重建、執行。虛擬化關閉,視窗/按鈕恢復 96 DPI 實際像素大小,文字由系統放大但未截斷 (因視窗未放大),模糊效果消失。

宣告 DPI Aware 後對照

UI 元素144 DPI 外觀
視窗大小相同 (96 DPI 像素)
按鈕大小相同
文字大小較大
按鈕文字截斷是
視窗文字截斷是
模糊效果無

練習 #4:修正按鈕大小與版面配置

使用專案內建的 CDPI 類 (g_metrics 實例) 將設計時像素轉換為當前 DPI 對應的邏輯像素。

任務 1:按鈕大小縮放

// 在 DemoApp::CreateChildWindows 中
SIZE buttonSize = { 60, 26 };
g_metrics.ScaleSize(&buttonSize);  // 依 DPI 縮放大小

任務 2:按鈕位置縮放

POINT ptButton1Pos = { 10, 55 };
g_metrics.ScalePoint(&ptButton1Pos);

POINT ptButton2Pos = { 85, 55 };  // 相對按鈕 1 右側 75 像素
g_metrics.ScalePoint(&ptButton2Pos);

POINT ptButton3Pos = { 160, 55 };
g_metrics.ScalePoint(&ptButton3Pos);

結果:按鈕大小與間距隨 DPI 正確縮放,版面不錯位。

練習 #5:修正視窗大小與文字截斷

任務 1:視窗尺寸縮放

// DemoApp::Initialize 中 CreateWindow 參數
g_metrics.ScaleX(420),  // 寬度
g_metrics.ScaleY(200)   // 高度

任務 2:使用主題文字 API 取代 TextOut

// DemoApp::OnRender
// TextOut(ps.hdc, rcText.left, rcText.top, szText, lstrlen(szText));

OffsetRect(&rcText, g_metrics.ScaleX(8), g_metrics.ScaleY(8));
HTHEME hTheme = OpenThemeData(hWnd, VSCLASS_TEXTSTYLE);
if (hTheme)
{
    DrawThemeText(hTheme, ps.hdc, TEXT_BODYTEXT, 0, szText, -1, DT_SINGLELINE, 0, &rcText);
    CloseThemeData(hTheme);
}
else
{
    DrawText(ps.hdc, szText, -1, &rcText, DT_SINGLELINE); // 回退
}
  • DrawThemeText 支援主題渲染、高 DPI 字體縮放、ClearType、自動換行/截斷處理。
  • 搭配 g_metrics.ScaleX/Y 調整文字矩形位置。

最終結果

視窗大小正確、按鈕大小間距正確、文字清晰無截斷、長寬比維持、無模糊——達成真正的高 DPI 感知。

總結與進階建議

  • 關鍵步驟: 資訊清單 <dpiAware>true</dpiAware> → 關閉虛擬化,接管繪製責任。
  • 縮放輔助: 使用 CDPI 類 (ScaleX/ScaleY/ScaleSize/ScalePoint) 將所有硬式編碼像素轉換為邏輯像素。
  • 文字繪製: 改用 DrawThemeText 等主題 API,自動處理高 DPI 字體度量。
  • 高保真素材: 準備多解析度位圖/圖示/工具列圖片,執行時選擇最接近當前 DPI 的素材再微縮放,避免模糊與失真。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved