解题:
一、在用户区的某个坐标位置打印一行字符串
二、在用户区的中心位置打印一行字符串,位置始终不变
三、读取一个纯文本文件(FILE)内容到用户区中,(保持格式)
BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint);:获取HDC句柄,其中LPPAINTSTRUCT lpPaint,是一个指向PAINTSTRUCT的指针。
PAINTSTRUCT结构:特别之处在于,它记录需要重绘的矩形区域(比如被遮盖的无效区域),在接收WM_PAINT消息时,重绘这个区域。
关于重绘的几个问题,第一,不是所有区域都需要重绘(比如标题栏,工具条等等),只是无效区域需要重绘。windows又如何知道重绘区域的大小呢?在BeginPaint()函数中,将无效区域的大小写在PAINTSTRUCT结构中。
typedef struct tagPAINTSTRUCT { HDC hdc;/*标识显示设备对象的句柄*/ BOOL fErase;/*若为非零,说明用户背景已被重画,否则未被重画*/ RECT rcPaint;/*指定要求重画的矩形区域的左上角和右下角的坐标*/ BOOL fRestore; BOOL fIncUpdate; BYTE rgbReserved[32]; } PAINTSTRUCT, *PPAINTSTRUCT, *NPPAINTSTRUCT, *LPPAINTSTRUCT;
InvalidateRect()函数强制某个区域为无效区域。
InvalidateRect( HWND hWnd , CONST RECT *lpRect, /*无效区域坐标,如果为NULL,则整个用户区无效*/ BOOL bErase);/*是否擦除RECT所标示的区域内容*/
TextOut函数(文本输出):
BOOL TextOut ( HDC hdc; int x;/*串起始点的逻辑x坐标值*/ int y;/*串起始点的逻辑y坐标值*/ LPSTR lpString;/*指向字符串的指针*/ int nCount)/*绘制的字符个数*/
EndPaint(),两个作用:第一,返回借用的设备对象,第二,清除消息队列中的WM_PAINT消息。
具体的在用户区中显示文本的几种特别方法:
(1)要求文本始终居于用户区的正中间
//DrawText()函数用于格式化显示文本
这种方法的一个缺点在于,只要产生WM_PAINT消息时,就需要计算用户区域的大小,但实际情况下用户区域的大小很少去动,这种计算显的多余。
改进:在windows窗口的大小发生改变时,会发送WM_SIZE(一个知识点)消息,直接进入消息队列,其中,在消息的附加参数lParam中,低位表示最后的宽度,高位表示最后的高度,通过对lParam的分离,得到窗口最后的宽高。然后借用这个矩形坐标显示文本,也能达成目的。
case WM_SIZE: rect.right=LOWORD(lParam);/*分离宽度*/ rect.bottom=HIWORD(lParam);/*分离高度*/ break;
关于字体
字体的信息图:
BOOL GetTextMetrics(HDC hdc,LPTEXTMETRICS lpMetric);
/*得到设备对象使用字体的尺寸,并存入到TEXTMETRICS的变量中*/
/*--------------完整代码-----------------*/

//-------------------程序包含的内容如下:---------------------// //创建窗口时产生的第一条消息:WM_CREATE; //获取设备DC:BeginPaint(),EndPaint(),InvalidateRect().. //获取用户区的区域大小..GetClientRect() //自定义用户消息,SendMessage()的使用; //窗口改变时,产生的WM_SIZE消息 //如何检测鼠标双键按下的消息 //文本输出:TextOut(),格式化输出:DrawText() //3个小例子 //一、在用户区的某个坐标位置打印字符串 //二、始终在用户区区域的中心位置显示某个字符串 //三、读取一个文本文件,并在用户区显示 //---------------------------------------------------------------// #include "stdio.h" #include <windows.h> #define WM_MYMSG WM_USER+100 /*自定义消息的ID*/ LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;/*回调函数声明*/ int _stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) { static char szAppName[] = TEXT ("HelloWin") ; HWND hwnd ; //窗口句柄 MSG msg ; //消息结构 WNDCLASS wndclass ; //窗口类结构 wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_WARNING) ;//加载图标 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; //加载鼠标指针 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;//获取一个图形对象 wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; RegisterClass (&wndclass);//注册窗口(类) hwnd = CreateWindow (szAppName,//创建窗口 TEXT ("一个简单的Win32程序"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; /*在此处发出第一个消息WM_CREATE*/ ShowWindow (hwnd, iCmdShow) ; //显示窗口 UpdateWindow (hwnd) ; //窗口刷新 /*在此处发出第一个WM_PAINT消息*/ while (GetMessage (&msg, NULL, 0, 0)) //从消息队列中获取消息 { TranslateMessage (&msg) ; //转换某些键盘消息 DispatchMessage (&msg) ; //将消息发送给窗口过程 } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; const static char msg[]="hello,welcome to Windows!"; static RECT rect;/*静态矩形区域*/ PAINTSTRUCT ps; static int xChar,yChar; char szBuffer[256]; int line=0; TEXTMETRIC tm;//字体尺寸信息结构体 FILE *fp; switch(message) { case WM_CREATE://窗口创建的第一条消息:WM_CREATE /*hdc=GetDC(hwnd); //GetDC()只能用于非WM_PAINT消息,原因是即使释放DC之后,并不能清除WM_PAINT消息 GetTextMetrics(hdc,&tm);//获取字体的相关信息,并存放在变量tm中; xChar=tm.tmAveCharWidth;//字符的平均宽度 yChar=tm.tmHeight+tm.tmExternalLeading;/*高度=字符高度+默认行距,此高度作为打印行的间距 ReleaseDC(hwnd,hdc);*/ break; case WM_SIZE:/*窗口大小接收到的消息*/ rect.right=LOWORD(lParam);//分离宽度 rect.bottom=HIWORD(lParam);//分离高度 break; case WM_PAINT: //InvalidateRect(hwnd,NULL,0);/*强制整个用户区为无效区域*/ hdc=BeginPaint(hwnd,&ps); //TextOut(hdc,10,20,msg,strlen(msg)); GetClientRect(hwnd,&rect);//获取用户区的区域坐标,放在矩形变量rect中; DrawText(hdc,msg,-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER); /*if((fp=fopen("disp.txt","r"))==NULL) //需要在当前目录下建立一个disp.c文件 { TextOut(hdc,0,0,"打开错误!",8);//一个汉字两字节// break; } else { while(!feof(fp)) { int i=0; char ch; while((ch=fgetc(fp))!=' ' && ch!=EOF) szBuffer[i++]=char(ch); TextOut(hdc,xChar,line*yChar,szBuffer,i);//打印文件,每一行控制间距// line++; } fclose(fp); }*/ EndPaint(hwnd,&ps);//EndPaint()可以清除消息队列中的WM_PAINT消息 break; case WM_MYMSG:/*自定义消息*/ MessageBox(NULL,"用户自定义消息","自定义",MB_OK); break; case WM_LBUTTONDOWN:/*鼠标左键按下后发送自定义消息WM_MYMSG*/ SendMessage(hwnd,WM_MYMSG,wParam,lParam); break; //case WM_LBUTTONDOWN:/*双键检测*/ //if(wParam & MK_RBUTTON) //SendMessage(hwnd,WM_MYMSG,wParam,lParam); //break; case WM_DESTROY: PostQuitMessage (0) ; //在消息队列中插入一条“退出”消息 break; } return DefWindowProc (hwnd, message, wParam, lParam);//执行默认的消息处理 }
GetDC()和BeginPaint()的区别
GetDC()通过ReleaseDC()释放后,但不能清除WM_PAINT消息,所以适合在非WM_PAINT消息中创建,EndPaint()可以清除WM_PAINT消息。