网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
源代码在线查看: 10.4 字体对话框.txt
10.4 字体对话框
下面为 Graphic程序添加字体对话框应用,该对话框类似于我们已经在对话框资源的属性对话框中
所看到的字体对话框,如图 10.15所示。
与上面的颜色对话框一样,字体对话框的创建也很简单,因为 MFC也提供了一个相应的类 :
CFontDialog.该类的派生层次结构如图 10.16所示,由此可知该类派生于 CDialog.所以,其也是一
个对话框类。
图 10.15字体对话框
CFontDialog类的构造函数如下所示:
CFontDialog(
LPLOGFONT lplflnitial = NULL ,
DWORD dwFlags = CF_EFFECTS I CF_SCREENFONTS ,
CDC* pdcprinter = NULL ,
CWnd* pParentWnd = NULL
.
该函数有四个参数,含义分别如下所述:
. lpltinitial
指向LOGFONT结构体的指针,允许用户设置一些字体的特征。
. dwFlags
主要设置一个或多个与选择的字体相关的标记。
. pdcPrinter
指向打印设备上下文的指针。
. pParentWnd
指向字体对话框父窗口的指针。
由 CFontDialog类的构造函数的声明可知,它的参数都有默认值,因此在构造字体对话框时可以不
用指定任何参数。
字体对话框的创建与前面的颜色对话框的一样,首先构造一个字体对话框对象,然后调用该对象的
DoModal函数显示这个对话框即可。因此再为Graphic程序增加一个菜单项用来显示字体对话框,将
其ID设置为: IDM_FONT, Caption设置为:字体。接着为其增加一个命令响应,并选择 CGraphicView
类对此菜单项命令做出响应。然后在此响应函数
中添加创建井显示字体对话框的代码,结果如例 10-19所示。
例10-19
图 10.16 CFontDialog类的派生层次结构图
void CGraphicview: :OnFont()
CFontDialog dlg;
dlg.DoModal() ;
下面我们要实现这样的功能:当用户通过字体对话框选择某种字体后,程序应该把当
前选择保存起来,然后在 CGraphicView类中利用此字体将用户选择的字体名称显示出来。例如如果
用户选择的是黑体,那么在程序中就创建黑体这种字体,再利用这种字体把字体名称:"黑体"显示出
来。
CFontDialog类有一个 CHOOSEFONT结构体类型的数据成员: m_cf CHOOSEFONT 结构体的定义如例
10-20所示。
例 10-20
typedef struct { DWORD lStructSizei HWND hwndOwner i HDC hDCi LPLOGFONT lpLogFonti INT
iPointSizei DWORD Flagsi COLORREF rgbColorsi LPARAM lCustDatai LPCFHOOKPROC lpfnHooki
LPCTSTR lpTemplateNamei HINSTANCE hlnstancei LPTSTR lpszStylei WORD nFontTypei 工 NT
nSizeMini 工 NT nSizeMaxi
1 CHOOSEFONT, *LPCHOOSEFONTi
其中成员 lpLogFont是指向逻辑字体 (LOGFONT类型)的指针。 LOGFONT结构的定义如例 10-21所示。
例 10-21
typedef struct tagLOGFONT { // lf
LONG lfHeight i
LONG lfWidthi
LONG lfEscapementi
LONG lfOrientationi
LONG lfWeighti
BYTE l fItalic;
BYTE lfUnderlinei
BYTE lfStrikeOuti
BYTE lfCharSeti
BYTE lfOutPrecisioni
BYTE lfClipPrecisioni
BYTE lfQualitYi
BYTE lfPitchAndFamilYi
TCHAR lfFaceName[LF_FACESIZE]i
} LOGF咱 ONTi
其中成员lfFaceName中存放的就是字体的名称。也就是说,可以通过此成员得到宇
字体的名称。
至于字体对象的创建,首先可以利用CFont类构造一个字体对象,然后利用CFont类的
CreateFontIndirect成员函数根据指定特征的逻辑字体 (LOGFONT类型〉来初始化这个字体对象。该
函数的声明形式如下所示:
BOOL CreateFontIndirect(const LOGFONT* lpLogFont);
CreateFontIndirect函数的功能就是利用参数 lpLogFont指向的LOGFONT结构体中的一些特征来初
始化CFont对象。
为了保存用户选择的字体,首先为 Graphic工程的 CGraphicView类增加一个 CFont成员变量: m
font,再增加一个CString类型的成员: m s位FontName,用来保存所选字体的名称,井将这两个变
量的访问权限都设置为私有的。然后在 CGraphicView类的构造函数中将m strFontName变量初始化
为空,代码如下所示:
m_strFontName="";
说明:读者在练习时,可以对m_font变量也进行初始化,为它创建一种默
认的字体。
然后在CGraphicView类的 OnFont函数中进行判断,如果用户单击的是字体对话框的 OK按钮,就用
所选字体信息初始化m font对象,井保存所选字体的名称。具体代码如例 10-22所示。
例IJ 10-22
1. void CGraphicView : :OnFont()
2. {
3. CFontDialog dlg ;
4. if (IDOK==dlg . DoModal () )
5. {
6. m_font.CreateFontlndirect(dlg.m_cf.lpLogFont);
7. m_strFontName=dlg.m_cf.lpLogFont->lfFaceName;
8. }
9. }
接下来,在视类窗口中把字体名称用选择的字体显示出来。这可以在 CGraphicView 类的OnDraw函
数中实现,因此在上述OnFont函数中,在第7行代码之后需要调用Invalidate函数让窗口无效,这样
当下一次发生WM PAINT消息时,窗口就会进行重绘。 CGraphicView类OnDraw函数的最终代码如例
10-23所示。
例 10-23
void CGraphicview: :OnDraw(CDC* pDC)
{ CGraphicDoc* pDoc = GetDocument() ; ASSERT_VALID(pDoc) ; // TODO : add draw code for nat
ive data here
CFont *pOldFont=pDC->SelectObject (τtn-font);
pDC->TextOut (O, O, ffi_strFont Name) ;
pDC->SelectObject (pOldFont) ;
在上述例 10-23所示代码中,首先把用户选择的新字体选入设备上下文,然后在窗口的(0, 0)处显
示所选字体的名称,最后再把先前的字体选入设备上下文。
Build井运行 Graphic程序。选择【绘图\字体】菜单项,这时将打开字体对话框,可以选择任一种
字体、字形,还可以指定字体的大小。例如字体选择隶书,字形选择粗体,大小指定为20 (如图 10.17
所示),然后单击字体对话框的OK按钮,这时在视类窗口中就可以看到用选定的字体、字形和大小输
出了所选字体的名称:"隶书",如图 10.18所示。
图 10.17选定字体 图 10.18用选定的字体显示所选字体名称
可是当再次选择【绘图飞字体】菜单项后,程序将出现非法操作。这是因为当第一次选择字体后,
OnFont函数中就把m font对象与这种字体资源相关联了(上述例 10-22所示 OnFont函数第6行代码
的结果〉。当再次选择一种字体后, OnFont函数又会试图把m_font对象与新字体资源相关联,这时
当然就会出错。因此,程序中应该进行一个判断,如果 m font对象已经与一个字体资源相关联了,
首先就需要切断这种关联,释放该字体资源,然后才能与新资源相关联。
要想释放先前的资源,可以利用CGdiObject类 (CPen, CFont, CBitmap, CBrush都派生于该类)的
DeleteObject成员函数来实现。该函数通过释放所有为WindowsGDI对象所分配的资源,从而删除与
CGdiObject对象相关联的WindowsGDI对象,同时与CGdiObject对象相关的存储空间并不会受此调用
影响。这句话的意思是要读者注意区分Windows GDI 和CGdiObject对象。后者是一个类的对象,而
前者是一种资源对象,就好像窗口类的对象和窗口的关系一样,例如视类对象和视类窗口,它们之
间的联系在于视类对象有一个数据成员: m hWnd保存了窗口资源的句柄值。同样地, CGdiObject
类的对象和Windows GDI 资源对象是两个不同的概念,它们之间也是通过一个数据成员来维系的。
当删除Windows GDI资源对象后,对于CGdiObject类所定义的对象来说,并不受影响,只是它们之间
的联系被切断了。
如果想判断 m font对象是否已经与某个字体资源相关联了,最简单的方法就是利用 CGdiObject对
象的数据成员m_hObject来判断,该变量保存了与CGdiObject对象相关联的 Windows GDI资源的句
柄。如果己经有关联了,则调用DeleteObject释放这个字体资源,
382 .
因此,在上述如例 10-22所示OnFont函数的第6行代码前添
加下述代码:
然后再与新的资源相关联。
if(~font.ID_hObject)
ID_font.DeleteObject();
解
详
一叫
再次运行Graphic程序,这时可以发现多次打开字体对话框选择字体,程序一切正确。