使用VC++的应用程序向导MFC AppWizard可以开发:
Single document(单文档)
Multiple document(多文档)
Dialog based(基于对话框)
单文档(Single Document Interface,SDI)应用程序是指程序运行后出现标准的Windows界面,并且同一时间只能打开一个文档的应用程序。
Windows界面由框架(包括菜单栏、工具栏、状态栏)和客户区组成。
【例1】利用MFC AppWizard[exe]向导生成一个SDI单文档应用程序。
【编程步骤】
(1)点菜单栏File->New->Project,弹出New Project对话框,我们可以选择工程类型。在Project name框中输入项目名称,本例为App15。
(2)设置完成后,单击OK按钮,出现MFC AppWizard-Step 1对话框。在该对话框中选择Single document项,向导将会创建一个单文档应用程序框架。
在本例中,以下的各个步骤使用向导提供的默认选项即可。
利用MFC AppWizard[exe]向导创建应用程序App15的框架后,用户无须添加任何代码,就可以对程序进行编译、连接,生成一个应用程序并且运行。运行结果如下图所示。
MFC应用程序框架实质上是一个标准的Windows应用程序,它具有标准的窗口、菜单栏和工具栏。
MFC AppWizard[exe]向导为一般的SDI应用程序生成了五个核心类,它们分别是:
应用程序类CApp15App
框架窗口类CMainFrame
文档类CApp15Doc
视图类CApp15View
文档模板类CSingleDocTemplate
一般应用程序框架中所有类的名字由MFC AppWizard[exe]向导根据一定的规则自动命名,但用户可以在向导的第6步改变类名和有关类的文件名。
除了框架窗口类CMainFrame和文档模板类CSingleDocTemplate,应用程序框架中类的命名一般遵照如下规则:
Class Name = C + ProjectName + ClassType
应用程序框架是生成一般的应用程序所必需的各种组件的集成,是类库的一种超集。应用程序框架可以调用成百上千个不同的类,但是核心类只有上述五个。
它们的MFC基类分别是:应用程序类CWinApp、框架窗口类CFrameWnd、文档类CDocument、视图类CView以及文档模板类CDocTemplate。
(1)应用程序类CApp15App
CApp15App类是MFC的CWinApp类的派生类。它的主要功能有:
应用程序的初始化
程序的启动
程序运行结束时的清理工作
应用程序对象theApp是一个唯一的全局变量,它的主要功能是通过调用WinMain()主函数启动程序的运行。
(2)框架窗口类CMainFrame
CMainFrame类是MFC的CFrameWnd类的派生类。它主要负责创建标题栏、菜单栏、工具栏和状态栏。对于不同的SDI应用程序,框架窗口类名均为CMainFrame。
CMainFrame类中声明了框架窗口中的菜单m_wndMenuBar、工具栏m_wndToolBar、状态栏m_wndStatusBar等成员变量和若干成员函数。
(3)文档类CApp15Doc
类CApp15Doc是MFC的CDocument类的派生类,它用于管理和维护数据,包括应用程序数据的保存和装载,即实现文档的序列化。
(4)视图类CApp15View
类CApp15View是MFC的CView类的派生类,它主要负责客户区文档数据的显示,以及如何进行人机交互。
(5)文档模板类CSingleDocTemplate
框架窗口对象、文档对象、视图对象如何联系在一起为一个应用程序服务呢?
文档、视图、框架类和所涉及的资源形成了一种固定的联系,这种固定的联系就称为文档模板。也就是说,文档模板描述了相对应每一种类型文档的视图和窗口的风格类型。
上述五个SDI应用程序核心类的MFC基类的类层次关系如图所示。
一般的应用开发都会涉及到数据处理。为了统一和简化数据处理,基于MFC的应用程序通常采用文档/视图结构。
在MFC文档/视图结构中,有关数据处理的工作可以分为数据的处理和数据的显示两个部分。
文档负责数据的处理、数据的维护以及数据的存储;
视图则负责数据的显示和数据的编辑,客户区消息的响应和处理等工作,即充当了文档与用户之间的交互界面。
文档(document)是MFC应用程序中所处理数据的集合,包括文本、图形、图像和表格等类型。
视图(view)是文档在应用程序窗口中的一个映像。视图就如一个观景器,用户通过视图看到文档,通过视图修改文档。
一个视图是一个没有边框的窗口,它位于主框架窗口中的客户区。视图是文档对外显示的窗口,但它并不能完全独立,它必须依存在一个框架窗口内。
文档、视图、框架类和所涉及的资源形成了一种固定的联系,这种固定的联系就称为文档模板。也就是说,文档模板描述了对应每一种类型文档的视图和窗口的风格类型。
当打开某种类型的文件时,应用程序必须确定哪一种文档模板用于解释这种文件。在初始化程序时,必须首先注册文档模板,以便程序利用这个模板来完成主框架窗口、视图、文档对象的创建和资源的装入。
BOOL CMyTextOutApp::InitInstance()
{
…
CSingleDocTemplate* pDocTemplate; //声明文档模板指针
pDocTemplate = new CSingleDocTemplate( //创建文档模板对象
IDR_MAINFRAME, //文档模板使用的资源ID
RUNTIME_CLASS(CApp15Doc), //创建文档对象
RUNTIME_CLASS(CMainFrame), // 创建主SDI框架窗口对象
RUNTIME_CLASS(CApp15View)); //创建视图对象
AddDocTemplate(pDocTemplate); //将文档模板加入文档模板链表
…
}
以【例1】的单文档应用程序App15为基础,添加代码实现文本输出。
程序运行后在视图窗口显示文本串“这是第一个单文档应用程序!”。
【编程步骤】
(1)本例需要在视图类的成员函数OnDraw()中添加显示文本的代码来实现屏幕输出。
打开类视图窗口,找到CApp15View类,展开该类,双击其成员函数OnDraw(),在编辑窗口出现该成员函数代码,在指定位置手工添加如下代码。
GetDocument()是视图类的成员函数,调用它可以返回与视图相关联的文档对象的指针,利用这个指针可以访问文档类及其派生类的公有成员。通常的用法如下:
CMyTextOutDoc* pDoc = GetDocument();
TextOut()是CDC类的成员函数。其功能是在指定的位置输出文本串。函数原型如下:
CDC: TextOut( int x, int y, const CString& str )
其中参数x,y指定文本输出位置坐标。
参数str指定输出内容。
ASSERT_VALID()是MFC库中的断言 。ASSERT_VALID()的用法是:
ASSERT_VALID(一个从CObject类派生的类对象指针)
功能:用于对C++对象或指针进行有效性判断,如果出错,会弹出带断言信息(程序,模块, assertion行)的对话框。对话框有3个按钮:“Break”,“Repeat”(“Debug”), 和“Continue”(“Ignore”)。“Break”结束程序,“Continue”忽略断言,最有用的是“Repeat”按钮。按下它会在断言的地方打开源代码编辑器. 在这里可以测试相关的变量值并找出问题所在。
编译连接程序,程序运行后将在程序视图区域显示文本串。程序运行结果如图所示。
在Windows中,凡绘图操作之前一定要先获得一个DC(Device Context)。DC是一种包含设备信息的数据结构,它可能代表全部屏幕,也可能代表一个窗口。DC包含了物理设备所需的各种状态信息。
DC实际上是一个关于如何绘制图形的方法的集合。它可以确立在应用窗口中绘制图形的方式,包括坐标系统(映射模式)、绘图工具(如画笔、画刷、颜色)等等。
当应用程序需要在某个图形设备上绘图时,首先要获取绘图窗口区域的一个设备环境DC,之后才能选取合适的绘图工具进行绘图工作。
为了方便图形绘制,Windows把与绘图相关的操作都制作成函数,这些函数的集合称为图形设备接口(graphical device interface,GDI)。
GDI提供了各种绘图函数,例如GDI中有绘制矩形的函数Rectangle()、绘制文本的函数DrawText()等。GDI还提供了一套绘图工具,如Pen(画笔)、Brush(画刷)、Font(字体)等。
由于在Windows屏幕上看到的所有内容都是图形,所以在应用窗口中每次进行显示和编辑操作时,都必须调用特定的GDI函数。
MFC将DC和GDI函数封装到一起形成了两种重要的图形处理的类:
设备环境类(CDC类),用于访问设备属性、设置绘图属性和绘制图形;
绘图对象类,封装了各种GDI绘图对象,包括画笔、画刷、字体、位图、调色板和区域。
MFC中,设备环境DC是由CDC类对象来表示的,并且可以调用CDC类的成员函数来完成各种各样的绘图操作,它提供了170多个成员函数。
设备环境描述类
CDC类是CObject的直接派生类,CDC类除了作为通用的设备环境类来使用,还派生了几种特定的设备环境描述类,包括:
CClientDC类
CPaintDC类
CMetaFileDC类
CWindowDC类
当用户改变了应用程序窗口的大小,或者当窗口恢复了先前被覆盖的部分,应用程序窗口都会收到Windows发来的WM_PAINT消息,
然后应用程序框架自动调用视图类CView的成员函数OnPaint()或程序员添加的函数OnPaint()来处理WM_PAINT消息,
在OnPaint()函数中重绘窗口中需要恢复的部分图形,更简单的方法是重绘整个窗口。
CPaintDC类
CPaintDC类是OnPaint()函数使用的设备环境类,它代表一个窗口的绘图画面。
如果添加WM_PAINT的消息处理函数OnPaint(),就需要使用CPaintDC类来定义一个设备环境对象。
在CView类的成员函数OnPaint()中就这样定义了一个设备环境对象。
void CView::OnPaint()
{
//standard paint routine
CPaintDC paintDC; //定义一个设备环境对象paintDC
OnPrepareDC(&paintDC);
OnDraw(&paintDC);
}
OnDraw()函数
由于基类CView的OnPaint()函数调用了OnDraw()函数,因此编程时经常在OnDraw()函数中绘制图形。
OnDraw()函数的声明为:
OnDraw(CDC *pDC);
这个函数的参数pDC就是指向CPaintDC类对象的指针,在OnDraw()函数中可以使用CDC类的成员函数对这个对象进行绘图操作。
GDI坐标系和映射模式
GDI支持两种类型的坐标系:
逻辑坐标系:一般GDI的文本和图形输出函数使用的是逻辑坐标。
设备坐标系:在客户区移动或按下鼠标所得到的鼠标位置使用的是设备坐标。
逻辑坐标系是面向设备环境DC的坐标系,这种坐标不考虑具体的设备类型,但在实际绘图时GDI会根据当前设置的映射模式将逻辑坐标转换为设备坐标。
映射模式规定了逻辑单位的实际大小、坐标轴的正方向,所有的映射模式的坐标原点都设在设备输出区域(如客户区或打印区)的左上角。
GDI定义了8种映射模式。使用映射模式使得程序员不必考虑输出设备的设备坐标系,只需在一个统一的逻辑坐标系中进行图形的绘制。
SetMapMode()设置映射模式
例如:dc.SetMapMode(MM_LOMETRIC);
GetMapMode()获得当前映射模式
在MFC开发中经常会使用GDI来输出文本或图形图像。
文本实际上就是一种特殊的图形,它只不过是根据事先指定的“字体”绘制出来的图形。
字体通常用来为字符集中每一个字符,如字母、数字、标点符号等,指定其形状等外表特征。
窗口创建后,如果没有专门指定,一般会采用系统字体作为默认字体。我们可以使用API函数GetStockObject(SYSTEM_FONT)获得系统字体的句柄。
CFont类封装了一个Windows图形设备接口(GDI)字体,并为操作字体提供了成员函数。
首先要构造一个CFont对象,通过调用CreateFont、CreateFontIndirect、CreatePointFont或CreatePointFontIndirect将一个Windows字体与此CFont对象关联,然后使用此CFont对象的成员函数就可以操作字体了。
1、CFont( )
构造一个CFont对象。此对象在使用之前应该先使用CreateFont、CreateFontIndirect、CreatePointFont或CreatePointFontIndirect初始化。
BOOL CreateFont(
int nHeight,
int nWidth,
int nEscapement,
int nOrientation,
int nWeight,
BYTE bItalic,
BYTE bUnderline,
BYTE cStrikeOut,
BYTE nCharSet,
BYTE nOutPrecision,
BYTE nClipPrecision,
BYTE nQuality,
BYTE nPitchAndFamily,
LPCTSTR lpszFacename );
CreateFont函数初始化CFont对象后,就能够使用CDC::SelectObject函数来为设备上下文选择字体了,并且还能够在不再使用此CFont对象时删除它。
此函数并不会创建一个新的Windows GDI字体,只是从GDI的物理字体中选择了一个最匹配的字体。
CFont font;
font.CreateFont(0, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, _T(“Times New Roman”));
3、BOOL CreateFontIndirect(const LOGFONT* lpLogFont);
通过一个LOGFONT结构体变量给出的特征来初始化CFont对象。参数lpLogFont是指向LOGFONT结构体变量的指针,此LOGFONT结构体变定义了逻辑字体的特征。
4、int GetLogFont(LOGFONT * pLogFont);
获取CFont对象的LOGFONT结构体的拷贝。参数pLogFont指向用来接收字体信息的LOGFONT结构体变量。成功则返回非零值,否则返回零。
CFont font ;
LOGFONT lf;
::ZeroMemory(&lf, sizeof(lf));
lf.lfHeight = 120;
lf.lfWeight = FW_BOLD;
lf.lfItalic = TRUE;
font.CreateFontIndirect(&lf);
ZeroMemory是美国微软公司的软件开发包SDK中的一个宏。 其作用是用0来填充一块内存区域。
5、BOOL CreatePointFont(int nPointSize,LPCTSTR lpszFaceName,CDC* pDC = NULL);
此函数提供了一种由指定字样和点数创建字体的简单方式。参数的意义如下:
nPointSize:指定字体高度,以十分之一点为单位。例如,nPointSize为120则表示是12点的字体。
lpszFacename:指定字体的字样名的字符串。此字符串的长度不应超过30个字符。
Windows函数EnumFontFamilies可以枚举出当前所有可用字体的字样名。
执行文本输出操作
使用设备上下文类CDC的成员函数TextOut来输出,CDC::TextOut函数的两种重载形式如下:
virtual BOOL TextOut(int x,int y,LPCTSTR lpszString,int nCount);BOOL TextOut(int x,int y,const CString& str);
参数x指定文本起始点的x坐标;参数y指定文本起始点的y坐标;参数lpszString为要输出的文本字符串;参数nCount指定字符串中的字节个数;参数str为包含要输出的字符的CString对象。
设计两个变量:
CFont newFont; // 新字体
CFont *pOldFont; // 选择新字体之前的字体newFont.CreatePointFont(180, _T("隶书"));
// 创建一种新的字体(18点,隶书)
pOldFont = (CFont*)dc.SelectObject(&newFont);
SelectObject()函数的功能是,选择一对象到指定的设备环境中,该新对象替换先前的相同类型的对象。函数原型是:
HGDIOBJ SelectObject(HGDIOBJ hgdiobj)
参数hgdiobj指的是被选择的对象的句柄。
返回值:如果函数执行成功,那么返回值是被取代的对象的句柄。否则返回NULL。
当应用程序需要使用用户自己定制的Windows GDI对象时,首先要将其选入设备环境。MFC的CDC类提供了成员函数SelectObject()用于将用户自己创建的GDI对象选入设备环境。
void CApp15View::OnDraw(CDC* pDC)
{
CApp15Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc) return;
CFont newFont; // 新字体
CFont *pOldFont; // 选择新字体之前的字体
newFont.CreatePointFont(180, _T("隶书")); // 创建一种新的字体
pOldFont=(CFont*)pDC->SelectObject(&newFont);
// 在指定位置输出文本
pDC->TextOut(40,10,_T("你好!"));
// 恢复以前的字体
pDC->SelectObject(pOldFont);
pDC->TextOut(50,50, _T("这是我的第一个单文档应用程序!"));
}
void CApp15View::OnDraw(CDC* pDC)
{
CApp15Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc) return;
CFont newFont; // 新字体
CFont *pOldFont; // 选择新字体之前的字体
newFont.CreatePointFont(180, _T("隶书")); // 创建一种新的字体
pOldFont=(CFont*)pDC->SelectObject(&newFont);
// 设置文本颜色为红色
pDC->SetTextColor(RGB(255,0,0));
// 在指定位置输出文本
pDC->TextOut(40,10,_T("你好!"));
// 设置文本颜色为绿色
pDC->SetTextColor(RGB(0,255,0));
// 在指定位置输出文本
pDC->TextOut(10,80, _T("学习总是有收获的"));
// 恢复以前的字体
pDC->SelectObject(pOldFont);
pDC->TextOut(50,50, _T("这是我的第一个单文档应用程序!"));
}
COLORREF是一个32bit整型数值,代表了一种颜色,其格式为0x00bbggrr,其中bb、gg和rr分别代表蓝、绿和红颜色的分量,每种颜色分量的取值范围为0~255。
通常使用RGB函数来初始化COLORREF类型数据。其使用形式是:
RGB(byRed,byGreen,byBlue)
其中参数byRed、byGreen和byBlue分别表示红、绿、蓝分量值。
改进【例1】的单文档应用程序,程序运行后使用菜单命令,调用字体对话框,设置字体字号等。
为了方便灵活地使用字体,Windows提供了一个通用字体对话框,应用程序可以使用它来选择不同的字体,设置字号和字体颜色等。该对话框的MFC类是CFontDialog类。
MFC使用CFontDialog类封装了字体对话框的所有操作。字体对话框也是一种模态对话框。
【编程步骤】
(1)建立菜单资源。在向导生成的程序框架中修改菜单资源,添加“文本”|“设置字体”菜单。
在ResourceView中找到IDR_MAINFRAME资源,双击之,在显示出来的主菜单项最后的虚线空白框处双击,在弹出的properties对话框中填写Caption项为“文本(&T)”,可以看到主菜单最后一个菜单项即为“文本”,字符“&”用于在显示字母“T”时加下划线,表示该菜单命令的快捷键是“Alt+T”。
接着为主菜单添加菜单项。在“文本”菜单下面的虚线空白框处双击,在弹出的properties对话框中填写Caption项为“设置字体”,在ID框中填写此菜单项的ID_FONTDLG_MENU。
在Prompt文本框中输入状态栏提示语“使用字体对话框设置字体”。如图所示。
(2) 添加菜单项命令处理函数。
在菜单项“字体对话框”上右击鼠标,在快捷菜单上点击“添加事件处理程序”,在弹出的对话框“事件处理程序向导”中,“类列表”选择视图类CApp15View,在“消息类型”列表框中选择COMMAND,单击“添加编辑”按钮,为“字体对话框”菜单项添加命令处理函数CApp15View::OnFontdlgMenu()
。该函数名是自动生成的。如图所示。
(3)在视图类中添加字体和字体颜色成员变量。
CFont m_font; //用户所选择的字体
COLORREF m_TextColor; //用户所选择的字体颜色
(4)编写“设置字体”菜单项的响应函数。
void CApp15View::OnFontdlgMenu()
{ // TODO: 在此添加命令处理程序代码
CFontDialog dlgFont; //通用字体对话框
if(dlgFont.DoModal() == IDOK)
{
LOGFONT LogFnt;
m_font.DeleteObject();
// 使用选定字体的LOGFONT创建新的字体
dlgFont.GetCurrentFont(&LogFnt);
m_font.CreateFontIndirect(&LogFnt);
m_TextColor = dlgFont.GetColor();
Invalidate(FALSE);
}
}
创建字体必须使用CFont类的成员函数。利用CFont创建字体的方法之一是:
BOOL CreateFontIndirect(const LOGFONT* lpLogFont )
该对象通过LOGFONT结构创建字体,LOGFONT结构的定义如下。
typedef struct tagLOGFONT {
LONG lfHeight;
LONG lfWidth;
LONG lfEscapement;
LONG lfOrientation;
LONG lfWeight;
BYTE lfItalic;
BYTE lfUnderline;
BYTE lfStrikeOut;
BYTE lfCharSet;
BYTE lfOutPrecision;
BYTE lfClipPrecision;
BYTE lfQuality;
BYTE lfPitchAndFamily;
TCHAR lfFaceName[LF_FACESIZE];
} LOGFONT;
当不再使用选入的GDI对象时需要释放该GDI对象。使用CDC类的方法DeleteObject将设备环境中的GDI对象删除。
m_font.DeleteObject();
为什么在CApp15View::OnFontdlgMenu()中要使用DeleteObject删除m_font关联的对象资源?
因为m_font对象原来已与某种字体资源相关联,现在m_font又试图与新字体资源相关联时,就会出错。而使用DeleteObject(),切断这种关联,释放该字体资源,再与新资源相关联就没有问题了。
Invalidate()是强制系统进行重画,但是不一定就马上进行重画。因为Invalidate()只是通知系统,此时的窗口已经变为无效。强制系统调用WM_PAINT,而这个消息只是Post就是将该消息放入消息队列。当执行到WM_PAINT消息时才会对敞口进行重绘。
UpdateWindow()只向窗体发送WM_PAINT消息,在发送之前判断GetUpdateRect(hWnd,NULL,TRUE)看有无可绘制的客户区域,如果没有,则不发送WM_PAINT。
RedrawWindow()则是具有Invalidate()和UpdateWindow()的双特性。声明窗口的状态为无效,并立即更新窗口,立即调用WM_PAINT消息处理。
(5)修改OnDraw()函数。在OnDraw()函数里设置字体、字体颜色并输出文本。
void App15View::OnDraw(CDC* pDC)
{
CApp15Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
CFont *pfntOld=(CFont*)pDC ->SelectObject(&m_font); //设置字体
pDC->SetTextColor(m_TextColor); //设置字体颜色
pDC->TextOut(40,10,_T("你好!"));
pDC->TextOut(10,80,_T("学习总是有收获的"));
pDC->TextOut(50,50,"这是我的第一个单文档应用程序!");
pDC->SelectObject(pfntOld); //恢复以前的字体
}
添加自定义对话框
【例2】程序运行后使用菜单命令,调用自定义对话框输入要在客户区显示的文本内容和坐标位置,在视图区按照所给的坐标位置显示文本。
【编程步骤】
(1)在“文本”下添加一个新的菜单项“显示文本”。修改属性。提示语“在视图区给定位置显示输入的文本内容”。添加消息处理函数。
(2)添加新的对话框资源,ID为IDD_TEXT_DIALOG 。Caption为“输入显示文本和位置”。
(3)在对话框上放置静态控件、编辑框控件和按钮控件。修改三个编辑框的ID,使之分别为IDC_EDIT_TEXT、IDC_TEXT_X、IDC_TEXT_Y。为编辑框IDC_EDIT_TEXT勾选“Multiline(多行)”、“Vertical Scroll(垂直滚动条)”、“Want return”选项。如图所示。
(4)为对话框资源创建对应的对话框类 CTextDialog。向导为该类自动生成两个文件TextDialog.h和TextDialog.cpp。
(5)为三个编辑框控件添加成员变量m_strText、m_nX、m_nY。如图所示。
(6)建立文本对话框与视图类的关联。
下面在视图类中加入与上述控件变量对应的三个成员变量,即在文件App15View.h中加入如下代码。
class CApp15View : public CView
{
protected: // 仅从序列化创建
CEx16_1View();
DECLARE_DYNCREATE(CEx16_1View)
// 特性
CFont m_font; //用户所选择的字体
COLORREF m_TextColor; //用户所选择的字体颜色
int m_nX;
int m_nY;
CString m_strText;
(7)在App15View.cpp文件中编写菜单命令响应函数CApp15View::OnShowtextMenu()的代码。
注意: 在文件开始处加入:#include “TextDialog.h”
void CApp15View::OnShowtextMenu()
{
// TODO: 在此添加命令处理程序代码
CTextDialog tdlg; //定义一个对话框对象
if(tdlg.DoModal()==IDOK) //显示对话框
{
m_nX=tdlg.m_nX;
m_nY=tdlg.m_nY;
m_strText=tdlg.m_strText;
}
Invalidate(FALSE);
}
将文本对话框的成员变量值赋给视图类的相应的成员变量m_strText, m_nTextX, m_nTextY,视图类已经获得了对话框控件上的数据,怎么将其显示在客户区呢?
这时需要调用视图类CDrawView的方法OnDraw(),该方法负责数据在客户区的显示。
(8)修改App15View.cpp中OnDraw()函数的代码,将原来的
pDC->TextOut(50,50,“这是我的第一个单文档应用程序!”);
替换为:
pDC->TextOut(m_nX,m_nY,m_strText);
编译、连接并运行程序后,单击菜单命令,在对话框中输入相应的内容,其运行结果如图所示。