示範在 WM_PAINT 中正確繪製文字:取得裝置環境(BeginPaint)、查詢用戶區大小(GetClientRect)、以 DrawText 置中單行顯示、釋放裝置環境(EndPaint)。對比低層 TextOut,DrawText 內建換行、置中、裁剪功能,更適合動態版面。
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
LOCAL rect:RECT
; RECT 結構 (Windows.inc 定義)
RECT STRUCT
left LONG ?
top LONG ?
right LONG ?
bottom LONG ?
RECT ENDS
GetClientRect(hWnd, &rect) 回傳用戶區座標:left=top=0,right=寬度,bottom=高度。
.ELSEIF uMsg==WM_PAINT
INVOKE BeginPaint, hWnd, ADDR ps
MOV hdc, EAX
INVOKE GetClientRect, hWnd, ADDR rect
INVOKE DrawText, hdc, ADDR OurText, -1, ADDR rect, \
DT_SINGLELINE OR DT_CENTER OR DT_VCENTER
INVOKE EndPaint, hWnd, ADDR ps
DrawText PROTO hdc:HDC, lpString:DWORD, nCount:DWORD, lpRect:DWORD, uFormat:DWORD
| 參數 | 說明 |
|---|---|
hdc | 裝置環境控制代碼 |
lpString | 欲繪製字串位址,以 0 結尾或由 nCount 指定長度 |
nCount | 字元數,-1 表以 0 結尾字串自動計算 |
lpRect | 格式化矩形區域 (RECT),同時作為裁剪區 |
uFormat | 格式旗標組合 (OR) |
DT_SINGLELINE:單行模式,忽略換行字元,垂直置中需配合 DT_VCENTERDT_CENTER:水平置中DT_VCENTER:垂直置中 (僅單行有效)DT_WORDBREAK:單字換行DT_CALCRECT:不實際繪製,僅計算所需矩形大小 (輸出於 lpRect)DT_NOCLIP:不裁剪,略過邊界檢查略微加速DT_EXPANDTABS:展開 Tab 字元DT_RIGHT:靠右對齊WM_PAINT 必須且只能呼叫一次 BeginPaint / EndPaintBeginPaint 內部會呼叫 ValidateRect,清除無效區旗標。若不處理 WM_PAINT 也不呼叫 DefWindowProc,會陷入無限 WM_PAINT 風暴。BeginPaint 依 PAINTSTRUCT.rcPaint 設定 DC 剪輯區,繪圖指令自動限制於需更新區域,提升效能。EndPaint 釋放 DC,下一個訊息必須重新 BeginPaint 或 GetDC。| 特性 | DrawText | TextOut |
|---|---|---|
| 換行處理 | 內建 (DT_WORDBREAK) | 無,需自行計算 |
| 對齊/置中 | 旗標控制 (DT_CENTER/VCENTER) | 需自行計算座標 |
| 裁剪 | 以 lpRect 為裁剪區 | 依 DC 剪輯區 |
| 回傳值 | 文字高度 (邏輯單位) | 成功非零 |
| 適用場景 | 動態版面、標籤、按鈕文字 | 固定座標、高效能繪圖迴路 |
GetDC → 繪圖 → ReleaseDC (即時回饋,不持久)InvalidateRect(hWnd, NULL, TRUE) → UpdateWindow(hWnd) 強制同步發送 WM_PAINT (持久化,建議做法)EndPaint → DC 洩漏、後續 BeginPaint 失敗DrawText 的 lpRect 傳遞錯誤位址 → 存取違規nCount 傳正數但字串含 0 → 截斷顯示DT_VCENTER 於多行文字 → 垂直置中失效