MFC编程框架总结

简介

  MFC是一种C++类库,利用面向对象的方法封装了Windows API,为Windows应用程序的开发带来了极大便利。本文总结了使用MFC进行编程的基本方法,编程环境为VS2008 SP1。

搭建MFC开发环境

  由于使用MFC应用程序向导后VS会自动生成应用程序框架,因而本文先利用VS生成一个空项目,然后在此基础上一步步编写应用程序。
  打开VS2008,从菜单中依次打开文件->新建->项目,弹出新建项目对话框,在左侧的项目类型中选择Visual C++->Win32,在右侧的模板中选择Win32 项目,并填写项目名称及路径,本文的项目名称为Hello,如下图所示。
MFC编程框架总结_第1张图片
  点击确定按钮,进入Win32应用程序向导对话框,点击下一步
MFC编程框架总结_第2张图片
  应用程序类型选择Windows应用程序附加选项选择空项目,点击完成
MFC编程框架总结_第3张图片
  现在已经生成了一个Win32空项目,然后鼠标右键单击左侧工作空间窗口中的Hello项目,选择属性。在弹出的属性配置对话框中,打开配置属性->常规,将MFC的使用使用标准Windows库改为在共享DLL中使用MFC,然后点击确定按钮。
MFC编程框架总结_第4张图片
  配置好该项属性后,项目就可以支持MFC类库了。

定义MFC应用程序对象

  开发MFC应用程序的首要任务是定义一个基于CWinApp类的应用程序对象。由于MFC已经对WinMain函数进行了封装,所以无需在程序中提供WinMain函数,而是采用对象来抽象表示应用程序,一个MFC应用程序有且仅有一个应用程序对象。
  鼠标右键单击左侧工作空间窗口中的Hello项目,依次选择添加->类,在弹出的对话框中选择C++类,点击添加按钮。
MFC编程框架总结_第5张图片
  在弹出的一般C++类向导对话框中填写应用程序对象的相关信息,本文将类名定义为CMyApp,基类一项填写CWinApp,其他项保持默认即可。
MFC编程框架总结_第6张图片
  点击完成按钮,会提示项目中未找到基类"CWinApp",点击跳过即可。
MFC编程框架总结_第7张图片
  为了解决提示中描述的问题,打开MyApp.h,添加#include 语句,即可将CWinApp以及其他MFC类引入应用程序中,并在CMyApp类的定义中添加InitInstance函数的声明。

#pragma once

#include 

class CMyApp : public CWinApp
{
public:
    CMyApp(void);
    ~CMyApp(void);

    virtual BOOL InitInstance();
};

  InitInstance函数的主要作用是为应用程序创建一个窗口。窗口是Windows应用程序的核心,是实现人机交互的重要接口。与应用程序对象相同,MFC使用CWnd类及其派生类对窗口进行抽象表示。在创建应用程序的过程中,有两个比较重要的窗口类,即CWndCFrameWnd。前者是所有窗口类的基类,后者是从前者派生而来,被称为框架窗口,框架窗口在文档/视图体系结构中起着重要作用。
  接下来打开MyApp.cpp,定义一个CMyApp类的对象代表应用程序,程序开始执行时该对象即在内存中实例化。

#include "MyApp.h"

// 应用程序对象
CMyApp myApp;

CMyApp::CMyApp(void)
{
}

CMyApp::~CMyApp(void)
{
}

创建框架窗口

  首先用同样的方法添加窗口类,右键单击左侧工作空间窗口中的Hello项目,依次选择添加->类,在弹出的对话框中选择C++类,点击添加按钮。弹出一般C++类向导对话框,类名填写CMainWindow,基类填写CFrameWnd,其他项保持默认即可。然后点击完成按钮,会提示项目中未找到基类"CFrameWnd",点击跳过即可。同样地,打开MainWindow.h,添加#include 语句,即可解决提示中出现的问题。
  通过生成窗口对象并调用其CreateCreateEx函数,MFC应用程序可以创建一个窗口。打开MainWindow.cpp,在CMainWindow类的构造函数中添加Create函数。

CMainWindow::CMainWindow(void)
{
    Create(NULL, _T("The Hello Application"));
}

  然后打开MyApp.cpp,包含MainWindow.h头文件并添加InitInstance函数的定义。

#include "MainWindow.h"

BOOL CMyApp::InitInstance()
{
    m_pMainWnd = new CMainWindow;
    m_pMainWnd->ShowWindow(m_nCmdShow);
    m_pMainWnd->UpdateWindow();

    return TRUE;
}

  其中,m_pMainWnd是指向CWnd类型的指针。该变量是由MFC定义的,指向应用程序的主窗口。ShowWindow函数的作用是显示窗口,其参数m_nCmdShowCWinApp类的成员变量。m_nCmdShow用于指定窗口的状态。通常情况下,m_nCmdShow的值为SW_SHOWNORMAL,即正常状态。UpdateWindow可以使窗口立即重新绘制。
  点击启动调试运行程序,可以看到一个标题为The Hello Application的空白窗口。
MFC编程框架总结_第8张图片

添加消息处理函数

  与过程化模型不同,Windows使用的是事件驱动编程模型,应用程序通过处理操作系统发送来的消息响应事件。以WM_PAINT消息为例,程序启动时会触发该消息用以绘制窗口,这时可以通过其对应的消息处理函数OnPaint对该消息进行处理。
  首先打开MainWindow.cpp添加消息映射及相应的命令响应函数。

BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
    ON_WM_PAINT()
END_MESSAGE_MAP()

void CMainWindow::OnPaint()
{
    CPaintDC dc(this);

    CRect rect;
    GetClientRect(&rect);

    dc.DrawText(_T("Hello, MFC"), -1, &rect,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}

  该函数用于在窗口中输出Hello, MFC。然后在MainWindow.h中为消息处理函数添加声明。

protected:
    afx_msg void OnPaint();

    DECLARE_MESSAGE_MAP()

  重新点击启动调试运行程序,可以看到窗口中心输出了Hello, MFC
MFC编程框架总结_第9张图片

创建普通窗口

  以上步骤阐述了框架窗口的使用,接下来将基于普通窗口创建应用程序。首先打开MainWindow.h,将基类CFrameWnd改为CWnd
  然后打开MainWindow.cpp,将BEGIN_MESSAGE_MAP宏中的基类改为CWnd,同时修改CMainWindow类的构造函数。

CMainWindow::CMainWindow(void)
{
    // 注册WNDCLASS
    CString strWndClass = AfxRegisterWndClass(
        CS_HREDRAW | CS_VREDRAW,
        AfxGetApp()->LoadStandardCursor(IDC_ARROW),
        (HBRUSH)(COLOR_WINDOW + 1),
        AfxGetApp()->LoadStandardIcon(IDI_WINLOGO));

    // 创建窗口
    CreateEx(0, strWndClass, _T("The Hello Application"),
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL);

    // 调整窗口大小
    CRect rect(0, 0, 352, 352);
    CalcWindowRect(&rect);
    SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(),
        SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW);
}

  可以看到,CMainWindow类的构造函数首先使用AfxRegisterWndClass函数注册了WNDCLASS。如果窗口类是从CFrameWnd派生的,并且将CFrameWnd::Create函数的第一个参数指定为NULL,MFC会完成WNDCLASS的注册。然而从CWnd派生窗口类时,需要自己注册WNDCLASSAfxRegisterWndClass函数的原型如下:

LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,
    HCURSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0);

  第一个参数nClassStyle指定了类样式,定义了窗口的某种操作特性。宏CS_HREDRAWCS_VREDRAW分别表示窗口被水平与垂直缩放时使整个客户区无效。第二个参数hCursor指定了该窗口中显示的光标形状。AfxGetApp函数用于获取当前应用程序对象的指针,其返回类型为CWinApp*CWinApp::LoadStandardCursor函数可以加载系统预定义的光标类型,IDC_ARROW代表标准箭头光标。第三个参数hbrBackground定义了窗口的默认背景色。(HBRUSH)(COLOR_WINDOW + 1)定义了白色背景。hIcon指定了Windows在桌面上、任务栏和其他地方代表应用程序的图标句柄。CWinApp::LoadStandardIcon函数用于加载预定义的系统图标。IDI_WINLOGO表示一个普通的应用程序图标。
  注册了WNDCLASS之后,就可以调用CWnd::CreateEx函数创建主窗口。第一个参数指定窗口扩展样式,第二个参数是AfxRegisterWndClass函数返回的WNDCLASS名称,第三个参数是窗口标题,第四个参数是窗口样式,接下来的四个参数指定了窗口的初始位置和大小,最后两个参数指定父窗口和菜单。
  CalcWindowRect函数根据参数rect计算窗口的尺寸,rect代表所希望的窗口客户区的尺寸。SetWindowPos函数使尺寸设置生效。
  从CWnd派生窗口类时,必须自己删除窗口对象。窗口在被销毁之前将收到最后一个消息WM_NCDESTROYCWnd类包括一个默认的OnNcDestroy函数,该函数首先执行一些清除任务,接着将调用PostNcDestroy函数。CFrameWnd类覆盖了PostNcDestroy函数并执行一个delete this语句删除自身。然而,CWnd类中的PostNcDestroy函数并不执行delete this语句,因而从CWnd派生窗口类时应该提供自己的PostNcDestroy函数。打开MainWindow.cpp,加入PostNcDestroy函数。

void CMainWindow::PostNcDestroy()
{
    delete this;
    CWnd::PostNcDestroy();
}

  然后打开MainWindow.h,加入该函数的声明。

virtual void PostNcDestroy();

  再次点击启动调试运行程序,可以看到一个尺寸较小的程序窗口。
MFC编程框架总结_第10张图片

你可能感兴趣的:(MFC)