📄 05.1.1 创建文本插入符.txt
字号:
5.1.1 创建文本插入符
在程序中想要创建插入符,可以利用 CWnd类的 CreateSolidCaretO函数来完成,该函数的原型声明如下:
void CreateSolidCaret( int nWidth, int nHeight );
该函数各个参数的含义如下所述:
. nWidth
指定插入符的宽度(逻辑单位)。如果该参数的值为 0,那么系统将其设置为系统定义的窗口边界的宽度。
. nHeight
指定插入符的高度(逻辑单位〉。如果该参数的值为 0,那么系统将其设置为系统定义的窗口边界的高度。下面我们利用这个函数在程序窗口中创建一个插入符,首先请读者按照第 3章介绍的步骤创建一个单文档类型的 MFCAppWizard (exe)工程,取名为 Text。
插入符需要在窗口上创建,单文档类型的工程有两个窗口,即框架类窗口和视类窗口,我们应该选择哪一个窗口来创建插入符呢?第4章曾介绍过,视类窗口始终位于框架类窗口之上,对窗口客户区的鼠标和键盘操作实际上都是在视类窗口上进行的,因此应该在视类窗口上创建插入符。
插入符的创建应该在窗口创建之后进行,可以在 WM_CREATE消息的响应函数 OnCreate中 (在创建窗口的代码之后)添加创建插入符的代码。MFC AppWizard所生成的 CTextView类中没有OnCreate函数,我们需要手动添加。为CTextView类添加WM CREATE 消息的响应函数OnCreate.然后在此函数中创建一个宽度为20、高度为 100的插入符,代码如例5-1所示。
int CTextView: :OnCreate(LPCREATESTRUCT lpCreateStruct)
i f (CView: :OnCreate(lpCreateStruct) -1) return -1;
// TODO: Add your special工zed creation code here
CreateSolidCaret(20 , 100) ;
return 0 ;
Build并运行Text程序,发现程序窗口中并没有出现刚才我们创建的插入符。这是为什么呢?实际上. CreateSolidCaret函数创建插入符以后,该插入符初始时是隐藏的,必须调用ShowCaret函数来显示它。因此,在上述例子1所示代码中调用CreateSolidCaret函数之后,应再添加下面这句代码:
ShowCaret() ;
Build并运行Text程序,创建的插入符终于显示在程序窗口中了,程序运行结果如图
5.1所示。
图 5.1插入符显示结果
显然,这个插入符看起来不太正常,太高也太宽了。我们使用Word时,都有这样的经验,插入符的大小会根据当前所选的字号来变化,如果选择了比较大的字号,例如三号,那么插入符也会相应的增大。对Text程序来说,如何才能够让插入符适合于当前字体的大小呢?首先我们需要得到设备描述表中当前字体的信息,也就是文本的信息,然后根据宇
体的信息来调整插入符的大小。调用CDC类的GetTextMetrics成员函数可以得到设备描述表中当前字体的度量信息。该函数的原型声明如下所示:
BOOL GetTextMetrics( LPTEXTMETRIC lpMetrics ) const;
可以看到,该函数的参数要求是一个TEXTMETRIC结构体的指针,也就是说,我们可以定义一个TEXTMETRIC结构体类型的变量,然后将该变量的地址传递给这个参数。通过GetTextMe国cs这个函数调用,它会用设备描述表中当前字体的信息来填充这个结构体。
TEXTMETRIC结构体的定义如下:
typedef struct tagTEXTMETRIC 1* tm *1
int t mHeight;
int tmAscent;
, int tmDescent;
int tmInternalLeading; ì
int tmExternalLeading;
int tmAveCharWidth;
int tmMaxCharWidth;
int tmWeight;
BYTE tmltalic ;
BYTE tmUnderlined;
BYTE tmStruCkOut ;
BYTE tmFirstChar;
BYTE tmLastChar;
BYTE tmDefaultChar ;
BYTE t mBreakChar;
BYTE tmPitchAndFamilY;
BYTE tmCharSet ;
int tmOverhang;
int tmDigitizedAspectX;
int tmDigitizedAspectY;
TEXTMETRIC;
可以发现TEXTMETRIC这个结构体的信息比较多,但实际上常用的只有几个。为了更好地理解TEXTMETRIC结构体中 tmAscent和 tmDescent成员的含义,先来看看图5.2所示的字体信息示意图。
tmAscent tmDescent
…........... ...1……μ … base line
图 5.2字体信息示意图
从图 5.2中可以看到,对英文字符来说, g和 h的高度明显是不一样的。每一种字体
都有一条基线 ( base line ),基线以上到图中 h字符最高点之间的高度称为升序高度 ( trnAscent),基线以下到图中 g字符最底点之间的高度称为降序高度 (tmDescent)。升序高度加上降序高度就是字体的高度 (tmHeight)。这样,当我们在文本程序窗口中输入文字时,下一行的文字才不会覆盖上-行的文字部分。
和字符的高度一样,英文字符的宽度也是不同的。读者可以在任意文本处理程序中输入一个w和i字符,将会很明显地看到这两个字符的宽度是不一样的,显然w要比i宽。因此,字体并没有一个具体的宽度值,只有一个平均宽度 ( tmAveCharWidth)。另外, TEXTMETRIC结构体中还定义了宇体的最大字符宽度 (trnMaxCharWidth)。
得到了字体的信息,我们就可以利用字体的高度和平均宽度来计算插入符的高度和宽度。例5-2是具体的实现代码:
int CTextView : :OnCreate(LPCREATESTRUCT lpCreateStruct) {
、
if (CView : :OnCreate(lpCreateStruct) -1)
return -1;
//创建设备描述表
CClientDC dc(this) ;
//定义文本信息结构体变量
TEXTMETRIC tm;
//获得设备描述表中的文本信息
dc . GetTextMetrics(&tm) ;
//根据字体大小,创建合适的插入符
CreateSolidCaret(tm.tmAveCharWidth/8, tm . tmH eight) ;
//显示插入符
ShowCaret() ;
return 0 ;
读者可能要提出这样的疑问,为什么上述例5-2所示代码在创建插入符时,要将字体平均宽度除以8呢?这是-个经验值,读者可以试试其他数值,看看结果是否符合自己的需要。
Build并运行Text程序,这时在应用程序窗口的左上角就出现了一条闪烁的竖线,而且其大小也比较符合常规。程序运行结果如图5.3所示。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -