第四章 文本输出

示例代码(Windows 1.0)

sysmets.h

#pragma once

#include <WinUser.h>
#include <winnt.h>

#define NUMLINES ((int) (sizeof(sysmetrics) / sizeof(sysmetrics[0])))

struct
{
	int iIndex;
	const TCHAR* szLabel;
	const TCHAR* szDesc;
}
sysmetrics[] =
{
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
	SM_CXSCREEN, TEXT("SM_CXSCREEN"), TEXT("SM_CXSCREEN"),
	SM_CYSCREEN, TEXT("SM_CYSCREEN"), TEXT("SM_CYSCREEN"),
	SM_CXVSCROLL, TEXT("SM_CXVSCROLL"), TEXT("SM_CXVSCROLL"),
};

main.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("HelloWin");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;

	// class style: 水平尺寸或垂直尺寸被改变都会重新绘画
	wndclass.style = CS_HREDRAW | CS_VREDRAW;

	// 窗口过程,用于处理该窗口的消息
	wndclass.lpfnWndProc = WndProc;
	// 预留额外空间大小
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	// 窗口设定图标,IDI:ID for an icon
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	// 鼠标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	// hbr:handle to a brush,窗口客户区的北京颜色
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("This program NT"), szAppName, MB_ICONERROR);

		return 0;
	}

	// WS_OVERLAPPEDWINDOW:层叠窗口
	// WS_VSCROLL | WS_HSCROLL : 垂直滚动条,水平滚动条,此时客户区并不包含滚动条所占用的空间;
	hwnd = CreateWindow(szAppName, TEXT("The Hellp Program"), WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
		// CW_USEDEFAULT:取默认值
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL);

	//iCmdShow:决定窗口的显示是正常还是最小化、最大化窗口
	ShowWindow(hwnd, iCmdShow);
	// 通过发送消息WM_PAINT给到WndProc来完成
	UpdateWindow(hwnd);

	// windows实现一个消息队列,来维护接收到的消息
	while (GetMessage(&msg, NULL, 0, 0))
	{
		// 将msg返还给windows以进行某些键盘消息的转换
		TranslateMessage(&msg);
		// 将msg发送给WndProc,只有在WndProc将控制权返还给windows后,DispatchMessage才会返回
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int cxChar, cxCaps, cyChar;
	static int cxClient, cyClient, iVscrollPos;
	HDC hdc;
	int i, y;
	PAINTSTRUCT ps;
	TCHAR szBuffer[10];
	TEXTMETRIC tm;
	RECT rect;
	int rangeMax = 0;
	int pos = 0;

	switch (message)
	{
		// 收到的第一条消息
	case WM_CREATE:
		// 获取窗口的设备环境
		hdc = GetDC(hwnd);

		// 获取默认系统字体的尺寸
		GetTextMetrics(hdc, &tm);
		// 平均字符宽度
		cxChar = tm.tmAveCharWidth;
		// 平均宽度(等宽字体中,等于cxChar,在变宽字体中,cxCaps设为cxChar的1.5倍)
		cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
		// 字符的总高度(包括外部间距)
		cyChar = tm.tmHeight + tm.tmExternalLeading;

		ReleaseDC(hwnd, hdc);

		GetClientRect(hwnd, &rect);

		// 判断显示的内容是否大于客户区高度,来决定range的最大值
		if (rect.bottom < (cyChar * NUMLINES))
		{
			rangeMax = NUMLINES - 1;
		}

		SetScrollRange(hwnd, SB_VERT, 0, rangeMax, FALSE);
		SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);

		return 0;

		//当客户区无效且必须更新时,就会接收到这套消息。第一次接收到是调用`UpdateWindow(hwnd);`的时候
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		for (i = 0; i < NUMLINES; i++)
		{
			y = cyChar * (i - iVscrollPos);

			// 程序会输出到客户区外面,没有必要调用,所以进入下一个循环
			if (y < 0)
			{
				continue;
			}

			// 显示index
			TextOut(hdc, 0, y, szBuffer,
				wsprintf(szBuffer, TEXT("%3d"), i));

			// 参数为HDC,坐标,文本内容,内容长度
			TextOut(hdc, 60, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));

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

			// 设置为右对齐,此时坐标从客户区的右上角开始
			SetTextAlign(hdc, TA_RIGHT | TA_TOP);

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

			SetTextAlign(hdc, TA_LEFT | TA_TOP);
		}

		EndPaint(hwnd, &ps);
		return 0;
		// 窗口大小发生变化时,这样就不需要每次都使用 GetClientRect 来获取客户区的大小
		// 由于窗口的风格为CS_HREDRAW | CS_VREDRAW,所以WM_SIZE消息之后会有一个WM_PAINT的消息
	case WM_SIZE:
		cxClient = LOWORD(lParam);
		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));
		pos = GetScrollPos(hwnd, SB_VERT);
		if (iVscrollPos != pos)
		{
			SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
			//使整个窗口无效,此时Windows会在消息队列中放置一条WM_PAINT消息
			//但是Windows将WM_PAINT消息当作低优先级消息处理,有可能会导致窗口重绘比较慢
			//这个时候可以调用UpdateWindow,此时WM_PAINT消息为非队列消息,直接由窗口过程处理
			InvalidateRect(hwnd, NULL, TRUE);
		}
		return 0;

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

	// 使用DefWindowProc来对所有窗口过程没有处理的消息进行默认处理非常重要,否则其他的正常行为(如结束程序)无法进行
	return DefWindowProc(hwnd, message, wParam, lParam);
}

示例代码(Win32)

这里使用了SetScrollInfoGetScrollInfoScrollWindow来替代上面的接口,通过设置页面大小以及范围来自动限制滚动的区间,以及接受了32位的参数,完善了旧接口只能接收16位范围的问题

#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("HelloWin");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;

	// class style: 水平尺寸或垂直尺寸被改变都会重新绘画
	wndclass.style = CS_HREDRAW | CS_VREDRAW;

	// 窗口过程,用于处理该窗口的消息
	wndclass.lpfnWndProc = WndProc;
	// 预留额外空间大小
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	// 窗口设定图标,IDI:ID for an icon
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	// 鼠标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	// hbr:handle to a brush,窗口客户区的北京颜色
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("This program NT"), szAppName, MB_ICONERROR);

		return 0;
	}

	// WS_OVERLAPPEDWINDOW:层叠窗口
	// WS_VSCROLL | WS_HSCROLL : 垂直滚动条,水平滚动条,此时客户区并不包含滚动条所占用的空间;
	hwnd = CreateWindow(szAppName, TEXT("The Hellp Program"), WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
		// CW_USEDEFAULT:取默认值
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL);

	//iCmdShow:决定窗口的显示是正常还是最小化、最大化窗口
	ShowWindow(hwnd, iCmdShow);
	// 通过发送消息WM_PAINT给到WndProc来完成
	UpdateWindow(hwnd);

	// windows实现一个消息队列,来维护接收到的消息
	while (GetMessage(&msg, NULL, 0, 0))
	{
		// 将msg返还给windows以进行某些键盘消息的转换
		TranslateMessage(&msg);
		// 将msg发送给WndProc,只有在WndProc将控制权返还给windows后,DispatchMessage才会返回
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int cxChar, cxCaps, cyChar;
	static int cxClient, cyClient, iMaxWidth;
	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;
		// 平均宽度(等宽字体中,等于cxChar,在变宽字体中,cxCaps设为cxChar的1.5倍)
		cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
		// 字符的总高度(包括外部间距)
		cyChar = tm.tmHeight + tm.tmExternalLeading;

		ReleaseDC(hwnd, hdc);

		iMaxWidth = 22 * cxCaps + 100 * cxChar;

		return 0;

	// 窗口大小发生变化时,这样就不需要每次都使用 GetClientRect 来获取客户区的大小
	// 由于窗口的风格为CS_HREDRAW | CS_VREDRAW,所以WM_SIZE消息之后会有一个WM_PAINT的消息
	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)
		{
			// 滚动窗口客户区的内容,而不是重绘
			// 最后两个参数为NULL,表示滚动整个客户区,会产生WM_PAINT
			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);
		}

		return 0;
		//当客户区无效且必须更新时,就会接收到这套消息。第一次接收到是调用`UpdateWindow(hwnd);`的时候
	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);

			// 显示index
			TextOut(hdc, x, y, szBuffer, wsprintf(szBuffer, TEXT("%3d"), i));

			// 参数为HDC,坐标,文本内容,内容长度
			TextOut(hdc, x + 60, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));

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

			// 设置为右对齐,此时坐标从客户区的右上角开始
			SetTextAlign(hdc, TA_RIGHT | TA_TOP);

			TextOut(hdc, x + 22 * cxCaps + 100 * 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;
	}

	// 使用DefWindowProc来对所有窗口过程没有处理的消息进行默认处理非常重要,否则其他的正常行为(如结束程序)无法进行
	return DefWindowProc(hwnd, message, wParam, lParam);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值