TScreen 代表應用程式運行環境的顯示裝置抽象,全域單例 Screen(定義於 Forms.hpp)提供螢幕幾何屬性、視窗/數據模組枚舉、系統字體/光標/輸入法清單、焦點追蹤事件等能力。本文系統講解核心屬性、多視窗協調模式、自定義光標註冊、高 DPI 適配策略與常見陷阱。
TObject
└── TPersistent
└── TComponent
└── TScreen // 非視覺,全域單例 Screen
| 類別 | 屬性 | 類型 | 說明 |
|---|---|---|---|
| 幾何屬性 | Width/Height | int | 螢幕像素寬高(虛擬桌面包含所有監視器) |
PixelsPerInch | int | 垂直 DPI(通常 96/120/144/192),水平需自行查詢 | |
WorkAreaWidth/Height | int | 工作區(扣除任務列)尺寸,VCL 內部計算 | |
| 視窗枚舉 | FormCount/Forms[] | int / TForm* | 當前顯示的 TForm 列表 |
CustomFormCount/CustomForms[] | int / TCustomForm* | 含 TForm、TPropertyPage 等 | |
DataModuleCount/DataModules[] | int / TDataModule* | 已實例化數據模組 | |
ActiveForm/ActiveControl | TForm* / TWinControl* | 當前焦點視窗/控件(只讀) | |
| 字體/光標/輸入法 | Fonts | TStrings* | 系統安裝字體名稱列表 |
Cursors[int Index] | HICON | 光標句柄陣列(含內建 + 自定義) | |
Imes/DefaultIme/DefaultKbLayout | TStrings* / AnsiString / HKL | 輸入法編輯器清單與預設狀態 | |
IconFont | TFont* | 圖標標籤字體(Shell 介面一致性) |
| 事件 | 觸發時機 | 典型用途 |
|---|---|---|
OnActiveControlChange | 焦點在控件間移動(含跨視窗) | 工具欄按鈕狀態同步、狀態列上下文更新 |
OnActiveFormChange | 活動視窗切換 | MDI 子視窗菜單合併、視窗特定工具欄顯隱 |
事件順序:跨視窗焦點移動 → OnActiveFormChange → OnActiveControlChange。
.cur/.ani,資源 ID 如 CUR_MYCUSTOM。const int crMyCustom = 100;HICON hCur = LoadCursor(HInstance, MAKEINTRESOURCE(CUR_MYCUSTOM));
Screen->Cursors[crMyCustom] = hCur; // 索引即常數值
Control->Cursor = crMyCustom; 或 Screen->Cursor = crMyCustom;(全域)。DestroyCursor。// 獲取主監視器 DPI(Win10 1703+)
UINT dpiX, dpiY;
GetDpiForMonitor(MonitorFromWindow(Application->Handle, MONITOR_DEFAULTTOPRIMARY),
MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
// 邏輯像素 → 物理像素
int PhysicalX = MulDiv(LogicalX, dpiX, 96);
int PhysicalY = MulDiv(LogicalY, dpiY, 96);
// 字體大小調整(邏輯點數 → 像素)
int PixelHeight = -MulDiv(PointSize, dpiY, 72); // LOGFONT lfHeight
Font->Height = PixelHeight; // 負值表字符高度
關鍵設定:
- Application->Scaled = true(VCL 自動縮放控件)。
- Manifest dpiAware=PerMonitorV2(Win10 1703+)。
- Screen->PixelsPerInch 僅反映主監視器垂直 DPI,多監視器異構 DPI 需自行查詢。
// 遍歷所有視窗關閉(除主視窗)
for (int i = Screen->CustomFormCount - 1; i >= 0; --i) {
TCustomForm* f = Screen->CustomForms[i];
if (f != Application->MainForm) f->Close();
}
// 尋找特定類型視窗
TMyForm* frm = nullptr;
for (int i = 0; i < Screen->FormCount; ++i)
if (dynamic_cast(Screen->Forms[i])) { frm = (TMyForm*)Screen->Forms[i]; break; }
// 全域焦點控件安全檢查
if (Screen->ActiveControl && Screen->ActiveControl->HandleAllocated())
Screen->ActiveControl->SetFocus();
| 現象 | 原因 | 對策 |
|---|---|---|
| Width/Height 不等於主監視器解析度 | 虛擬桌面跨多監視器 | 用 GetMonitorInfo 獲取單監視器矩形 |
| Fonts 列表缺少剛安裝字體 | 字體快取未刷新 | 呼叫 EnumFontFamiliesEx 重新枚舉或重啟應用 |
| 自定義光標不顯示 | 資源類型錯誤(用 BITMAP 而非 CURSOR) | 資源編輯器確認類型為 CURSOR/ANICURSOR |
| OnActiveFormChange 重複觸發 | 焦點在同視窗內控件移動也觸發 | 事件內比較 Screen->ActiveForm != lastForm |
| 高 DPI 下自繪控件模糊 | 未處理 PixelsPerInch 變化 | 繼承 TWinControl 覆寫 ChangeScale 或用 Scaled 屬性 |
TScreen 是 VCL 感知「顯示環境」的唯一入口,掌握其幾何查詢、資源枚舉、焦點事件與 DPI 適配模式,即能構建在單/多監視器、標準/高 DPI、不同語系環境下均表現一致的專業桌面應用。