windows程序设计第4章Text Output练习(831121)

Painting和重绘

通过Post WM_PAINT消息通知WndProc,客户区的无效区域要重绘。

WM_PAINT消息

在以下情况下WndProc收到WM_PAINT

1.被遮挡的区域通过窗口移动又重现

2..resize

3. ScrollWindow或ScrollDC的调用,以scroll客户区

4. 程序调用了InvalidateRect或InvalidateRgn

    有时,当客户区的某部分被暂时重写时,Windows也会试图保存之前的display以便restore。但不保证成功,所以有时Windows也会post WM_PAINT消息,有下列几种情况:

1.对话框,消息框在客户区的移动

2.menu拉动

3.tool tip显示

在下列情况,windows可以restore之前保存的display

1.mouse光标移动

2.icon拖曳入客户区

Valid和Invalid矩形区

     每次只需更新一个小的区域,即有display更改的矩形区域,以提高绘制效率。当客户区有invalid区时,Windows就会将WM_PAINT消息放置到消息队列。

     Wndows内部对每个窗口都维护了一个paint information structure,对于invalid区,包含了一个最小的能encompass invalid区的矩形,即”invalid矩形”。倘若在WndProc处理等待的WM_PAINT消息之前,又有新的invalid区产生,则Windows会计算对应的新的invalid矩形。

     WndProc可以通过调用InvalidateRect函数,来使自己的客户区的一个矩形变成invalid矩形,倘若此时队列中有WM_PAINT,则合并生成新的invalid矩形,否则,则放置一个WM_PAINT到队列。

     通过GetUpdateRect,我们可得到invalid矩形的坐标。而通过调用ValidateRect函数,可将任一矩形区设为valid,如果该函数将整个客户区都validate了,那么队列中的WM_PAINT将统统被移去。(有invalid矩形,才有重绘的必要)。

GDI介绍

    GDI(Graphics Device Interface)。

设备上下文(DC)

    DC是GDI内部维护的一个数据结构,它和一个特定的显示设备联系在一起。DC有一些graphics的属性值,诸如文字颜色,字体等等。用完DC后,要记得release。

获取DC句柄:法1

     在处理WM_PAINT时用此法,涉及两个函数,BeginPaint和EndPaint。使用前者填充PAINTSTRUCT结构ps,并返回DC句柄,后者负责释放DC。

必须成对出现。另外,有一个很重要的clipping区的概念,windows只能在clipping区绘制,调用BeginPaint,将会把Update区设为clipping区,如果有标志要erase背景,则BeginPaint会将Update区的背景擦掉。BeginPaint还会把invalid区设为有效,不用担心,原来的invalid区信息已保存在DC和ps中。

Paint信息结构

fErase:是否要erase背景,如果之前调用了BeginPaint,则不需要,如果调用InvalidateRect,并将该函数的最后一个参数设为0,则引发的WM_PAINT处理时,fErase为真,需要erase invalid矩形的背景。

rcPaint: 客户区中的invalid 矩形,此为应该绘制之所。

获取DC句柄:法2

在WM_PAINT处理之外,用GetDC得到DC,最后用ReleaseDC释放。此法返回的DC的clipping区是整个客户区,即可以随便画。而且它不会validate任何区域,若想validate整个客户区,需调用

ValidateRect(hwnd,NULL)

TextOut:细说

TextOut(hdc,x,y,psTest,iLength);

系统字体

不同的字符宽度不一。

字符大小

系统字体的height和平均width。有用的函数:GetTextMetrics

Text Metrics:细节

LONG tmHeight ;
LONG tmAscent ;
LONG tmDescent ;
LONG tmInternalLeading ;
LONG tmExternalLeading ;
LONG tmAveCharWidth ;
LONG tmMaxCharWidth ;

格式化文本

sprintf,wsprintf,不好用printf了

putting it all together

例子程序:利用GetSystemMetrics获取各种属性,并打印在客户区。

/*-----------------------------------------------
SYSMETS.H -- System metrics display structure
-----------------------------------------------*/
#define NUMLINES ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))
struct  
{
	int iIndex;
	TCHAR * szLabel;
	TCHAR * szDesc;
}
sysmetrics[] = {
	SM_CXSCREEN,			TEXT ("SM_CXSCREEN"),		TEXT ("Screen width in pixels"),
	SM_CYSCREEN,			TEXT ("SM_CYSCREEN"),		TEXT ("Screen height in pixels"),
	SM_CXVSCROLL,			TEXT ("SM_CXVSCROLL"),		TEXT ("Vertical scroll width"),
	SM_CYHSCROLL,			TEXT ("SM_CYHSCROLL"),		TEXT ("Horizontal scroll height"),
	SM_CYCAPTION,			TEXT ("SM_CYCAPTION"),		TEXT ("Caption bar height"),
	SM_CXBORDER,			TEXT ("SM_CXBORDER"),		TEXT ("Window border width"),
	SM_CYBORDER,			TEXT ("SM_CYBORDER"),		TEXT ("Window border height"),
	SM_CXFIXEDFRAME,		TEXT ("SM_CXFIXEDFRAME"),	TEXT ("Dialog window frame width"),
	SM_CYFIXEDFRAME,		TEXT ("SM_CYFIXEDFRAME"),	TEXT ("Dialog window frame height"),
	SM_CYVTHUMB,			TEXT ("SM_CYVTHUMB"),		TEXT ("Vertical scroll thumb height"),
	SM_CXHTHUMB,			TEXT ("SM_CXHTHUMB"),		TEXT ("Horizontal scroll thumb width"),
	SM_CXICON,				TEXT ("SM_CXICON"),			TEXT ("Icon width"),
	SM_CYICON,				TEXT ("SM_CYICON"),			TEXT ("Icon height"),
	SM_CXCURSOR,			TEXT ("SM_CXCURSOR"),		TEXT ("Cursor width"),
	SM_CYCURSOR,			TEXT ("SM_CYCURSOR"),		TEXT ("Cursor height"),
	SM_CYMENU,				TEXT ("SM_CYMENU"),			TEXT ("Menu bar height"),
	SM_CXFULLSCREEN,		TEXT ("SM_CXFULLSCREEN"),	TEXT ("Full screen client area width"),
	SM_CYFULLSCREEN,		TEXT ("SM_CYFULLSCREEN"),	TEXT ("Full screen client area height"),
	SM_CYKANJIWINDOW,		TEXT ("SM_CYKANJIWINDOW"),	TEXT ("Kanji window height"),
	SM_MOUSEPRESENT,		TEXT ("SM_MOUSEPRESENT"),	TEXT ("Mouse present flag"),
	SM_CYVSCROLL,			TEXT ("SM_CYVSCROLL"),		TEXT ("Vertical scroll arrow height"),
	SM_CXHSCROLL,			TEXT ("SM_CXHSCROLL"),		TEXT ("Horizontal scroll arrow width"),
	SM_DEBUG,				TEXT ("SM_DEBUG"),			TEXT ("Debug version flag"),
	SM_SWAPBUTTON,			TEXT ("SM_SWAPBUTTON"),		TEXT ("Mouse buttons swapped flag"),
	SM_CXMIN,				TEXT ("SM_CXMIN"),			TEXT ("Minimum window width"),
	SM_CYMIN,				TEXT ("SM_CYMIN"),			TEXT ("Minimum window height"),
	SM_CXSIZE,				TEXT ("SM_CXSIZE"),			TEXT ("Min/Max/Close button width"),
	SM_CYSIZE,				TEXT ("SM_CYSIZE"),			TEXT ("Min/Max/Close button height"),
	SM_CXSIZEFRAME,			TEXT ("SM_CXSIZEFRAME"),	TEXT ("Window sizing frame width"),
	SM_CYSIZEFRAME,			TEXT ("SM_CYSIZEFRAME"),	TEXT ("Window sizing frame height"),
	SM_CXMINTRACK,			TEXT ("SM_CXMINTRACK"),		TEXT ("Minimum window tracking width"),
	SM_CYMINTRACK,			TEXT ("SM_CYMINTRACK"),		TEXT ("Minimum window tracking height"),
	SM_CXDOUBLECLK,			TEXT ("SM_CXDOUBLECLK"),	TEXT ("Double click x tolerance"),
	SM_CYDOUBLECLK,			TEXT ("SM_CYDOUBLECLK"),	TEXT ("Double click y tolerance"),
	SM_CXICONSPACING,		TEXT ("SM_CXICONSPACING"),	TEXT ("Horizontal icon spacing"),
	SM_CYICONSPACING,		TEXT ("SM_CYICONSPACING"),	TEXT ("Vertical icon spacing"),
	SM_MENUDROPALIGNMENT,	TEXT ("SM_MENUDROPALIGNMENT"),TEXT ("Left or right menu drop"),
	SM_PENWINDOWS,			TEXT ("SM_PENWINDOWS"),		TEXT ("Pen extensions installed"),
	SM_DBCSENABLED,			TEXT ("SM_DBCSENABLED"),	TEXT ("Double-Byte Char Set enabled"),
	SM_CMOUSEBUTTONS,		TEXT ("SM_CMOUSEBUTTONS"),	TEXT ("Number of mouse buttons"),
	SM_SECURE,				TEXT ("SM_SECURE"),			TEXT ("Security present flag"),
	SM_CXEDGE,				TEXT ("SM_CXEDGE"),			TEXT ("3-D border width"),
	SM_CYEDGE,				TEXT ("SM_CYEDGE"),			TEXT ("3-D border height"),
	SM_CXMINSPACING,		TEXT ("SM_CXMINSPACING"),	TEXT ("Minimized window spacing width"),
	SM_CYMINSPACING,		TEXT ("SM_CYMINSPACING"),	TEXT ("Minimized window spacing height"),
	SM_CXSMICON,			TEXT ("SM_CXSMICON"),		TEXT ("Small icon width"),
	SM_CYSMICON,			TEXT ("SM_CYSMICON"),		TEXT ("Small icon height"),
	SM_CYSMCAPTION,			TEXT ("SM_CYSMCAPTION"),	TEXT ("Small caption height"),
	SM_CXSMSIZE,			TEXT ("SM_CXSMSIZE"),		TEXT ("Small caption button width"),
	SM_CYSMSIZE,			TEXT ("SM_CYSMSIZE"),		TEXT ("Small caption button height"),
	SM_CXMENUSIZE,			TEXT ("SM_CXMENUSIZE"),		TEXT ("Menu bar button width"),
	SM_CYMENUSIZE,			TEXT ("SM_CYMENUSIZE"),		TEXT ("Menu bar button height"),
	SM_ARRANGE,				TEXT ("SM_ARRANGE"),		TEXT ("How minimized windows arranged"),
	SM_CXMINIMIZED,			TEXT ("SM_CXMINIMIZED"),	TEXT ("Minimized window width"),
	SM_CYMINIMIZED,			TEXT ("SM_CYMINIMIZED"),	TEXT ("Minimized window height"),
	SM_CXMAXTRACK,			TEXT ("SM_CXMAXTRACK"),		TEXT ("Maximum draggable width"),
	SM_CYMAXTRACK,			TEXT ("SM_CYMAXTRACK"),		TEXT ("Maximum draggable height"),
	SM_CXMAXIMIZED,			TEXT ("SM_CXMAXIMIZED"),	TEXT ("Width of maximized window"),
	SM_CYMAXIMIZED,			TEXT ("SM_CYMAXIMIZED"),	TEXT ("Height of maximized window"),
	SM_NETWORK,				TEXT ("SM_NETWORK"),		TEXT ("Network present flag"),
	SM_CLEANBOOT,			TEXT ("SM_CLEANBOOT"),		TEXT ("How system was booted"),
	SM_CXDRAG,				TEXT ("SM_CXDRAG"),			TEXT ("Avoid drag x tolerance"),
	SM_CYDRAG,				TEXT ("SM_CYDRAG"),			TEXT ("Avoid drag y tolerance"),
	SM_SHOWSOUNDS,			TEXT ("SM_SHOWSOUNDS"),		TEXT ("Present sounds visually"),
	SM_CXMENUCHECK,			TEXT ("SM_CXMENUCHECK"),	TEXT ("Menu check-mark width"),
	SM_CYMENUCHECK,			TEXT ("SM_CYMENUCHECK"),	TEXT ("Menu check-mark height"),
	SM_SLOWMACHINE,			TEXT ("SM_SLOWMACHINE"),	TEXT ("Slow processor flag"),
	SM_MIDEASTENABLED,		TEXT ("SM_MIDEASTENABLED"),	TEXT ("Hebrew and Arabic enabled flag"),
	SM_MOUSEWHEELPRESENT,	TEXT ("SM_MOUSEWHEELPRESENT"),TEXT ("Mouse wheel present flag"),
	SM_XVIRTUALSCREEN,		TEXT ("SM_XVIRTUALSCREEN"),	TEXT ("Virtual screen x origin"),
	SM_YVIRTUALSCREEN,		TEXT ("SM_YVIRTUALSCREEN"),	TEXT ("Virtual screen y origin"),
	SM_CXVIRTUALSCREEN,		TEXT ("SM_CXVIRTUALSCREEN"),TEXT ("Virtual screen width"),
	SM_CYVIRTUALSCREEN,		TEXT ("SM_CYVIRTUALSCREEN"),TEXT ("Virtual screen height"),
	SM_CMONITORS,			TEXT ("SM_CMONITORS"),		TEXT ("Number of monitors"),
	SM_SAMEDISPLAYFORMAT,	TEXT ("SM_SAMEDISPLAYFORMAT"),TEXT ("Same color format flag")
};
//SYSMETS1.cpp
#include <Windows.h>
#include "SYSMETS.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("SysMets1");
	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_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL,TEXT("fail!"),szAppName,MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName,
		TEXT("Get System Metrics No. 1"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL						
		);

	ShowWindow(hwnd,iCmdShow);

	UpdateWindow(hwnd);

	while (GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;

	//	return 0;
}

//WParam是int,LPARAM是long
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	static int cxChar,cxCaps,cyChar;
	HDC hdc;
	PAINTSTRUCT ps;
	TCHAR szBuffer[10];
	TEXTMETRIC tm;

	switch(message)
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);
		GetTextMetrics(hdc,&tm);
		cxChar = tm.tmAveCharWidth;
		cxCaps = (tm.tmPitchAndFamily & 1 ? 3:2) * cxChar / 2;
		cyChar = tm.tmHeight + tm.tmExternalLeading;
		ReleaseDC(hwnd,hdc);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hwnd,&ps);
		for(int i =0;i < NUMLINES;i++)
		{
			TextOut(hdc,0,cyChar * i,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));
			TextOut(hdc,22 * cxCaps,cyChar * i,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));
			SetTextAlign(hdc,TA_RIGHT | TA_TOP);

			int len = wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].iIndex));
			TextOut(hdc, 22 * cxCaps + 40 * cxChar, cyChar * i,szBuffer,len);
			SetTextAlign(hdc,TA_LEFT | TA_TOP);
		}
		EndPaint(hwnd,&ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd,message,wParam,lParam);
}

SYSMETS2.cpp

#include <Windows.h>
#include "SYSMETS.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("SysMets2");
	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_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL,TEXT("fail!"),szAppName,MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName,
		TEXT("Get System Metrics No. 2"),
		WS_OVERLAPPEDWINDOW | WS_VSCROLL,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL						
		);

	ShowWindow(hwnd,iCmdShow);

	UpdateWindow(hwnd);

	while (GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;

	//	return 0;
}

//WParam是int,LPARAM是long
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	static int cxChar,cxCaps,cyChar,cyClient,iVscrollPos;
	HDC hdc;
	PAINTSTRUCT ps;
	TCHAR szBuffer[10];
	TEXTMETRIC tm;

	switch(message)
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);
		GetTextMetrics(hdc,&tm);
		cxChar = tm.tmAveCharWidth;
		cxCaps = (tm.tmPitchAndFamily & 1 ? 3:2) * cxChar / 2;
		cyChar = tm.tmHeight + tm.tmExternalLeading;
		ReleaseDC(hwnd,hdc);
		SetScrollRange(hwnd,SB_VERT,0,NUMLINES - 1,FALSE);
		SetScrollPos(hwnd,SB_VERT,iVscrollPos,TRUE);
		return 0;
	case WM_SIZE:
		cyClient = HIWORD(lParam);
		return 0;
	case WM_VSCROLL:
		switch(LOWORD(wParam))
		{
		case SB_LINEUP:
			iVscrollPos --;
			break;
		case SB_LINEDOWN:
			iVscrollPos ++;
			break;
		case SB_PAGEUP:
			iVscrollPos -= cyClient / cyChar;
			break;
		case SB_PAGEDOWN:
			iVscrollPos += cyClient / cyChar;
			break;
		case SB_THUMBPOSITION:
			iVscrollPos = HIWORD(wParam);
			break;
		default:
			break;
		}
		iVscrollPos = max(0,min(iVscrollPos,NUMLINES - 1));
		if (iVscrollPos != GetScrollPos(hwnd,SB_VERT))
		{
			SetScrollPos(hwnd,SB_VERT,iVscrollPos,TRUE);
			InvalidateRect(hwnd,NULL,TRUE);
			UpdateWindow(hwnd);//马上绘制
		}
	case WM_PAINT:
		hdc = BeginPaint(hwnd,&ps);
		for(int i =0;i < NUMLINES;i++)
		{
			int y = cyChar * (i - iVscrollPos);
			TextOut(hdc,0,y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));
			TextOut(hdc,22 * cxCaps,y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));
			SetTextAlign(hdc,TA_RIGHT | TA_TOP);

			int len = wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].iIndex));
			TextOut(hdc, 22 * cxCaps + 40 * cxChar, y,szBuffer,len);
			SetTextAlign(hdc,TA_LEFT | TA_TOP);
		}
		EndPaint(hwnd,&ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd,message,wParam,lParam);
}
原文地址:https://www.cnblogs.com/speedmancs/p/1731446.html