从0开始学习《Windows程序设计》:不要试图猜测文本的尺寸!

本文探讨了在编程中动态计算行距的方法,避免了硬编码宏常量的局限性。通过使用GetTextMetrics函数,可以获取当前字体的详细信息,如字符高度、平均宽度及外部间距,从而实现文本尺寸的精确测量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题的提出

在之前的编程中,我们对行距的使用,是定义了一个宏常量!

#define LINEHEIGHT 15

第一个问题:这是我们进过多次测试后得出的比较合适行距,大家可以试试其他的行距。
但是这样话,如果工程很大的话,有上万行代码的时候,就会定义很多的宏,所以呢,我们就希望可以让windows为我们动态的计算合适的行距。
第二个问题:那个15的单位是什么呢,是15像素,还是15英寸,也许有人会说,这还用想,肯定是15像素了,但其实是不对的,这是和映射关系有关的。

在这里插入图片描述
从上图我们可以看到,根据不同的映射方式,得到的实际尺寸是不同的,默认的是像素,还有其他的单位。

二、文本尺寸的测量
函数:GetTextMetri

函数功能:

GetTextMetrics 函数将当前字体的信息填充到指定缓冲区(TEXTMETRIC 结构)


API 函数原型:

BOOL GetTextMetrics(
  _In_   HDC hdc,
  _Out_  LPTEXTMETRIC lptm
);
复制代码


参数解析:

参数	含义
hdc	设备环境句柄
lptm	指向 TEXTMETRIC 结构的指针,该结构用于获得字体信息


返回值:

1. 如果函数调用成功,返回值是非 0;

2. 如果函数调用失败,返回值是 0。


备注:

1. 要确定一种字体是否为 TrueType 字体,可以通过调用 GetTextMetrics 函数,然后检查 TEXTMETRIC.tmPitchAndFamily 的值是否为 TMPF_TRUETYPE

2. 注意,调用 GetDC 函数返回的是一个未初始化的 DC,它具有“系统”(一个位图字体)作为默认字体。因此你需要先选择一种字体到 DC
TEXTMETRIC 结构
typedef struct tagTEXTMETRIC {
  LONG  tmHeight;
  LONG  tmAscent;
  LONG  tmDescent;
  LONG  tmInternalLeading;
  LONG  tmExternalLeading;
  LONG  tmAveCharWidth;
  LONG  tmMaxCharWidth;
  LONG  tmWeight;
  LONG  tmOverhang;
  LONG  tmDigitizedAspectX;
  LONG  tmDigitizedAspectY;
  TCHAR tmFirstChar;
  TCHAR tmLastChar;
  TCHAR tmDefaultChar;
  TCHAR tmBreakChar;
  BYTE  tmItalic;
  BYTE  tmUnderlined;
  BYTE  tmStruckOut;
  BYTE  tmPitchAndFamily;
  BYTE  tmCharSet;
} TEXTMETRIC, *PTEXTMETR

成员	含义
**tmHeight	字符高度(tmAscent + tmDescent)
tmAscent	字符上部高度(基线以上)
tmDescent	字符下部高度(基线以下)
tmInternalLeading	内部间距(包含在 tmHeight 中),该间距通常被用于显示重音符号
tmExternalLeading	外部间距,这个值是字体设计者建议在两行文字间留出的空间大小
tmAveCharWidth	1. 字体中小写字符的平均宽度(一般定义为字母 x 的宽度)
2. 字体中大写字符的平均宽度一般是该值的 1.5 倍计算
3. 此值不包括字体所需要的加粗和倾斜字符
tmMaxCharWidth	字体中最宽字符的宽度
tmWeight	字体的粗细轻重程度**
tmOverhang	加入某些拼接字体上的附加高度
tmDigitizedAspectX	字体设计所针对的设备水平方向
tmDigitizedAspectY	字体设计所针对的设备垂直方向
tmFirstChar	为字体定义的第一个字符
tmLastChar	为字体定义的最后一个字符
tmDefaultChar	字体中所没有字符的替代字符
tmBreakChar	定义文本对齐截断操作所显示的字符
tmItalic	如果该值非零,则为斜体字体
tmUnderlined	如果该值非零,则为带下横线字体
tmStruckOut	如果该值非零,则为带删除线字体(字符中间画一条线)
tmPitchAndFamily	1. 如果低位为 0,表示等宽字体,小写和大写字母平均宽度一样
2. 如果低位为 1,表示变宽字体,大写字母是小写平均宽度的 3/2 倍
tmCharSet	字体的字符集

转自鱼c论坛
这里那,我们需要掌握给结构的前7个成员,结合下面的图片理解。
在这里插入图片描述

TEXTMETRIC tm;
	static int cxChar, cyChar;
	switch (message)
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);
		GetTextMetrics(hdc, &tm);
		cxChar = tm.tmAveCharWidth;
		cyChar = tm.tmHeight + tm.tmExternalLeading;
		ReleaseDC(hwnd, hdc);
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		for (int i = 0; i < 10; i++)
		{
			StringCchPrintf(szBuffer, 128, TEXT("%d: %s"), i + 1, TEXT("爱心天使的守护!"));
			StringCchLength(szBuffer, 128, &iTarget);
			TextOut(hdc, cxChar, i*cyChar, szBuffer, lstrlen(szBuffer));
		}
		EndPaint(hwnd, &ps);
		return 0;

我们可以通过以上的调用来动态获取当前字符的大小,所以切记不要去猜测字符的大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值