windows程序设计(七)文字输出

本讲中要使用TextOut函数来在窗口上显示多行文字,首先介绍TextOut函数的用法。
TextOut函数在指定位置写入的字符串,利用当前选择的字体,背景颜色和文本颜色。

BOOL TextOutA(
  HDC    hdc,
  int    x,
  int    y,
  LPCSTR lpString,
  int    c
);

第一个参数hdc为装置内容代号,可以是GetDC的回传值,也可以是在处理WM_PAINT信息的BeginPaint回传值。
第二个参数x和第三个参数y为系统对齐字符的参考点,原点为显示区域的左上角。
第四个参数lpString为指向字符串的指针。
第五个参数c为字符串的长度。

如果想要在视窗中显示多个字符,那么就必须知道字符的大小,在早期的windows版本中,使用的字体为等宽字体即所有的字符都具有相等的宽度,从windows3.0之后,windows的系统字体变成了变宽字体,如大写W字符要比小写的a字符宽。windows的系统字体是一种点阵字体。

字元大小

对于不同的分辨率,会有不同的大小的系统字体,可以通过GetTextMetrics
获得字体大小的信息,windows对于不同字体的信息存放在TEXTMETRIC 结构体中

typedef struct tagTEXTMETRICA {
  LONG tmHeight;
  LONG tmAscent;
  LONG tmDescent;
  LONG tmInternalLeading;
  LONG tmExternalLeading;
  LONG tmAveCharWidth;
  LONG tmMaxCharWidth;
  LONG tmWeight;
  LONG tmOverhang;
  LONG tmDigitizedAspectX;
  LONG tmDigitizedAspectY;
  BYTE tmFirstChar;
  BYTE tmLastChar;
  BYTE tmDefaultChar;
  BYTE tmBreakChar;
  BYTE tmItalic;
  BYTE tmUnderlined;
  BYTE tmStruckOut;
  BYTE tmPitchAndFamily;
  BYTE tmCharSet;
} TEXTMETRICA, *PTEXTMETRICA, *NPTEXTMETRICA, *LPTEXTMETRICA;

第一个参数tmHeight为字符的高度(tmAscent+tmDescent 上升+下降)。
第二个参数tmAscent为字符的上升(基线上方的单位)。
第三个参数tmDescent为字符的下降(基线下方的单位)。
第四个参数tmInternalLeading为tmHeight成员设置的边界内的前导(空格)量,通常是用来标注重音,可以设置为0。
第五个参数tmExternalLeading为它是字体设计者建议加在横向字元之间的空间大小,可以将其设为0。
第六个参数tmAveCharWidth为字体中字符的平均宽度(通常定义为字母x的宽度)。此值不包括粗体或斜体字符所需的突出部分。对于大写字母的平均宽度则需要tmAveCharWidth的1.5倍。
第七个参数tmMaxCharWidth为字体中最宽字符的宽度。

格式化文字

如果要在视窗中显示字体,就必须首先取得字元的高度和宽度,可以在开始定义两个变量来保存平均字元的宽度和总的字元高度,如下:

 cxChar = tm.tmAveCharWidth ;  
 cyChar = tm.tmHeight + tm.tmExternalLeading ;

可以看到在计算cyChar时包括了tmExternalLeading 栏位来确保可读性。
要显示格式化的字符串必须要使用sprintf和wsprintf函数来显示,从 sprintf 和 wsprintf 传回的值就是字串的长度。

综合使用

/*-------------------------------------
 SYSMETS.H -- System metrics display structure
---------------------------------------*/
#include <tchar.h>
#include <Windows.h>

#define NUMLINES ((int) (sizeof sysmetrics / sizeof sysmetrics [0])) 
struct 
{
	int index;
	TCHAR * szLable;
	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"),
};
/*-------------------------------------
 将SYSMETS.H中的结构体显示到视窗上面 
---------------------------------------*/
#include<Windows.h>
#include "SYSTEMS.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR sCmdLine, int iCmdShow) 
{
	static TCHAR szAppName[] = TEXT("SysMets1");
	HWND hwnd;
	MSG msg;
	WNDCLASSEX wndclass;
	wndclass.cbSize = sizeof(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;  //窗口类的名称
	wndclass.hIconSm = NULL; //没有类的小图标

	if (!RegisterClassEx(&wndclass)) {
		MessageBox(NULL, TEXT("Can't funcitom"), szAppName, MB_ICONERROR);
		return 0;
	}
	
	hwnd = CreateWindowEx(
		0,  //dwExStyle, 扩展样式 
		szAppName, //lpClassName,类名
		"WindowsName",  //lpWindowName窗口名称
		WS_OVERLAPPEDWINDOW, //dwStyle, 窗口风格
		CW_USEDEFAULT,  //X,初始X坐标
		CW_USEDEFAULT,  //Y,初始Y坐标
		CW_USEDEFAULT,  //nWight, 宽度
		CW_USEDEFAULT,  //nHight, 高度
		NULL,  //hWndParent, 父窗口句柄
		NULL,  //hMenu, 菜单句柄
		hInstance,  //hInstance, 程序实例句柄
		NULL   //ipParam,用户数据
	);

	::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) 
{
	static int cxChar, cxCaps, cyChar;
	HDC hdc;
	int i;
	PAINTSTRUCT ps;
	TCHAR szBuff[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].szLable,
				lstrlen(sysmetrics[i].szLable));

			TextOut(hdc, 22 * cxCaps, cyChar * i, sysmetrics[i].szDesc,
				lstrlen(sysmetrics[i].szDesc));
			SetTextAlign(hdc, TA_RIGHT | TA_TOP);
			TextOut(hdc, 22 * cxCaps + 40 * cxChar, cyChar * i, szBuff, wsprintf(szBuff, TEXT("%5d"),
				GetSystemMetrics(sysmetrics[i].index)));
			SetTextAlign(hdc, TA_LEFT | TA_TOP);
		}
		EndPaint(hwnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

该程序是将一个结构体数组中的全部内容打印在视窗中,该数组存储再SYSTEMS.h的头文件中,对与视窗的创建和前面所说的完全一致,重点放在视窗信息处理函数的处理过程上。在信息处理函数中要处理三个命令。分别是WM_CREATE、 WM_PAINT和WM_DESTROY。
在创建视窗时,我们会先执行第一个讯息WM_CREATE,首先通过GetDC函数获取该视窗的装置代号并存储在hdc 变量中,并且调用GetTextMetrics 函数获得系统中字体的一些信息,将系统字体的平均宽度存储在cxChar中,字元的总高度存储在cyChar中 , 还将大写字母的平均宽度保存在静态变量 cxCaps,对于固定宽度的字体,cxCaps等于 cxChar。最后调用ReleaseDC释放当前装置代号。
在处理WM_PAINT信息时,首先使用BeginPaint获取装置内容代号,之后使用for循环将结构体数组中内容全部打出,使用TextOut函数。可以看到在三个TextOut函数中每次循环的y坐标均相同,为cyChar * i,x坐标依次向后,并且长度是固定的,所以最终显示的应该是三列显示出,在计算字符串长度时,使用lstrlen函数来确定长度。

参考资料:
[1]《Windows程序设计(第五版)》
[2]https://docs.microsoft.com/zh-cn/welcome-to-docs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值