接触VC 3:1

 

第三部分:MFC基于对话框程序

 

最近,本人赶时髦,装上了一套Visual Studio.net(不过是盗版,微软挺悲惨的。但如果是正版的话,那悲惨的就不会是微软,而是我了。没钱啊)。安装要2213M呢,硬盘上三个盘符总共剩下不足2G的地方了。不过,界面相当的漂亮,且功能强大,值得心慰。我终于可以在类视图上,尽情去看类的基类,以及基类的实现代码了。不仅如此,最好的是那附带的MSDN上所有的VC基础文章都是中文,翻译的比希望出版社的好得没的说。什么文档啊,框加窗口啊,多视图啊,应有尽有。所以建议大家都来用.net的吧,注意是要那七张盘的同三张的是beta版,VC功能不全的。

这部分该说一说MFC的具体程序了。因为我用的是.net,所以代码可能会与6.0的略有不同,但也无关紧要,不会妨碍整体结构。我也会小心代码兼容性的。

好了,拿起手边的VC吧。跟我一块来看一个基于对话框程序的所有代码吧。

如果是6.0的朋友则首先在菜单上选择新建,在工程(Project)选项卡中选中MFC AppWizard,将工程名(Project name)中起名为Dialog,按确定(OK)。在向导第一步中选择基于对话框(Dialog based),直接按完成(Finish)就可以了。

如果是.net的朋友则在菜单上选择新建->项目,在项目类型中选择Visual C++项目,在模板中选择MFC应用程序,在名称中输入Dialog,按确定。在应用程序类型中选择基于对话框,后按完成。

于是一个基于对话框程序就做好了。第一次使用MFC的朋友,一定会为之喳舌。自己从零开始编程序久了,也许还不习惯别人为咱们生成代码吧。第一映象就是乱,这就是我的同学给我的回答。没关系,我们可以一点一点来看和理解VC给我们生成的代码。毕竟,它为我们节省了很多时间来打WindowSDK框架代码。

请打开类视图(ClassView),如果无误的话,我们可以看到三个类。分别是CAboutDlg, CDialogApp, CDialogDlg这三个类。

其中,CDialogApp是最重要的一个类。双击CDialogApp,打开其定义体。我们会看到它是这么定义的:

class CDialogApp : public CWinApp

我们可以看到这个类是派生于CWinApp的。在MFC编程中,这种情况很多见,继承类库类来添加自己需要的功能,然后再去使用。在MFC应用程序中,CWinApp就是这样使用的。查一查类库关于CWinApp的描述,是这样的:

MFC中的主应用程序类封装用于 Windows 操作系统的应用程序的初始化、运行和终止。基于框架生成的应用程序必须有且仅有一个从 CWinApp 派生的类的对象。在创建窗口之前先构造该对象。

CWinApp 是从 CWinThread 派生的,后者表示可能具有一个或多个线程的应用程序的主执行线程。在最新版本的 MFC 中,InitInstanceRunExitInstance OnIdle 成员函数实际位于 CWinThread 类中。此处将这些函数作为 CWinApp 成员来探讨,因为探讨所关心的是对象作为应用程序对象而不是主线程的角色。

与用于 Windows 操作系统的任何程序一样,框架应用程序也具有 WinMain 函数。但在框架应用程序中不必编写 WinMain。它由类库提供,并在应用程序启动时调用。WinMain 执行注册窗口类等标准服务。然后它调用应用程序对象的成员函数来初始化和运行应用程序。(可通过重写由 WinMain 调用的 CWinApp 成员函数来自定义 WinMain。)

为初始化应用程序,WinMain 调用应用程序对象的 InitApplication InitInstance 成员函数。为运行应用程序的消息循环,WinMain 调用 Run 成员函数。在终止时,WinMain 调用应用程序对象的 ExitInstance 成员函数。

上面这段里指的框架应用程序,包括了我们这种对话框应用程序。如MSDN所说,MFC类库已经为我们提供了WinMain函数,而不必我们添加。这就是为什么在MFC程序看不见主函数的原故。请看这句话“基于框架生成的应用程序必须有且仅有一个从 CWinApp 派生的类的对象。在创建窗口之前先构造该对象。”,打开类视图的全局(Glotbals),会发现有一个theApp全局变量(或对象,我总觉得变量与对象可以归为一类,应该有一个统一的名称来讲)。双击它,就可以看到CDialogApp theApp这样的定义。因为全局变量和对象在程序中是最先被创建的,于是保证了在创建窗口之前构造一个CWinApp对象(因为CDialogApp派生于CWinApp,所以theApp也是一个CWinApp对象)。这个全局对象是非常有用,因为CWinApp本身集成了所有的程序资源WinAPI,我们可以使用它来取得程序的资源(如图标,图像,预定义字符串等等)。一般要取得此全局对象,不直接使用theApp,而是调用::AfxGetApp()来取得这个全局对象的指针。

MFC默认的主函数,会先调用theApp对象的InitApplicationInitInstance成员函数,来进行程序的初始化,在程序中一般只重写InitInstance函数。然后,建立一个消息循环,不同的是在循环不停地调用theAppRun成员函数。当收到WM_QUIT后,退出while循环。最后,执行theAppExitInstance成员函数,从而结束整个应用程序。

让我们在类视图(Class View)中展开CDialogApp(点击那个+符号),我们可以看到CDialogApp重写了InitInstance()函数。它用于对应用程序主线程进行初始化。双击视图中的InitInstance()来查看此函数的定义。我这里的函数定义如下:

000:BOOL CDialogApp::InitInstance()

001:{

002: // 如果一个运行在 Windows XP 上的应用程序代码指定要

003: // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,

004: //则需要 InitCommonControls()。否则,将无法创建窗口。

005: InitCommonControls();

006:

007: CWinApp::InitInstance();         //调用父类的InitInstance来进行默认的初始化

008:

009: AfxEnableControlContainer();

010:

011:

012: CDialogDlg dlg;                  //建立一个对话框对象,CDialogDlg是我们自定义的对话框类

013: m_pMainWnd = &dlg;               //将本线程(即程序主线程)的主窗口设置为这个对话框

014: INT_PTR nResponse = dlg.DoModal();   //有模式地显示这个对话框,直到对话框关闭

015: if (nResponse == IDOK)           //如果对话框是用确定来关闭的,则

016: {

017:     // TODO:在此放置处理用“确定”来关闭

018:     //对话框的代码

019: }

020: else if (nResponse == IDCANCEL)  //如果对话框是用取消来关闭的,则

021: {

022:     // TODO:在此放置处理用“取消”来关闭

023:     //对话框的代码

024: }

025:

026: // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,

027: // 而不是启动应用程序的消息泵。

028: return FALSE;

029:}

因为InitInstance()函数的结束返回值是false,应用程序将会立即退出。也就是只显示对话框,当对话框关闭后,程序就会结束了。这时候的InitInstance函数就有点主函数的味道了。

下面,我们再来看看CDialogDlg类的定义,它是派生于CDialog的。它重写了以下函数

CDialogDlg(CWnd* pParent = NULL);      自定义的构造函数

virtual BOOL OnInitDialog();                  对话框初始化消息操作函数

  afx_msg void OnSysCommand(UINT nID, LPARAM lParam);    系统菜单消息响应函数

  afx_msg void OnPaint();                       对话框重绘响应函数

  afx_msg HCURSOR OnQueryDragIcon();  最小化图标询问响应函数

另外,要注意的是在CDialogDlg类的定义体中有这么一个枚举的定义:

enum { IDD = IDD_DIALOG_DIALOG };

它表明这个CDialogDlg类使用的对话框模板是IDD_DIALOG_DIALOG

CDialogDlg派生层次如下:

CDialogDlg=>CDialog=>CWnd=>CCmdTarget=>CObject

先来看看构造函数:

CDialogDlg::CDialogDlg(CWnd* pParent /*=NULL*/)

     : CDialog(CDialogDlg::IDD/*这个IDD就是那个枚举的值*/, pParent)

{

         m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

在这个函数中首先,调用父类CDialog的构造函数来完成默认构造操作。其次,它使用AfxGetApp函数取得全局CWinApp对象theApp的指针,并使用它的LoadIcon函数来取得程序中IDR_MAINFRAME图标资源,并赋给成员变量m_hIcon。这个图标可以在资源视图的ICON中可以的查到和设定。

CDialogDlg的实现文件CDialogDlg.cpp中,可以找到如下一段语句

BEGIN_MESSAGE_MAP(CDialogDlg, CDialog)

     ON_WM_SYSCOMMAND()

     ON_WM_PAINT()

     ON_WM_QUERYDRAGICON()

     //}}AFX_MSG_MAP

END_MESSAGE_MAP()

这是一段消息映射宏定义段。表示这个对话框类可以响应WM_SYSCOMMAND ,WM_PAINT,WM_QUERYDRAG- ICON消息。它们的响应函数,系统默认分别为OnSysCommand,OnPaint,OnQueryDragIcon。这段的意思是说,如果CDialogDlg类的对话框接收到WM_SYSCOMMAND消息,就会调用OnSysCommand。其它消息以此为例。不过,这些响应段一般是用不着我们自己手动添写的,是由系统来管理的。vk js 你得到一个MFC程序,这一块是一个很好的切入点,可以清楚的看到这个程序到底都可以响应什么消息,都有些什么功能。以上这些宏都可以在MSDN中查到。

接下段

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值