第4章,[标签 Win32] :文本的格式化,等待完善

专栏导航

上一篇:第4章,[标签 Win32] :文本尺寸的度量

回到目录

下一篇:无

本节前言

对于本节所讲解的知识,有可能,你会需要时不时地参考本专栏的其它文章。真的遇到了需要参考之前的文章的知识点,请你自行查阅。

我呢,也会提到一部分的参考课节。但是呢,你不应该依赖于我的主动提及。最好呢,你自己能够多去了解和查看本专栏目录。

本节内容,来自对佩措尔德教材内容的大段抄录。

我们开始。

一. 本节正文

Windows 运行时,系统字体不会变化。因此,应用程序只需要调用一次 GetTextMetrics 函数。最好的时机,是在窗口过程处理 WM_CREATE 消息时。 WM_CREATE 消息是窗口过程收到的第一条消息。当应用程序在 WinMain 中调用 CreateWindow 时,Windows 将发送一条 WM_CREATE 消息给窗口过程。

假设你的 Windows 程序需要在客户区内显示几行文本,你需要获取字符的宽度和高度。在窗口过程中,可以定义两个变量来保存字符的平均宽度和总高度。

static int cxChar, cyChar;

变量名的前缀 c 代表 "count",也就是 "个数" ,在这里代表像素数。和 x 与 y 结合,分别表示宽度和高度。它们被定义为静态变量,因为它们必须在 Windows 处理其它消息(比如 WM_PRINT)时还有效。它们也可以定义为全局变量,也就是定义在所有函数之外。

忘了 static 语法的,我们可以来略微复习一下。请看下面的函数。

复制代码
func_01(int * py)
{
    int x = 3;
    x++;
    *py = 3 * x + 1;
}

这段代码,其实还是不难的。假定,我们在主函数中调用了 func_01 函数三次,则两次调用的结果是一样的,每一次调用结束以后,*py 的值都是 13 。

然后呢,我们将上面的代码修改一下,修改为下面的样子。

复制代码
func_01(int * py)
{
    static int x = 3;
    x++;
    *py = 3 * x + 1;
}

修改之后的代码,相比之前的版本,我们只是将 x 的声明加上了 static 关键字。可是,加上了关键字之后,执行机制就会有所不同了。

加上了 static 之后,变量 x 成了一个局部静态变量。它在程序运行的整个周期里面都有效,但只能在 func_01 内部引用它。

我们依然假定,我们在主函数中调用 func_01 函数三次。

第一次调用之后,*py 的值为 13 。第二次调用之后,*py 的值为 16 。第三次调用之后,*py 的值为 19 。

这里,我简单地领大家复习了一下,在函数体中,用 static 关键字来静态声明一个局部变量的用法。我相信,你能够理解我的意思,尽管我的概念表述不精确。

我们接着讲。

以下的 WM_CREATE 代码显示了怎样获取系统字体的宽度和高度。

复制代码
case WM_CREATE:
    hdc = GetDC (hwnd);

    GetTextMetrics (hdc, &tm);
    cxChar = tm.tmAveCharWidth;
    cyChar = tm.tmHeight + tm.tmExternalLeading;

    ReleaseDC (hwnd, hdc);
    return 0;

注意,这里在 cyChar 中包括了 tmExternalLeading 。尽管在我前面用到的系统字体中,这一项通常是 0,但考虑到它可能不是 0,所以还是要包括它,因为这会使行与行之间更加清晰易读。在窗口中,每一行文本显示在上一行文本下方 cyChar 个像素处。

通常需要显示的是格式化的数字和字符串。如第 2 章所述,不能用传统的工具(例如 print 函数),但是可以使用 Windows 版的字符处理函数 ------ wsprintf 。这个函数与 printf 函数功能类似,区别在于格式化之后的字符保存在一个字符串里。这个字符串可以通过 TextOut 函数输出到窗口中。方便的是,wsprintf 函数的返回值是字符串中包含的字符的个数。

注意哦,是字符个数,而不是字符串所包含的字节数。而且,这一个数,并不包含字符串结尾的 NULL 字符。

可以将 wsprintf 的返回值传递给 TextOut 函数,作为 iLength 参数。下面的代码是典型的 wsprintf 和 TextOut 的组合。

复制代码
int iLength;
TCHAR szBuffer[40];
[其他程序行]
iLength = wsprintf (szBuffer, TEXT("the sum of %d and %d is %d"),
                iA, iB, iA + iB);
TextOut (hdc, x, y, szBuffer, iLength);

对于上述代码,wsprintf 的返回值会由 iLength 来接收,而 iLength 又会作为 TextOut 的参数,因此,我们可以省略 iLength 变量的定义,而将 TextOut 函数写作下面的模样。

复制代码
iLength = ;
TextOut (hdc, x, y, szBuffer, 
        wsprintf (szBuffer, TEXT("the sum of %d and %d is %d"),
                iA, iB, iA + iB));

这么写,看上去并不直观,而功能是一样的。

我个人更喜欢分着写的方式,因为这样子写,逻辑上更为清楚。合起来写的方式,虽说代码简略了一点,但是,读起来也会更为费力一些。

我个人,还是更喜欢让代码容易阅读一些。不过,你还是需要能够理解这样的代码。

在调用一个函数的时候,首先呢,会将此被调函数的各个实参压入栈中,参数入栈的顺序,是从右到左。也就是,在参数入栈之时,会先将右侧的参数压入栈中,然后再将左边的参数压入栈中。全部参数入栈以后,才是调用此被掉函数,进入被调函数的函数体之中。

对于上面的代码块的代码,本来应该是从右到左,依次将参数给压入栈中的。然而,当想要将最右边的参数压入栈中的时候,却发现,最右边的参数部分,不是一个已确定的数值,而是一个函数调用,此函数调用尚未有返回值。因此,计算机将先去执行 wsprintf 函数,从 wsprintf 函数返回之后,返回值就有了。有了返回值以后,计算机会将 wsprintf 的返回值压入栈中,然后依次将 szBuffer,y,x 和 hdc 压入栈中,最后才是去执行 TextOut 函数。

我这样子的表述,不知道,你能否理解。多看几遍吧。此处,务必理解。

这算是一个小的攻坚战,硬骨头,务必将其啃下来。

在我的专栏里面,如果呢,我所采用的代码,是佩措尔德的代码,那么,佩措尔德使用的合写的、逻辑复杂一些的代码,那么,我也就这么来写,不会对这种合写的风格作出修改。

但是呢,如果是说,我自己编写某一个程序的话,那么,我尽量采用分着写,容易理解的风格,来书写代码。

你呢,其实最好还是说,你能够把这种复杂的、合写的、不太好理解的代码风格,给啃下来。但是呢,当前阶段,我还是希望,尽量地,分解难度,希望尽量地,能够让你学得会,看得懂。所以呢,我自己写的代码,我会尽量地采用容易理解的、分着写的写法。

如果你只能看懂分着写的、容易理解的代码,而看不懂合写的、不好理解的代码,那么,你还是需要多锻炼。编程学习的路上,难免会有人喜欢用复杂风格的代码。自己的能力上来了,难的,我们可以应付,简单的,也能够应付,那不是很好吗?

总 结

本节的主体内容,是对佩措尔德教材的大段抄录。我自己呢,还是在写教程的时候,加上了我自己的一点讲解,以便让你好理解一些。

以后,有机会,我应该还是会尽量地去修改内容,以便,我以我的讲法,分解难度,让学员更容易学。

专栏导航

上一篇:第4章,[标签 Win32] :文本尺寸的度量

回到目录

下一篇:无

相关推荐
雾岛听蓝3 小时前
C++11新特性(lambda、包装器)
c++·经验分享·笔记
m0_531237174 小时前
C语言-指针终阶
c语言·开发语言
散峰而望4 小时前
C++ 启程:从历史到实战,揭开命名空间的神秘面纱
c语言·开发语言·数据结构·c++·算法·github·visual studio
PingdiGuo_guo5 小时前
C++数据类型、变量常量
开发语言·c++
水饺编程5 小时前
第4章,[标签 Win32] :TextOut 测试案例3代码改编
c语言·c++·windows·visual studio
Darkwanderor5 小时前
数据结构 - 并查集的应用
数据结构·c++·并查集
多恩Stone5 小时前
【C++ debug】在 VS Code 中无 Attach 调试 Python 调用的 C++ 扩展
开发语言·c++·python
PingdiGuo_guo6 小时前
C++联合体详解!
开发语言·c++
code bean6 小时前
Visual Studio 2026 离线安装包制作指南
ide·visual studio
浅念-6 小时前
C++ 继承
开发语言·c++·经验分享·笔记·学习·算法·继承