前一章示範的程式僅建立一個基本視窗,除了標題列顯示視窗名稱外,並未在用戶區呈現任何資訊。實際應用程式需在視窗用戶區內繪製文字與圖形。本章專注於文字列顯示,透過範例程式介紹數個 Windows 文字輸出函數、有效與無效矩形區概念,以及裝置內容與字型尺寸的基礎觀念。此外,還將說明幾個關鍵的 Windows 訊息,應用程式可利用它們進行初始化、終止處理與任務執行。
以下程式自用戶區左上角起始座標 (0,0) 開始顯示「Hello,Welcome to Windows」。
// 2-1.c 顯示文字資訊
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int PASCAL WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{
char szAppName[] = "DispText";
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
if (!hPrevInstance) {
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
return FALSE;
}
hwnd = CreateWindow(
szAppName,
"Display Text",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
char msg[] = "Hello, Welcome to Windows!";
PAINTSTRUCT ps;
HDC hDC;
switch (message) {
case WM_PAINT:
hDC = BeginPaint(hwnd, &ps);
TextOut(hDC, 0, 0, msg, sizeof(msg) - 1);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
HDC 定義於 windows.h,類似 HWND,用於識別一個裝置內容;所有繪圖函數皆需此控制代碼,繪圖動作將發生在該裝置內容所代表的物件上。
此結構包含重繪視窗用戶區所需的資訊,以下列出應用程式關心的欄位:
typedef struct tagPAINTSTRUCT {
HDC hdc; // 顯示裝置內容控制代碼
BOOL fErase; // 非零表示背景已重繪
RECT rcPaint; // 需重繪矩形區域的左上、右下座標
// ... 其他保留欄位供系統使用
} PAINTSTRUCT;
typedef struct tagRECT {
int left; // 左上角 X 座標
int top; // 左上角 Y 座標
int right; // 右下角 X 座標
int bottom; // 右下角 Y 座標
} RECT;
BeginPaint() 接收視窗控制代碼與 PAINTSTRUCT 指標,除填充結構欄位外,還會向系統申請一個顯示裝置內容供繪圖使用,並傳回其控制代碼。EndPaint() 必須與 BeginPaint() 成對出現於 WM_PAINT 訊息處理中,具備雙重功能:歸還借用的裝置內容(系統僅管理五個公用顯示裝置內容),以及從訊息佇列移除 WM_PAINT 訊息。
使用 BeginPaint() 取得的裝置內容,在用戶區繪製字串。參數說明如下:
| 參數 | 說明 |
|---|---|
| HDC hDC | 裝置內容控制代碼 |
| int x | 字串起始點邏輯 X 座標(相對用戶區左上角) |
| int y | 字串起始點邏輯 Y 座標 |
| LPSTR lpString | 欲繪製的字串指標 |
| int nCount | 欲繪製的字元數 |
函數原型:BOOL TextOut(HDC hDC, int x, int y, LPSTR lpString, int nCount);
當視窗用戶區部分需重繪時(如視窗被遮蔽後再顯示),Windows 會將 WM_PAINT 放入應用程式訊息佇列。應用程式必須在 WM_PAINT 處理中完成所有繪圖工作,並呼叫 BeginPaint()/EndPaint() 組合,否則訊息會持續重發導致程式無法正常運作。