前一章所介紹的程序只創建了一個的窗口,但是除了窗口的標題欄中顯示的窗口名之外,並未用它顯示其它信息。應用程序可以在窗口的用戶區內顯示文本和圖形信息。本章僅討論文本行的顯示。通過本章的程序實例,我們將介紹幾個用於文本輸出的Windows函數以及有效和無效矩形區的概念。同時介紹有關設備對象和字體尺寸的基本概念。這裡,我們還將介紹幾個重要的Windows消息。應用程序可以利用這些消息進行程序的初始化和終止處理,以及完成應用程序的任務等。
2.1、顯示信息
下面的程序從用戶區的左上角開始顯示“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);
}
我們首先介紹這個程序中使用的Windows數據類型,然後介紹和這幾個類型有的Windows函數,最後介紹消息WM_PAINT的含義。
HDC是在Windows.h中定義的一個數據類型,類似於HWND,它是用於標識一個設備對象的句柄;許多繪圖函數需要這個句柄,這些繪圖函數在這個句柄標識的對象上繪圖。
PAINTSTRUCT結構類型的變量所包含的信息可被用來重新繪制窗口的用戶區域,下面的定義中只給出應用程序關心的幾個域,其它未列出的域是供Windows系統使用的。
typedef struct tagPAINTSTRUCT {
HDC hdc; // 標識顯示設備對象的句柄
BOOL fErase; // 若為非零。說明用戶背景已被重畫過,否則未被重畫
RECT rcPaint; // 指定要求重畫(著色)的矩形區域的左上角和右下角坐標
//......
} PAINTSTRUCT;
其中,類型RECT的說明為:
typedef struct tagRECT {
int left; // 矩形左上角的X坐標值
int top; // 矩形左上角的Y坐標值
int right; // 矩形右上角的X坐標值
int bottom; // 矩形右上角的Y坐標值
} RECT;
函數BeginPaint()使用一個窗口句柄和一個指向PAINTSTRUCT類型的變量的指針為參數,它除了填充該指針所指向的變量的各域以外,同時向Windows借用一個顯示設備用於繪制用戶區。該函數返回這個設備對象的句柄,有了該句柄,應用程序就可以隨意繪制用戶區。函數EndPaint()與函數BeginPaint()所使用的參數一樣,它必須與函數BeginPaint()配對使用,並且必須同時都用在WM_PAINT消息內。函數EndPaint()有兩個作用。其一是歸還BeginPaint()所借用的顯示設備對象。Windows管理著五個公用的顯示設備對象,供應用程序在顯示設備上進行文本和圖形輸出所用。當一個窗口對象要繪制它的用戶區時,它必須首先向Windows借用一個顯示設備對象。由於公用的顯示設備對象有限,因此,窗口對象在繪制完它的用戶區之後,必須及時歸還它所借用的設備對象,以不影響其它對象使用公用顯示設備對象。一般的原則是:在從窗口函數中返回之前,應歸還所借用的顯示設備對象。EndPaint()函數的第二個作用是消除應用程序消息隊列中的WM_PAINT消息,關於WM_PAINT消息,我們放在後面單獨討論。
函數TextOut()使用BeginPaint()所借用的顯示設備對象,在用戶區中顯示一條消息。表2-1給出該函數的使用說明。
表2-1 TextOut 函數
用 途
該函數用當前選擇的字體繪制一字符串。其中參數x和y是串中第一個字符左上角的坐標。
原 型
BOOL TextOut(
HDC hDC
設備對象的句柄
int x,
串起始點的邏輯x坐標值(相對於用戶區左上角)
int y,
串起始點的邏輯y坐標值(相對於用戶區左上角)
LPSTR lpString,
所要繪制的字符串
int nCount
所要繪制的字符個數
);