当前位置: 首页 > 文档资料 > VC 经典教程 >

5.6 公用对话框

优质
小牛编辑
132浏览
2023-12-01

在使用Windows的过程中,用户经常会遇到一些常用的有特定用途的对话框。例如,当选择File->Open,会弹出一个文件选择的对话框,用户可以在其中选择想要打开的文件。象文件选择这样的对话框,使用的非常普遍,因此Windows系统本身提供了对该对话框的支持,用户不必自己设计文件选择对话框。与文件选择对话框类似的还有颜色选择、字体选择、打印和打印设置以及正文搜索和替换对话框。这五种对话框均由Windows支持,被称为公用对话框。

MFC提供了一些公用对话框类,它们均是CDialog类的派生类,封装了公用对话框的功能。表5.6列出了MFC的公用对话框类。

 

表5.6 公用对话框类

通用对话框类

用途

CColorDialog

选择颜色

CFileDialog

选择文件名,用于打开和保存文件

CFindReplaceDialog

正文查找和替换

CFontDialog

选择字体

CPrintDialog

打印和打印设置

通用对话框类使用方便,读者只需知道怎样创建对话框和访问对话框的数据,不必关心它们的内部细节。

5.6.1 CColorDialog类

CColorDialog类用于实现Color(颜色选择)公用对话框。Color对话框如图5.12所示,在Windows的画板程序中,如果用户在颜色面板的某种颜色上双击鼠标,就会显示一个Color对话框来让用户选择颜色。

T5_12.tif (167359 bytes)

图5.12 Color对话框

 

Color对话框的创建与一般的对话框没什么两样:首先是在堆栈上构建一个CColorDialog对象,然后调用CColorDialog::DoModal( )来启动对话框。CColorDialog的构造函数为

CColorDialog( COLORREF clrInit = 0, DWORD dwFlags = 0, CWnd* pParentWnd = NULL );

参数clrInit用来指定初始的颜色选择,dwFlags用来设置对话框,pParentWnd用于指定对话框的父窗口或拥有者窗口。

根据DoModal返回的是IDOK还是IDCANCEL可知道用户是否确认了对颜色的选择。DoModal返回后,调用CColorDialog::GetColor()可以返回一个COLORREF类型的结果来指示在对话框中选择的颜色。COLORREF是一个32位的值,用来说明一个RGB颜色。GetColor返回的COLORREF的格式是0x00bbggrr,即低位三个字节分别包含了蓝、绿、红三种颜色的强度。

读者将在后面的章节中看到颜色选择对话框的例子。

 

 

5.6.2 CFileDialog类

CFileDialog类用于实现文件选择对话框,以支持文件的打开和保存操作。用户要打开或保存文件,就会和文件选择对话框打交道,图5.13显示了一个标准的用于打开文件的文件选择对话框。用MFC AppWizard建立的应用程序中自动加入了文件选择对话框,在File菜单选Open或Save As命令会启动它们。

T5_13.tif (115270 bytes)

图5.13 文件选择对话框

文件选择对话框的创建过程与一般对话框的类似,首先是在堆栈上构建一个CFileDialog对象,然后调用CFileDialog::DoModal( )来启动对话框。文件对话框的构造函数为

CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL );

如果参数bOpenFileDialog的值为TRUE,将创建Open(打开文件)对话框,否则就创建Save As(保存文件)对话框。参数lpszDefExt用来指定缺省的文件扩展名。lpszFileName用于规定初始文件名。dwFlags用于设置对话框的一些属性。lpszFilter指向一个过滤字符串,用户如果只想选择某种或某几种类型的文件,就需要指定过滤字符串。参数pParentWnd是指向父窗口或拥有者窗口的指针。

过滤字符串有特定的格式,它实际上是由多个子串组成,每个子串由两部分组成,第一部分是过滤器的字面说明,如“Text file (*.txt)”,第二部分是用于过滤的匹配字符串,如“*.txt”,子串的两部分用竖线字符“ | ”分隔开。各子串之间也要用“ | ”分隔,且整个串的最后两个字符必须是两个连续的竖线字符“ || ”。一个典型的过滤字符串如下面所示:

char szFilter[]=

“All files (*.*)|*.*|Text files(*.txt)|*.txt|Word documents(*.doc)|*.doc||”;

若CFileDialog::DoModal返回的是IDOK,那么可以用表5.7列出的CFileDialog类的成员函数来获取与所选文件有关的信息。

 

表5.7 CFileDialog类辅助成员函数

函数名

用途

GetPathName

返回一个包含有全路径文件名的CString对象。

GetFileName

返回一个包含有文件名(不含路径)的CString对象。

GetFileExt

返回一个只含文件扩展名的CString对象。

GetFileTitle

返回一个只含文件名(不含扩展名)的CString对象。

5.6.3 CFindReplaceDialog类

CFindReplaceDialog类用于实现Find(搜索)和Replace(替换)对话框,这两个对话框都是非模态对话框,用于在正文中搜索和替换指定的字符串。图5.14显示了一个Find对话框,图5.15显示了一个Replace对话框。

T5_14.tif (55570 bytes)

图5.14 Find对话框

T5_15.tif (69140 bytes)

图5.15 Replace对话框

 

由于Find和Replace对话框是非模式对话框,它们的创建方式与其它四类公用对话框不同。CFindReplaceDialog对象是用new操作符在堆中创建的,而不是象普通对话框那样以变量的形式创建。要启动Find/Replace对话框,应该调用CFindReplaceDialog::Create函数,而不是DoModal。Create函数的声明是

BOOL Create( BOOL bFindDialogOnly, LPCTSTR lpszFindWhat, LPCTSTR lpszReplaceWith = NULL, DWORD dwFlags = FR_DOWN, CWnd* pParentWnd = NULL );

当参数bFindDialogOnly的值为TRUE时,创建的是Find对话框,为FALSE时创建的是Replace对话框。参数lpszFindWhat指定了要搜索的字符串,lpszReplaceWith指定了用于替换的字符串。dwFlags用来设置对话框,其缺省值是FR_DOWN(向下搜索),该参数可以是几个FR_XXX常量的组合,用户可以通过该参数来决定诸如是否要显示Match case、Match Whole Word检查框等设置。参数pParentWnd指明了对话框的父窗口或拥有者窗口。

Find/Replace对话框与其它公用对话框的另一个不同之处在于它在工作过程中可以重复同一操作而对话框不被关闭,这就方便了频繁的搜索和替换。CFindReplaceDialog类只提供了一个界面,它并不会自动实现搜索和替换功能。CFindReplaceDialog使用了一种特殊的通知机制,当用户按下了操作的按钮后,它会向父窗口发送一个通知消息,父窗口应在该消息的消息处理函数中实现搜索和替换。

CFindReplaceDialog类提供了一组成员函数用来获得与用户操作有关的信息,如表5.8所示,这组函数一般应在通知消息处理函数中调用。

 

表5.8 CFindReplaceDialog类的辅助成员函数

函数名

用途

FindNext

如果用户点击了Findnext按钮,该函数返回TRUE。

GetNotifier

返回一个指向当前CFindReplaceDialog对话框的指针。

GetFindString

返回一个包含要搜索字符串的CString对象。

GetReplaceString

返回一个包含替换字符串的CString对象。

IsTerminating

如果对话框终止了,则返回TRUE。

MatchCase

如果选择了对话框中的Match case检查框,则返回TRUE。

MatchWholeWord

如果选择了对话框中的Match Whole Word检查框,则返回TRUE。

ReplaceAll

如果用户点击了Replace All按钮,该函数返回TRUE。

ReplaceCurrent

如果用户点击了Replace按钮,该函数返回TRUE。

SearchDown

返回TRUE表明搜索方向向下,返回FALSE则向上。

 

 

CEditView类自动实现了Find和Replace对话框的功能,但MFC AppWizard并未提供相应的菜单命令。读者可以在前面的Register工程的Edit菜单中加入&Find...和&Replace...两项,并令其ID分别为ID_EDIT_FIND和ID_EDIT_REPLACE,则Find/Replace对话框的功能就可以实现。

5.6.4 CFontDialog类

CFontDialog类支持Font(字体)对话框,用来让用户选择字体。图5.16显示了一个Font对话框。Font对话框的创建过程与Color对话框的类似,首先是在堆栈上构建一个CFontDialog对象,然后调用CFontDialog::DoModal来启动对话框。

T5_16.tif (144136 bytes)

图5.16 Font对话框

 

CFontDialog类的构造函数如下所示

CFontDialog( LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, CDC* pdcPrinter = NULL, CWnd* pParentWnd = NULL );

参数lplfInitial指向一个LOGFONG结构,用来初始化对话框中的字体设置。dwFlags用于设置对话框。pdcPrinter指向一个代表打印机的CDC对象,若设置该参数,则选择的字体就为打印机所用。pParentWnd用于指定对话框的父窗口或拥有者窗口。

若DoModal返回IDOK,那么可以调用CFontDialog的成员函数来获得所选字体的信息,这些函数在表5.9列出。

 

表5.9 CFontDialog类的辅助成员函数

函数名

用途

GetCurrentFont

用来获得所选字体的属性。该函数有一个参数,该参数是指向LOGFONT结构的指针,函数将所选字体的各种属性写入这个LOGFONT结构中。

GetFaceName

返回一个包含所选字体名字的CString对象。

GetStyleName

返回一个包含所选字体风格名字的CString对象。

GetSize

返回所选字体的尺寸(以10个象素为单位)。

GetColor

返回一个含有所选字体的颜色的COLORREF型值。

GetWeight

返回所选字体的权值。

IsStrikeOut

若用户选择了空心效果则返回TRUE,否则返回FALSE。

IsUnderline

若用户选择了下划线效果则返回TRUE,否则返回FALSE。

IsBold

若用户选择了黑体风格则返回TRUE,否则返回FALSE。

IsItalic

若用户选择了斜体风格则返回TRUE,否则返回FALSE。

 

.6.5 CPrintDialog类

CPrintDialog类支持Print(打印)和Print Setup(打印设置)对话框,通过这两个对话框用户可以进行与打印有关的操作。图5.17显示了一个Print对话框,图5.18显示了一个Print Setup对话框。

T5_17.tif (147955 bytes)

图5.17 Print对话框

T5_18.tif (136979 bytes)

图5.18 Print Setup对话框

 

Print和Print Setup对话框的创建过程与Color对话框类似。该类的构造函数是

CPrintDialog( BOOL bPrintSetupOnly, DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION, CWnd* pParentWnd = NULL );

参数bPrintSetupOnly的值若为TRUE,则创建的是Print对话框,否则,创建的是Print Setup对话框。dwFlags用来设置对话框,缺省设置是打印出全部页,禁止From和To编辑框(即不用确定要打印的页的范围),PD_USEDEVMODECOPIES使对话框判断打印设备是否支持多份拷贝和校对打印(Collate),若不支持,就禁止相应的编辑控件和Collate检查框。pParentWnd用来指定对话框的父窗口或拥有者窗口。

程序可以调用如表5.10所示的CPrintDialog的成员函数来获得打印参数。

 

表5.10 CPrintDialog的辅助成员函数

函数名

用途

GetCopies

返回要求的拷贝数。

GetDefaults

在不打开对话框的情况下返回缺省打印机的缺省设置,返回的设置放在m_pd数据成员中。

GetDeviceName

返回一个包含有打印机设备名的CString对象。

GetDevMode

返回一个指向DEVMODE结构的指针,用来查询打印机的设备初始化信息和设备环境信息。

GetDriverName

返回一个包含有打印机驱动程序名的CString对象。

GetFromPage

返回打印范围的起始页码。

GetToPage

返回打印范围的结束页码。

GetPortName

返回一个包含有打印机端口名的CString对象。

GetPrinterDC

返回所选打印设备的一个 HDC 句柄。

PrintAll

若要打印文档的所有页则返回TRUE。

PrintCollate

若用户选择了Collate Copies检查框(需要校对打印拷贝)则返回TRUE。

PrintRange

如果用户要打印文档的一部分页,则返回TRUE。

PrintSelection

若用户想打印当前选择的部分文档,则返回TRUE。

 

 

用缺省配置的MFC AppWizard建立的程序支持Print和Print Setup对话框,用户可以在File菜单中启动它们。

 

 

5.6.6 公用对话框的使用实例

现在,让我们来测试一下公用对话框的使用。请读者用AppWizard创建一个单文档的MFC应用程序,名为CommonDlg。注意别忘了在AppWizard的第一步中选Single document。

CommonDlg程序要对所有的公用对话框进行了测试。为此,首先要提供用户命令接口。请读者在CommonDlg的菜单资源中插入一个名为&Common的新菜单,这个菜单插在Help菜单之前。然后,在Common菜单中,请按表5.11创建菜单项。

 

表5.11 Common菜单的菜单项

Caption

ID

&Color...

ID_COMMON_COLOR

&Open file...

ID_COMMON_OPENFILE

&Save file...

ID_COMMON_SAVEFILE

&Font...

ID_COMMON_FONT

&Print...

ID_COMMON_PRINT

P&rint setup...

ID_COMMON_PRINTSETUP

F&ind...

ID_COMMON_FIND

&Replace...

ID_COMMON_REPLACE

 

 

接下来的工作是编写测试程序的源代码。首先,利用ClassWizard为表5.11的菜单项创建消息处理函数,注意这些处理函数都是CCommonDlgView的成员。接着,请按清单5.10和5.11修改程序。限于篇幅,这里仅列出与测试相关的部分源代码。

 

清单5.10 头文件CommonDlgView.h

class CCommonDlgView : public CView

{

 

. . . . . .

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

void DispPrintInfo(CPrintDialog& dlg);

protected:

CFont m_Font; //正文的字体

COLORREF m_ForeColor; //正文的前景色

COLORREF m_BackColor; //正文的背景色

 

CFindReplaceDialog *m_pFindReplaceDlg;

BOOL m_bFindOnly;

// Generated message map functions

protected:

 

//Find和Replace对话框通知消息处理函数

afx_msg LRESULT OnFindReplaceCmd(WPARAM, LPARAM lParam);

//{{AFX_MSG(CCommonDlgView)

afx_msg void OnCommonColor();

afx_msg void OnCommonFont();

afx_msg void OnCommonOpenfile();

afx_msg void OnCommonSavefile();

afx_msg void OnCommonPrint();

afx_msg void OnCommonPrintsetup();

afx_msg void OnCommonFind();

afx_msg void OnCommonReplace();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

 

. . . . . .

 

 

清单5.11 文件CCommonDlgView.cpp

#include "stdafx.h"

#include "CommonDlg.h"

 

#include "CommonDlgDoc.h"

#include "CommonDlgView.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

 

IMPLEMENT_DYNCREATE(CCommonDlgView, CView)

 

 

//获取对本进程唯一的消息编号

static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);

 

BEGIN_MESSAGE_MAP(CCommonDlgView, CView)

//{{AFX_MSG_MAP(CCommonDlgView)

ON_COMMAND(ID_COMMON_COLOR, OnCommonColor)

ON_COMMAND(ID_COMMON_FONT, OnCommonFont)

ON_COMMAND(ID_COMMON_OPENFILE, OnCommonOpenfile)

ON_COMMAND(ID_COMMON_SAVEFILE, OnCommonSavefile)

ON_COMMAND(ID_COMMON_PRINT, OnCommonPrint)

ON_COMMAND(ID_COMMON_PRINTSETUP, OnCommonPrintsetup)

ON_COMMAND(ID_COMMON_FIND, OnCommonFind)

ON_COMMAND(ID_COMMON_REPLACE, OnCommonReplace)

//}}AFX_MSG_MAP

// Standard printing commands

ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

 

ON_REGISTERED_MESSAGE(nMsgFindReplace, OnFindReplaceCmd)

END_MESSAGE_MAP()

 

CCommonDlgView::CCommonDlgView()

{

// TODO: add construction code here

 

//缺省前景色为黑色,背景色为白色,字体为系统字体

m_ForeColor=0;

m_BackColor=0xFFFFFF;

m_Font.CreateStockObject(SYSTEM_FONT);

 

m_pFindReplaceDlg=NULL;

 

}

 

void CCommonDlgView::OnDraw(CDC* pDC)

{

CCommonDlgDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

 

// TODO: add draw code for native data here

 

int x,y;

CFont *pOldFont;

TEXTMETRIC TM;

int textHeight;

 

//设置正文的字体

pOldFont=pDC->SelectObject(&m_Font);

//设置正文的前景色和背景色

pDC->SetTextColor(m_ForeColor);

pDC->SetBkColor(m_BackColor);

 

//计算每行正文的高度

pDC->GetTextMetrics(&TM);

textHeight=TM.tmHeight+TM.tmExternalLeading;

 

//输出正文

x=5;y=5;

pDC->TextOut(x,y,"ABCDEFG");

y+=textHeight;

pDC->TextOut(x,y,"abcdefg");

 

//恢复原来的字体

pDC->SelectObject(pOldFont);

 

}

 

void CCommonDlgView::OnCommonColor()

{

// TODO: Add your command handler code here

 

CColorDialog dlg;

 

if(dlg.DoModal()==IDOK)

{

m_BackColor=dlg.GetColor();

 

//重绘视图

Invalidate();

UpdateWindow();

}

}

 

void CCommonDlgView::OnCommonFont()

{

// TODO: Add your command handler code here

 

CFontDialog dlg;

 

if(dlg.DoModal()==IDOK)

{

LOGFONT LF;

 

//获取所选字体的信息

dlg.GetCurrentFont(&LF);

m_ForeColor=dlg.GetColor();

//建立新的字体

m_Font.DeleteObject();

m_Font.CreateFontIndirect(&LF);

 

Invalidate();

UpdateWindow();

}

}

 

void CCommonDlgView::OnCommonOpenfile()

{

// TODO: Add your command handler code here

 

//过滤字符串

char szFileFilter[]=

"Cpp files(*.cpp)|*.cpp|"

"Header files(*.h)|*.h|"

"All files(*.*)|*.*||";

 

CFileDialog dlg(TRUE, //Open对话框

"cpp", //缺省扩展名

"*.cpp",

OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, //文件必须存在

szFileFilter,

this);

 

if(dlg.DoModal()==IDOK)

{

CString str="The full path name is:";

str+=dlg.GetPathName();

AfxMessageBox(str);

}

 

}

 

void CCommonDlgView::OnCommonSavefile()

{

// TODO: Add your command handler code here

 

char szFileFilter[]=

"Cpp files(*.cpp)|*.cpp|"

"Header files(*.h)|*.h|"

"All files(*.*)|*.*||";

 

CFileDialog dlg(FALSE, //Save对话框

"cpp",

"*.cpp",

OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,

szFileFilter,

this);

 

if(dlg.DoModal()==IDOK)

{

CString str="The file name is:";

str+=dlg.GetFileName();

AfxMessageBox(str);

}

 

}

 

 

void CCommonDlgView::OnCommonPrint()

{

// TODO: Add your command handler code here

 

CPrintDialog dlg(FALSE, PD_ALLPAGES); //Print对话框

//设置Print对话框的属性

dlg.m_pd.nCopies=2;

dlg.m_pd.nMinPage=1;

dlg.m_pd.nMaxPage=50;

dlg.m_pd.nFromPage=1;

dlg.m_pd.nToPage=50;

 

if(dlg.DoModal()==IDOK)

DispPrintInfo(dlg);

}

 

void CCommonDlgView::OnCommonPrintsetup()

{

// TODO: Add your command handler code here

 

CPrintDialog dlg(TRUE) //Print Setup对话框

if(dlg.DoModal()==IDOK)

DispPrintInfo(dlg);

}

 

 

void CCommonDlgView::DispPrintInfo(CPrintDialog& dlg)

{

CString str;

CString temp;

 

str+="Driver name:";

str+=dlg.GetDriverName();

str+="\nDevice name:";

str+=dlg.GetDeviceName();

str+="\nPort name:";

str+=dlg.GetPortName();

str+="\nNumber of copies:";

temp.Format("%d",dlg.GetCopies());

str+=temp;

str+="\nCollate:";

str+=dlg.PrintCollate()?"Yes":"No";

str+="\nPrint all:";

str+=dlg.PrintAll()?"Yes":"No";

str+="\nPrint range:";

str+=dlg.PrintRange()?"Yes":"No";

str+="\nSelection:";

str+=dlg.PrintSelection()?"Yes":"No";

str+="\nFrom page:";

temp.Format("%d",dlg.GetFromPage());

str+=temp;

str+="\nTo page:";

temp.Format("%d",dlg.GetToPage());

str+=temp;

 

AfxMessageBox(str);

 

}

 

void CCommonDlgView::OnCommonFind()

{

// TODO: Add your command handler code here

 

//判断是否已存在一个对话框

if(m_pFindReplaceDlg)

{

if(m_bFindOnly)

{

//若Find对话框已打开,则使之成为活动窗口

m_pFindReplaceDlg->SetActiveWindow();

return;

}

else

//关闭Replace对话框

m_pFindReplaceDlg->SendMessage(WM_CLOSE);

}

m_bFindOnly=TRUE;

//创建Find对话框

m_pFindReplaceDlg=new CFindReplaceDialog;

m_pFindReplaceDlg->Create(TRUE,NULL,NULL,FR_DOWN,this);

}

 

void CCommonDlgView::OnCommonReplace()

{

// TODO: Add your command handler code here

 

//判断是否已存在一个对话框

if(m_pFindReplaceDlg)

{

if(!m_bFindOnly)

{

//若Replace对话框已打开,则使之成为活动窗口

m_pFindReplaceDlg->SetActiveWindow();

return;

}

else

//关闭Find对话框

m_pFindReplaceDlg->SendMessage(WM_CLOSE);

}

m_bFindOnly=FALSE;

//创建Replace对话框

m_pFindReplaceDlg=new CFindReplaceDialog;

m_pFindReplaceDlg->Create(FALSE,NULL,NULL,FR_DOWN,this);

 

}

 

 

//Find和Replace对话框通知消息处理函数

LRESULT CCommonDlgView::OnFindReplaceCmd(WPARAM, LPARAM lParam)

{

//判断对话框是否被关闭

if(m_pFindReplaceDlg->IsTerminating())

m_pFindReplaceDlg=NULL;

 

return 0;

}

 

 

让我们先来看看对Color对话框的测试。在CCommonDlgView::OnCommonColor中创建了一个Color对话框,在此处该对话框的用途是为视图中显示的正文指定背景色。在CCommonDlgView的构造函数中将背景色m_BackColor的初值设置为白色(0x00000000)。若DoModal返回IDOK,则调用CColorDialog::GetColor获取用户选择的颜色并将之保存在m_BackColor成员中。然后,调用Invalidate和UpdateWindow函数以重绘视图。这两个函数的说明如下:

void Invalidate( BOOL bErase = TRUE );
该函数的作用是使整个窗口客户区无效。窗口的客户区无效意味着需要重绘,例如,如果一个被其它窗口遮住的窗口变成了前台窗口,那么原来被遮住的部分就是无效的,需要重绘。这时Windows会在应用程序的消息队列中放置WM_PAINT消息。MFC为窗口类提供了WM_PAINT的消息处理函数OnPaint,OnPaint负责重绘窗口。视图类有一些例外,在视图类的OnPaint函数中调用了OnDraw函数,实际的重绘工作由OnDraw来完成。参数bErase为TRUE时,重绘区域内的背景将被擦除,否则,背景将保持不变。

void UpdateWindow( );
该函数的作用是使窗口立即重绘。调用Invalidate等函数后窗口不会立即重绘,这是由于WM_PAINT消息的优先级很低,它需要等消息队列中的其它消息发送完后才能被处理。调用UpdateWindow函数可使WM_PAINT被直接发送到目标窗口,从而导致窗口立即重绘。

 

在CCommonView::OnDraw函数中调用了CDC::SetBkColor来设置背景色。CDC类用于绘图,在后面的几章里将会对其作详细介绍。CDC::TextOut函数用于输出正文。两个函数的说明如下:

virtual COLORREF SetBkColor( COLORREF crColor );
用于设置背景色。参数crColor指定了背景色的RGB值。返回的是原来的背景色。

BOOL TextOut( int x, int y, const CString& str );
在指定的位置输出正文。参数x和y指定了输出起点的横向和纵向坐标。str参数是输出的字符串。若该函数调用成功则返回TRUE。

对文件选择对话框的测试比较简单。在CCommonDlgView::OnCommonOpenfile和CCommonDlgView:OnCommonSavefile函数中,分别创建了一个Open对话框和一个Save对话框。在创建Open对话框时,在CFileDialog的构造函数中规定了OFN_FILEMUSTEXIST属性,这样当用户试图打开一个不存在的文件时,对话框会发出错误信息并让用户从新选择文件。在创建Save对话框时,在CFileDialog的构造函数中规定了OFN_OVERWRITEPROMPT属性,这样,当用户试图覆盖一个已存在的文件时,对话框会询问用户是否真的要覆盖该文件。

若用户确认了对文件的选择,那么在文件选择对话框关闭后,程序会将所选文件的文件名或全路径文件名输出到屏幕上。

 

Find和Replace对话框的创建工作分别由CCommonDlgView::OnCommonFind和CCommonDlgView::OnCommonReplace完成。

在OnCommonFind函数中,首先判断是否已经打开了一个Find/Replace对话框。这个判断是完全必要的,因为Find/Replace对话框是非模态对话框,打开一个对话框后,用户有可能通过菜单再次执行Find或Replace命令。成员m_pFindReplaceDlg是指向CFindReplaceDialog对象的指针,若该指针不为空,则说明对话框已打开。接着,根据成员m_bFindOnly来判断原先打开的是否是Find对话框,如果原先打开的是一个Find对话框,则此时不必创建新的对话框,只需激活已打开的Find对话框就行了;如果原先打开的是一个Replace对话框,则应该先关闭该对话框,然后再创建Find对话框。然后,给m_bFindOnly赋TRUE值,以表明现在打开的是一个Find对话框。最后,创建一个非模态的Find对话框,请注意其过程与创建模态对话框的不同之处:

对话框对象是用new操作符在堆上创建的,而不是以变量的形式创建。

对话框的启动是靠调用Create函数实现的,而不是DoModal函数。

 

调用CWnd::SetActiveWindow以激活窗口。调用CWnd::SendMessage(WM_CLOSE)来关闭窗口,这是因为WM_CLOSE消息会导致CWnd::DestroyWindow函数的调用。

OnCommonReplace函数的过程与OnCommonFind函数类似。在该函数中,对m_bFindOnly赋值FALSE以表明打开的是Replace对话框。

Find/Replace对话框通知消息的处理函数是CCommonDlgView::OnFindReplaceCmd,这个消息处理函数及消息映射均是手工加入的。请注意在CommonDlgView.cpp文件的开头部分定义了一个静态全局变量nMsgFindReplace

 

static const UINT nMsgFindReplace = :: RegisterWindowMessage( FINDMSGSTRING );

nMsgFindReplace变量用于存放消息码,这个消息是由函数RegisterWindowMessage提供的,该函数的声明为

UINT RegisterWindowMessage(LPCTSTR lpString);

参数lpString是一个消息字符串。调用RegisterWindowMessage函数会返回一个Windows注册消息,注册消息的编码在系统中是唯一的。当有多个应用程序需要处理同一个消息时,应调用该函数注册消息。如果消息是本应用程序专有的,则不必注册。如果两个应用程序使用相同的字符串注册消息,则会返回相同的消息,这样,通过该消息,两个应用程序可以进行通信。

注册消息的消息映射宏是ON_REGISTERED_MESSAGE,在CommonDlgView的消息映射中可以找到它。

在函数OnFindReplaceCmd中应该进行实际的搜索和替换工作,但在本例中该函数什么工作也不作。该函数只是判断一下对话框是否被关闭,若是,则给m_pFindReplaceDlg赋NULL值,以表明对话框已不存在了。

 

Font对话框的创建由函数CCommonView:: OnCommonFont完成。该函数收集了用户选择的字体的信息,并利用这些信息创建新的字体。成员m_ForeColor用来保存所选字体的颜色,成员m_Font是一个CFont对象,用来保存用户选择的字体。在CCommonView的构造函数中,m_ForeColor被初始化成黑色(0xFFFFFF),m_Font被初始化为系统字体。系统字体的获得是通过调用CGdiObject::CreateStockObject(SYSTEM_FONT)实现的,该函数用于获得系统库存的绘图对象,包括字体、画笔、刷子、调色板等。

在OnCommonFont函数中,主要调用了下列函数:

调用CFontDialog:: GetCurrentFont以获得用户选择字体的信息,该函数的声明为
void GetCurrentFont( LPLOGFONT lplf );
参数lplf是一个指向LOGFONT结构的指针,LOGFONT结构用来存放与字体有关的信息。

调用CFontDialog::GetColor来获得所选字体的颜色(前景色)。

调用CGdiObject:: DeleteObject()来删除存放在CFont对象m_Font中的老字体。

调用CFont::CreateFontIndirect以创建一种字体,该函数的声明是
BOOL CreateFontIndirect(const LOGFONT* lpLogFont );
参数lpLogFont是一个指向LOGFONT结构的指针,函数根据该结构提供的信息来初始化Cfont对象。

调用CWnd::Invalidate和CWnd::UpdateWindow重绘视图。

 

在CCommonView::OnDraw函数中,利用选择的字体和颜色输出两行正文。当视图需要重绘时,OnDraw就会被调用。在OnDraw函数中主要调用了下列函数:

在输出正文前,调用CDC::SelectObject指定输出正文的字体,输出完成后,调用CDC::SelectObject恢复被替换的字体。SelectObject有五个版本,用于为绘图指定画笔、刷子、字体、位图等绘图对象。在用该函数指定绘图对象时,应该把被替换的对象保存起来,在绘图完成后,需要再次调用该函数恢复被替换的绘图对象。如果不进行恢复,则可能会使设备对象CDC中含有非法的句柄。指定字体的SelectObject函数的声明是
virtual CFont* SelectObject( CFont* pFont );
参数pFont是指向CFont对象的指针。函数返回一个CFont对象的指针,指向被替代的字体。

调用CDC::SetTextColor来指定正文显示的前景色,该函数的声明为
virtual COLORREF SetTextColor( COLORREF crColor );
参数crColor指定了RGB颜色。函数返回的是原来的正文颜色。

调用CDC:: GetTextMetrics函数获得与绘图字体有关的各种信息,该函数的声明为
BOOL GetTextMetrics( LPTEXTMETRIC lpMetrics ) const;
参数lpMetrics是一个指向TEXTMETRIC结构的指针,该结构包含有字体的信息,其中tmHeight成员说明了字体的高度,tmExternalLeading成员说明了行与行之间的空白应该是多少。把这两个值相加就得到了每行正文的高度。

调用CDC::TextOut在指定位置输出正文。

在CCommonDlgView::OnCommonPrint和CCommonDlgView::OnCommonPrintsetup()函数中,分别创建了一个Print对话框和Print Setup对话框。在创建Print对话框时,通过CPrintDialog对象的m_pd成员,对对话框进行了一些初始化,这包括对拷贝份数、打印范围等的设置。在两个对话框DoModal返回IDOK后,均调用CCommonDlgView::DispPrintInfo报告打印信息。DispPrintInfo函数的代码较简单,这里就不作解释了。