首先需要说明的是,我所说的字符串的长度,不是string的length,也不是string的size。我指的是显示的长度,即物理长度。

缘由:
之所以要提到这个,是因为遇到了一些问题。
再使用duilib进行开发时,发现label控件不能自适应宽度。

思考:
这显示是这个库的一个不足,但是我们可以试图去修改一下这个库。但是本着开源的精神,或许这个库的设计初衷就是label不能自适应字符串的宽度呢?

所有只有走第二条路,我们首先获得要显示字符串的宽度width值,然后把这个label的宽度设置为width。

实现:
现在的问题就是在windows上,如何获得一个字符串的宽度呢?

这个时候一定想到了使用设备描述表,HDC。

如何获得DC以及如何释放DC,这里就不再赘述了,之前的博客有过讲解。

这个时候你又会问,我怎么确定一个字符串的显示长度呢?
对于同一个字符串,不同大小的字体,显示也是不一样的啊。

所以,我们肯定也需要用到字体。

这里有个函数:

HFONT hFont=CreateFont(27, 0, 0, 0, FW_DONTCARE, 0, 0, 0,ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, NULL);

看看这个函数,参数很多:

cHeight是字体的高度。
cWidth是字体的宽度。
cEscapement是字体的倾斜角。
cOrientation是字体的倾斜角。
cWeight是字体的粗细。
bItalic是字体是否斜体。
bUnderline是字体是否有下划线。
bStrikeOut是字体是否有删除线。
iCharSet是字体使用的字符集。
iOutPrecision是指定如何选择合适的字体。
iClipPrecision是用来确定裁剪的精度。
iQuality是怎么样跟选择的字体相符合。
iPitchAndFamily是间距标志和属性标志。
pszFaceName是字体的名称。
函数功能:该函数创建一种有特殊性的逻辑字体,此逻辑字体可以在后面被任何设备选择。
函数原型:HFONT CreateFont(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD fdwltalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD

fdwCharSet, DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCTSTR lpszFace);

参数:
nHeight:指定字体的字符单元或字符的逻辑单位高度,字符的高度值(也被称为em高度)是指字符单元高度值减去内部标头值。字体映射器以如下方式解释nHeight指定的值,各值含义
为:

0:字体映射器转换这个值以设备单位,并和已有字体的单元高度相匹配。

0:字体映射器转换在选择匹配时用一个缺省的高度值。

<0:字体映射器转换这个值到设备单位,并将它的绝对值和已有字体的字符高度相匹配。

比较所有的高度,字体映射器选择不超过要求大小的最大字体。

此映射当字体第一次被使用时发生。

对于MM_TEXT映射方式,可以用下面的公式为一种指定了点大小的字体确定高度:

nHeight=-MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY),72)

nWidth:指定所要求字体的字符的逻辑单位的平均宽度。如果此值为0,字体映射器选择一个closest match值,closest match值是由比较当前设备的特征系数与可使用字体的数字化特征系数之差的绝对值而确定的。

nEscapement:指定移位向量和设备X轴之间的一个角度,以十分之一度为单位。移位向量平行于正文行的基线。

Windows NT:当图形设备设置为GM_ADVANCED时,可以不依赖字符串的字符的定位角而指定字符串的移位角。

当图形模式被设置为GM_COMPATIBLE时,nEscapement同时指定移位角和定位角,可以设置nEscapement和nOrientation为相同的值。

Windows 95:nEscapement同时指定移位角和定位角,可设置nEscapement和nOrientation为相同的值。

nOrientation:指定每个字符的基线和设备X轴之间的角度。

FnWeight:在0到1000之间指定字体的权值,如400表示标准体,700表示黑(粗)体,如果此值为0,则使用缺省的权值。

为方便定义,可使用如下值:

FW_DONTCARE:0;FW_THIN;100;FW_EXTRALIGHT;200;FW_ULTRALIGHT;200;FW_LIGHT;300;

FW_NORMAL:400;FW_REGULAR;400;FW_MEDIUM;500;FW_SEMIBOLD;600;FW_DEMIBOLD;600;

FW_BOLD:700;FW_EXTRABOLD;800;FW_ULTRABOLD;800;FW_HEAVY;900;FW_BLACK;900。

fdwItalic:如果设置为TRUE则指定斜体。

fdwUnderline:如果设置为TRUE,则指定加下划线的字全。

fdwStrikeOut:如果设置为TRUE,则strikeout指定字体。

fdwCharSet:指定字符集,下列值是预定义的:

ANSI_CHARSET; BALTIC_CHARSET; CHINESEBIG5_CHARSET; DEFAULT_CHARSET;

EASTEUROPE_CHARSET; GB2312_CHARSET; GREEK_CHARSET; HANGUL_CHARSET; MAC_CHARSET; OEM_CHARSET; RUSSIAN_CHARSET; SHIFTJIS_CHARSET;
SYMBOL_CHARSET; TURKISH_CHARSET。
韩国Windows:JOHAB_CHARSET;
中东地区Windows:HEBREW_CHARSSET; ARABIC_CHARSET
泰国Windows:THAI_CHARSET

OEM_CHARSET指定的字符集与操作系统有关。

可以使用DEFAULT_CHARSET值来允许字体的名字和大小来充分描述逻辑字体。如果指定的字体名不存在,任何字符集的字体都可以替代指定的字体,所以应该小心地用DEFAULT_CHARSET来避免不期望的结果出现。
操作系统中存在其他字符集的字体。如果一个应用程序用一种未知字符集的字体,则应用程序不会试图去翻译或解释用那种字体写出来的字符串。

在字体映射过程中此参数很重要。为确保获得一致的结果,指定一个特殊的字符集。如果在lpszFace参数中指定了一个字体名,确定fdwCharSet值与由lpszFace指定的字体字符集是否匹配。
fdwOutputPrecision:指定输出精度,输出精度义输出与要求的字体高度、宽度、字符定位、移位、字符间距和字符类型的匹配程序,它可取下列值之一:

OUT_CHARACTER_PRECIS;未用。

OUT_DEFAULT_PRECIS:指定缺省的字体映射器状态。

OUT_DEVICE_PRECIS:指示字体映射器在当系统里有多种字体使用同一个字体使用同一个名字时选择一种设备字体。

OUT_OUTLINE_PRCIS:在Windows NT中此值指示字体映射器从TrueType和其他基于边框的字体中选择。

OUT_RASTER_PRECIS:指示字体映射器在当系统里有多种字体使用同一个名字时选择一种光栅字体。

OUT_STRING_PRECIS:此值没有被字全映射器使用,但是当扫描字体被列举时作为返回值。

OUT_STROKE_PRECIS:在Windows NT中此值没有被字体映射器使用,但是当TrueType字体、其他基于边框的字体和向量字体被列举时,作为返回值。

Windows 95:此值没有被字体映射器使用,但是当TrueType字体或向量字体被列举时,作为返回值。

OUT_TT_ONLY_PRECIS:指示字体映射器仅从TrueType字体中选择,如果系统中没有安装TrueType字体,则字体映射返回缺省状态。、

OUT_TT_PRECIS:指示字体映射器在当系统里有多种同名的字体时选择一种TrueType字体。

当操作系统含有多种与指定名字同名的字体时,应用程序可以使用OUT_DEVICE_PRECIS,OUT_RASTER_PRECIS和OUT_TT_PRECIS值来控制字体映射器如何选择一种字体,例如,如果操作系统含有名字Symbol的光栅和TrueType两种字体,指定OUT_TT_PRECIS使字体映射器选择TrueType方式。指定OUT_TT_ONLY_PRECIS使字体映射器选择一种TrueType字体,尽管这会给TrueType字体换一个名字。

fdwClipPrecision;指定裁剪精度,裁剪精度定义如何裁剪部分超出裁剪区的字符,它可取一个或多个下列值:

CLIP_DEFAULT_PRECIS:指定缺省裁剪状态。CLIP_CHARACTER_PRECIS:未用。

CLIP_STROKE_PRECIS:未被字体映射器使用,但是当光栅字体、向量字体或TrueType字体被列举时作为返回值。在Windows环境下,为保证兼容性,当列举字体时这个值总被返回。

CLIP_MASK:未用。CLIP_EMBEDDED:要使用嵌入式只读字体必须使用此标志。

CLIP_LH_ANGLES:当此值被使用时,所有字体的旋转依赖于坐标系统的定位是朝左的还是朝右的。

如果未使用此值,设备字体总是逆时针方向旋转,但其他字体的旋转依赖于坐标系统的定向。要得到更多关于坐标系统定向的信息,参见参数orientation。

CLIP_TT_ALWAYS:未用。

fdwQuality:指向输出质量,输出质量定义GDI如何仔细地将逻辑字体属性与实际物理字体属性相匹配。它可取下列值之一:

DEFAULT_QUALITY:字体的外观不重要。

DRAFT_QUALITY:字体外观的重要性次于使用PROOF_QUALITY时,对GDI光栅字体,缩放比例是活动的,这意味着多种字体大小可供选择,但质量可能不高,如果有必要,粗体、斜体、下划线、strikeout字体可被综合起来使用。

PROOF_QUALITY:字符质量比精确匹配逻辑字体字体属性更重要。对GDI扫描字体,缩放比例是活动的,并选择最接近的大小。尽管当使用PROOF_QUALITY时,选择字体大小并不完

全匹配,但字体的质量很高,并没有外观上的变形。如果有必要,粗体、斜体、下划线、strikeout字体可被综合起来使用。

fdwPitchAndFamily:指定字体间距和字体族,低端二位指定字体的字符间距,它可取下列值之一:

DEFAULT_PITCH;FIXED_PITCH; VARIABLE_PITCH

高端四位指定字体族,可取下列值之一:

FF_DECORATIVE:新奇的字体,如老式英语(Old English)。FF_DONTCARE:不关心或不知道。

FF_MDERN:笔划宽度固定的字体,有或者无衬线。如Pica、Elite和Courier New。

FF_ROMAN:笔划宽度变动的字体,有衬线。如MS Serif。

FF_SCRIPT:设计成看上去象手写体的字体。如Script和Cursive。

FF_SWISS:笔划宽度变动的字体,无斜线。如MS Sans Serif。

应用程序可以用运算符OR将字符间距和字体族组合起来给fdwPitchAndFamily赋值。

字体族描述一种字体的普通外观,当所有的精确字样都不能使用时,可用它们来指定字体。

lpszface:指向指定字体的字样名的、以/0结束的字符串指针,字符串的长度不能超过32个字符(包括字符/0),函数EnumFontFamilies可用来列举所有当前可用字体的字样名。

如果lpszFace为NULL或指向一个空串,GDI使用能匹配其他属性的第一种字体。

返回值:如果函数调用成功,返回值是一种逻辑字体句柄;如果函数调用失败,返回值为NULL。

Windows NT:若想获得更多错误信息,请调用GetLastError函数。

备注:当一种字体不再使用时,可用DeleteObject来删除。

为保护那些提供字体给Windows和Windows NT的卖主的版权,基于Win32的应用程序总是列出所选择字体的准确名字。由于不同的系统会使用不同的字体,不要认为所选择字体就是要

求的字体。例如,如果要求名叫Palatino的字体,但系统没提供那样一种字体,则字体映射器将会以一种不同名但有相似属性的字体取而代之。系统总是将用户选择的字体名报告出来。

接下来就是利用SelectObject()函数,选入hdc和字体,这里SelectObject函数也不做过多介绍。

下面就要开始整体了,我们有两种方法。

1使用函数GetTextExtentPoint32
函数功能:该函数计算指定的正文字符串的高度和宽度。
函数原型:BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int cbString, LPSIZE lpSize);
参数:
hdc:设备环境句柄。
lpString:指向正文字符串的指针。此字符串不必以\0结束,因为cbString指定了字符串的长度。
cbString:指向字符串中的字符数。
lpSize:指向SIZE结构的指针,该结构中字符串的尺寸将被返回。
返回值:如果函数调用成功,返回值是非零值,如果函数调用失败,返回值是0。

2使用函数DrawText
函数原型
int DrawText(
HDC hDC, // 设备描述表句柄
LPCTSTR lpString, // 将要绘制的字符串
int nCount, // 字符串的长度
LPRECT lpRect, // 指向矩形结构RECT的指针
UINT uFormat // 正文的绘制选项
);

参数
hdc:
[输入]设备环境句柄。
lpString:
[输入]指向将被写入的字符串的指针,如果参数nCount是-1,则字符串必须是以\0结束的。 如果uFormat包含DT_MODIFYSTRING,则函数可为此字符串增加4个字符,存放字符串的缓冲区必须足够大,能容纳附加的字符。
nCount:
[输入]指向字符串中的字符数。如果nCount为-1,则lpString指向的字符串被认为是以\0结束的,DrawText会自动计算字符数。
lpRect:
[输入/输出]指向结构RECT的指针,其中包含文本将被置于其中的矩形的信息(按逻辑坐标)。
uFormat:
[输入]指定格式化文本的方法。它可以下列值的任意组合,各值描述如下:
DT_CALCRECT:这个参数比较重要,可以使DrawText函数计算出输出文本的尺寸。如果输出文本有多行,DrawText函数使用lpRect定义的矩形的宽度,并扩展矩形的底部以容纳输出文本的最后一行。如果输出文本只有一行,则DrawText函数改变矩形的右边界,以容纳下正文行的最后一个字符。出现上述任何一种情况,DrawText函数将返回格式化文本的高度,而不是绘制文本。
DT_CENTER:指定文本水平居中显示。
DT_VCENTER:指定文本垂直居中显示。该标记只在单行文本输出时有效,所以它必须与DT_SINGLELINE结合使用。
DT_SINGLELINE:单行显示文本,回车和换行符都不断行。

最后,献上代码:

int CalWstringWidth(const std::wstring & name)
{HDC hDC = ::GetDC(NULL);HFONT hFont = CreateFont(27, 0, 0, 0, FW_DONTCARE, 0, 0, 0,ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, NULL);SelectObject(hDC, hFont);LPCTSTR  string = name.c_str();SIZE size = { 0 };GetTextExtentPoint32(hDC, string, _tcslen(string), &size);RECT rect = { 0 };//::DrawText(hDC, string, _tcslen(string), &rect, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE);DeleteDC(hDC);//int str_width = std::abs(rect.right - rect.left);return size.cx;
}

windows客户端开发--如何测量一个字符串显示的物理长度相关推荐

  1. Windows客户端开发--获取系统mac地址(使用WMI)

    之前写过两篇博客,介绍了windows的WMI技术,以及如果通过WMI获取显卡详细信息: Windows客户端开发–WMI技术介绍 Windows客户端开发–使用WMI获取显卡详细信息(win32控制 ...

  2. windows客户端开发--也许是一条不归路

    如今的Windows客户端开发,已经被同行嘲笑为鸡肋,甚至有些人认识做Windows客户端就是一个笑柄. 食之无味,弃之可惜. 不可否认,PC端没落的很快. 但是想说的是,任何一门技术都有存在的道理. ...

  3. Windows客户端开发简介(二)

    Windows客户端开发简介(二) 一个典型的Windows客户端程序要有哪几部分构成呢?下面我会以一个国内比较流行的互联网客户端程序的基本架构来跟大家逐步展开分析,由于涉及到知识产权的问题,请大家不 ...

  4. Windows客户端开发简介(一)

    在这样一个移动当道的年代,我跟大家讨论Windows客户端开发,似乎有些倚老卖老的意思了.然而我却觉得无论什么时候,Windows客户端开发其实还是有着不少实用经典的技术的.对了,确切说我是要说说Wi ...

  5. mysql 长度为1 的空字符串_MYSQL,如果定义了一个字符串的字段,长度为255,那么当我添加一个空字符串数据时占用空间吗?...

    你的位置: 问答吧 -> PHP -> 问题详情 MYSQL,如果定义了一个字符串的字段,长度为255,那么当我添加一个空字符串数据时占用空间吗? MYSQL,如果定义了一个字符串的字段, ...

  6. 给windows客户端开发新人的一点建议

    转载链接:http://blog.csdn.net/wininternal/article/details/7604099 看到论坛上很多新人想从事windows开发,却不知从何学起,本ID是过来人, ...

  7. windows客户端开发--使用json11解析json

    类似xml,JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式. json11是适用于c++11的一个轻量级的库,用于解析json. 什么是json? JSO ...

  8. windows客户端开发--根据可下载url另存为文件(微信windows客户端这样做的)

    可以我的blog的标题会让你误解,那么好,没图说了xx: 比如微信windows客户端发送了一张图片,我们可以预览这张图片,还可以保存到本地: 那么windows程序是如何下载这张图片的呢? 是这样, ...

  9. python windows 客户端开发_如何在Windows上使用Python进行开发

    本文由葡萄城技术团队于原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 一直以来C#都是微软在编程语言方面最为显著的Tag,但时至今日Python ...

  10. windows客户端开发--windows api大全

    网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连接 WNetAddConnection3 创建同一个网络资源的 ...

最新文章

  1. FOSCommentBundle功能包:设置Doctrine ODM映射
  2. 8086实时时钟实验(一)——《x86汇编语言:从实模式到保护模式》05
  3. 建立文件服务器好处,文件服务器好处
  4. js获取字符串最后一个字符代码
  5. ax.spines——matplotlib坐标轴设置
  6. python 字符串format格式化一
  7. win11菜单栏的推荐项目怎么取消 windows11取消推荐项目的设置方法
  8. 【React Native 安卓开发】----(Flexbox布局)【第二篇】
  9. 关于开源软件的十个问题(下篇)
  10. 4-vue的生命周期(钩子函数)
  11. 【课程设计】图书管理系统 C语言版---操作系统版
  12. 图片拼图效果——ps
  13. 计算机桌面基本设置操作包括哪些,电脑技巧入门操作有哪些
  14. 深度学习整理:detection 学习(2)——detection细节知识入门
  15. vite+ts+vue3 知识点(全局组件,局部组件,递归组件)
  16. mysql笔记(一):Navicat for MySQL远程连接mysql服务报错的解决方法(1130、2509)
  17. matlab 功率谱密度 汉宁窗_【转】功率谱密度相关方法的MATLAB实现
  18. 狗眼看人低的10个经典场景(组图)
  19. 读书笔记-赢在用户[1]:什么是人物角色?为什么要创建人物角色?
  20. linux环境中配置cuda环境,指定gpu以及用量

热门文章

  1. 关于 PHP 的框架 phalcon 学习(一) url 路由过程。
  2. 不要在循环中访问数据库,这样会严重影响数据库性能
  3. yes we can
  4. python软著申请_软著申请流程时间
  5. MAC清除Launchpad 应用程序 图标
  6. mysql 月初 月末_月初 月末 sql 语句(日期所在月的第一天,最后一天)
  7. 学习大数据开发零基础是不是限制,小白能否快速学会?附上学习路线图
  8. 微信V3接口商家转账到零钱
  9. 如何制作资产编号标签
  10. BTN7971B电机驱动设计(含原理图)