Win32程序文本输出 --设备无关的编程基础、滚动条

注:以下内容为学习笔记,多数是从书本、资料中得来,只为加深印象,及日后参考。然而本人表达能力较差,写的不好。因非翻译、非转载,只好选原创,但多数乃摘抄,实为惭愧。但若能帮助一二访客,幸甚!


以下内容摘自Charles Petzold所著《Windows程序设计》

1.WM_PAINT

Windows通过发送WM_PAINT消息来通知窗口过程其可获区需要重绘。

以下任何一个事件发送时,窗口过程都会收到一条WM_PAINT消息:

1)用户移动一个窗口,导致原来被遮盖的部分窗口暴露出来。

2)用户调整窗口大小(当窗口类型设定为CS_HREDRAW和CS_VREDRAW时)

3)程序调用ScrollWindow或ScrollDC函数滚动客户区

4)程序调用InvalidateRect或InvalidateRgn函数显式生成WM_PAINT消息


在某些情况下,当客户区的一部分被临时覆盖时,Windows会试图保存被覆盖的这部分,以便将来恢复。这并不是每次都能成功。以下情形,Windows有时会发送一条WM_PAINT消息:

1)Windows关闭一个覆盖了部分窗口的对话框或消息框

2)下拉菜单被拉下然后收回

3)显式提示信息


在少数情况下,Windows总是会保存被覆盖的部分的显式内容,然后恢复:

1)鼠标指针在客户区移动

2)在客户区内拖到图标


2.有效矩形和无效矩形

尽管窗口过程必须能够在收到WM_PAINT消息时更新整个客户区,但通常它只需要更新其中的一部分,最常见的是更新其中一个矩形区域。

需要重新绘制的部分称为“无效区域”或“更新区域”。在客户区中有一个无效区域将导致Windows在应用程序的消息队列中放置一条WM_PAINT消息。只有当程序客户区的一部分失效时,窗口过程才会接收到WM_PAINT消息。

Windows内部为每个窗口保存了一个“绘制信息结构”这个结构保存着一个可以覆盖该无效区域的最小矩形的坐标和一些其他的信息。这个最小矩形被称为“无效矩形”。

窗口过程可以通过调用InvalidRect强制使自己的客户区中一个矩形失效。

窗口过程在处理WM_PAINT时,调用BeginPaint后,整个客户区会变成有效的。也可以调用ValidateRect使客户区中任意的矩形变得有效。


3.设备环境

绘制一个客户区需要调用Windows的图形设备接口(GDI)函数。

设备环境句柄是程序窗口使用GDI函数的通行证。

设备环境(也被简称为DC)实际上是GDI内部维护的一个数据结构,与特定的显式设备(如显示器或打印机)相关联。


获取设备环境句柄:

1)方法1

HDC hdc; 
hdc = BeginPaint(hwnd, &ps);
// ...
EndPaint(hwnd, &ps);

2)方法2

HDC hdc;
hdc = GetDC(hwnd);
//....
ReleaseDC(hwnd, hdc);

从GetDC返回的设备环境句柄中的裁剪矩形是整个客户区。这意味着你可以在客户区的任意部分绘制,而不仅仅是在无效矩形里。GetDC与BeginPaint不同,它不会将无效区域有效化。如果需要将整个客户区有效化,可:

ValidateRect(hwnd, NULL);


与GetDC类似,GetWindowDC返回的是整个窗口的设备环境句柄,可以在窗口的标题栏输出。


4.TextOut

它是显式文本的最重要的GDI函数。

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

hdc设备环境句柄,它的属性决定了文本显式的特性。

在类似于TextOut的GDI绘图函数的文档中,传给函数的坐标值通常被称为”逻辑坐标“。

设备环境同时定义了一个裁剪区域。GetDC得到的设备环境句柄中,该裁剪区域就是整个客户区;BeginPaint得到的则是无效区域。调用TextOut时,Windows将不会显示字符串落在裁剪区域外的部分。


5.字符尺寸大小

可调用GetSystemMetrics获取用户界面的尺寸,可调用GetTextMetrics获取字体尺寸。

Windows提供了与设备无关的图形界面,但应注意:不要在Windows应用程序中猜测文本的尺寸,不要使用固定的值,应用GetTextMetrics获取这些信息。


6.示例代码(显示Windows中各种图形项的尺寸信息)

/*-----------------------------------------------
   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 -- System Metrics Display Program ver1
 *----------------------------------------------------------------------------------*/

#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("HelloWin32");
	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("This program requires windows NT!"), szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName,					// window class name
						TEXT("System Metrics"),		// window caption
						WS_OVERLAPPEDWINDOW,		// window style
						CW_USEDEFAULT,				// initial x position
						CW_USEDEFAULT,				// initial y position
						CW_USEDEFAULT,				// initial x size
						CW_USEDEFAULT,				// initial y size
						NULL,						// parent window handle
						NULL,						// window menu handle
						hInstance,					// program instance handle
						NULL);						// creation parameters

	ShowWindow(hwnd, iCmdShow);
	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)
{
	// cxChar平均字符宽度,cyChar字符的总高度(包括外部间距),cxCaps大写字符的平均宽度
	// 等宽字体中,cxCaps等于cxChar,变宽字体中,cxCaps等于cxChar的1.5倍
	static int	cxChar, cxCaps, cyChar;	
	HDC			hdc;
	int			i;
	PAINTSTRUCT	ps;
	TCHAR		szBuffer[10];
	TEXTMETRIC	tm;						// 

	switch (message)
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);
		
		GetTextMetrics(hdc, &tm);		// 获取系统默认字体的尺寸
		cxChar = tm.tmAveCharWidth;
		// tmPitchAndFamily为1表示变宽字体,为0表示等宽字体
		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 (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);

			// 第一栏里显示的字符串最长有20个字符
			TextOut(hdc, 22*cxCaps + 40*cxChar, cyChar*i, szBuffer, wsprintf(szBuffer, TEXT("%5d"), 
				GetSystemMetrics(sysmetrics[i].iIndex)));

			// 将对齐方式设回正常方式
			SetTextAlign(hdc, TA_LEFT | TA_TOP);
		}

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

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




7.滚动条

解决上面显示不完全的问题。

每个滚动条都有相应的“范围”和“位置”。默认状态范围为0~100.可用

SetScrollRange(hwnd, iBar, iMin, iMax, bRedraw);
iBar为SB_VERT或SB_HORZ。

若需要Windows根据新的范围来重绘滚动条时,bRedraw设为TRUE。

通过下面函数可设置滑块在滚动条范围中的位置:

SetScrollPos(hwnd, iBar, iPos, bRedraw);
在程序中使用滚动条时,程序需要和Windows共同负责维护滚动条以及滑块在滚动条中的位置。

Windows负责:

1)处理滚动条中的所有鼠标消息

2)当用户单击滚动条时,提供一种反向显示的闪烁

3)当用户拖动滑块时,在滚动条内移动滑块

4)向拥有滚动条的窗口 的窗口过程发送滚动条消息


程序负责:

1)初始化滚动条的范围和位置

2)处理传送给窗口过程的滚动条消息

3)更新滑块的位置

4)根据滚动条的变化更新客户区的内容


滚动条消息:

当用户单击滚动条或拖动滑块时,Windows向窗口过程发送WM_VSCROLL消息(垂直滚动)或WM_HSCROLL(水平滚动)。在滚动条上的任何鼠标动作会至少产生两条消息:一条在鼠标键按下时,另一条在鼠标键松开时。

加入滚动条的SYSMETS代码:

/*-----------------------------------------------------------------------------------
	SysMets1.cpp -- System Metrics Display Program ver1
 *----------------------------------------------------------------------------------*/

#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("HelloWin32");
	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("This program requires windows NT!"), szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName,							// window class name
						TEXT("System Metrics"),				// window caption
						WS_OVERLAPPEDWINDOW | WS_VSCROLL,	// window style
						CW_USEDEFAULT,						// initial x position
						CW_USEDEFAULT,						// initial y position
						CW_USEDEFAULT,						// initial x size
						CW_USEDEFAULT,						// initial y size
						NULL,								// parent window handle
						NULL,								// window menu handle
						hInstance,							// program instance handle
						NULL);								// creation parameters

	ShowWindow(hwnd, iCmdShow);
	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)
{
	// cxChar平均字符宽度,cyChar字符的总高度(包括外部间距),cxCaps大写字符的平均宽度
	// 等宽字体中,cxCaps等于cxChar,变宽字体中,cxCaps等于cxChar的1.5倍
	static int	cxChar, cxCaps, cyChar, cyClient, iVscrollPos;	
	HDC			hdc;
	int			i, y;
	PAINTSTRUCT	ps;
	TCHAR		szBuffer[10];
	TEXTMETRIC	tm;	

	switch (message)
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);
		
		GetTextMetrics(hdc, &tm);		// 获取系统默认字体的尺寸
		cxChar = tm.tmAveCharWidth;
		// tmPitchAndFamily为1表示变宽字体,为0表示等宽字体
		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 -= 1;
			break;

		case SB_LINEDOWN:
			iVscrollPos += 1;
			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);
		}
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		for (i = 0; i < NUMLINES; i++)
		{
			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);

			TextOut(hdc, 22*cxCaps + 40*cxChar, y, szBuffer, wsprintf(szBuffer, TEXT("%5d"), 
				GetSystemMetrics(sysmetrics[i].iIndex)));

			// 将对齐方式设回正常方式
			SetTextAlign(hdc, TA_LEFT | TA_TOP);
		}

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

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



效果更好的滚动,解决前面程序效率低的问题

使用函数SetScrollInfo和GetScrollInfo:

SetScrollInfo(hwnd, iBar, &si, bRedraw);

GetScrollInfo(hwnd, iBar, &si);


代码:

/*-----------------------------------------------------------------------------------
	SysMets1.cpp -- System Metrics Display Program ver1
 *----------------------------------------------------------------------------------*/

#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("HelloWin32");
	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("This program requires windows NT!"), szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName,										// window class name
						TEXT("System Metrics"),							// window caption
						WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,	// window style
						CW_USEDEFAULT,									// initial x position
						CW_USEDEFAULT,									// initial y position
						CW_USEDEFAULT,									// initial x size
						CW_USEDEFAULT,									// initial y size
						NULL,											// parent window handle
						NULL,											// window menu handle
						hInstance,										// program instance handle
						NULL);											// creation parameters

	ShowWindow(hwnd, iCmdShow);
	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)
{
	// cxChar平均字符宽度,cyChar字符的总高度(包括外部间距),cxCaps大写字符的平均宽度
	// 等宽字体中,cxCaps等于cxChar,变宽字体中,cxCaps等于cxChar的1.5倍
	static int	cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth, iVscrollPos;	
	HDC			hdc;
	int			i, x, y, iVertPos, iHorzPos, iPaintBeg, iPaintEnd;
	PAINTSTRUCT	ps;
	SCROLLINFO	si;
	TCHAR		szBuffer[10];
	TEXTMETRIC	tm;	

	switch (message)
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);
		
		GetTextMetrics(hdc, &tm);		// 获取系统默认字体的尺寸
		cxChar = tm.tmAveCharWidth;
		// tmPitchAndFamily为1表示变宽字体,为0表示等宽字体
		cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
		cyChar = tm.tmHeight + tm.tmExternalLeading;

		ReleaseDC(hwnd, hdc);

		iMaxWidth = 40*cxChar + 22*cxCaps;
		return 0;

	case WM_SIZE:
		cxClient = LOWORD(lParam);
		cyClient = HIWORD(lParam);
		
		si.cbSize	= sizeof(si);
		si.fMask	= SIF_RANGE | SIF_PAGE;

		si.nMin		= 0;
		si.nMax		= NUMLINES-1;
		si.nPage	= cyClient / cyChar;
		SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

		si.cbSize	= sizeof(si);
		si.fMask	= SIF_RANGE | SIF_PAGE;

		si.nMin		= 0;
		si.nMax		= 2 + iMaxWidth/cxChar;
		si.nPage	= cxClient / cxChar;
		SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

		return 0;
		
	case WM_VSCROLL:
		si.cbSize	= sizeof(si);
		si.fMask	= SIF_ALL;

		GetScrollInfo(hwnd, SB_VERT, &si);
		iVertPos = si.nPos;

		switch (LOWORD(wParam))
		{
		case SB_TOP:
			si.nPos = si.nMin;
			break;

		case SB_BOTTOM:
			si.nPos = si.nMax;
			break;

		case SB_LINEUP:
			si.nPos -= 1;
			break;

		case SB_LINEDOWN:
			si.nPos += 1;
			break;

		case SB_PAGEUP:
			si.nPos -= si.nPage;
			break;

		case SB_PAGEDOWN:
			si.nPos += si.nPage;
			break;

		case SB_THUMBTRACK:
			si.nPos = si.nTrackPos;
			break;

		default:
			break;
		}

		si.fMask = SIF_POS;
		SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
		GetScrollInfo(hwnd, SB_VERT, &si);

		if (si.nPos != iVertPos)
		{
			ScrollWindow(hwnd, 0, cyChar*(iVertPos-si.nPos), NULL, NULL);
			UpdateWindow(hwnd);
		}
		return 0;

	case WM_HSCROLL:
		si.cbSize	= sizeof(si);
		si.fMask	= SIF_ALL;

		GetScrollInfo(hwnd, SB_HORZ, &si);
		iHorzPos = si.nPos;

		switch (LOWORD(wParam))
		{
		case SB_LINELEFT:
			si.nPos -= 1;
			break;

		case SB_LINERIGHT:
			si.nPos += 1;
			break;

		case SB_PAGELEFT:
			si.nPos -= si.nPage;
			break;

		case SB_PAGERIGHT:
			si.nPos += si.nPage;
			break;

		case SB_THUMBPOSITION:
			si.nPos = si.nTrackPos;
			break;

		default:
			break;
		}

		si.fMask = SIF_POS;
		SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
		GetScrollInfo(hwnd, SB_HORZ, &si);

		if (si.nPos != iHorzPos)
		{
			ScrollWindow(hwnd, cxChar*(iHorzPos-si.nPos), 0, NULL, NULL);
			UpdateWindow(hwnd);
		}
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		si.cbSize = sizeof(si);
		si.fMask = SIF_POS;
		
		GetScrollInfo(hwnd, SB_VERT, &si);
		iVertPos = si.nPos;

		GetScrollInfo(hwnd, SB_HORZ, &si);
		iHorzPos = si.nPos;

		iPaintBeg = max(0, iVertPos + ps.rcPaint.top/cyChar);
		iPaintEnd = min(NUMLINES-1, iVertPos + ps.rcPaint.bottom/cyChar);

		for (i = iPaintBeg; i <= iPaintEnd; i++)
		{
			x = cxChar * (1-iHorzPos);
			y = cyChar * (i-iVertPos);

			TextOut(hdc, x, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));

			TextOut(hdc, x + 22*cxCaps, y, sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));

			SetTextAlign(hdc, TA_RIGHT | TA_TOP);

			TextOut(hdc, x + 22*cxCaps + 40*cxChar, y, szBuffer, wsprintf(szBuffer, TEXT("%5d"), 
				GetSystemMetrics(sysmetrics[i].iIndex)));

			// 将对齐方式设回正常方式
			SetTextAlign(hdc, TA_LEFT | TA_TOP);
		}

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值