MFC—使用MFC创建窗口

头文件

/*
	
	MFC是一个封装了WindowsAPI且面向对象的C++类库,同时也是一个应用程序的框架结构。另外,并非所有MFC提供的函数都是类的成员,MFC也以
	全局函数的形式,为用户提供了各类前缀为Afx的函数,可供用户在必要时随时随地进行调用。
		
	由MFC创建的应用,我们不能够直接看到其程序的入口。入口函数AfxWinMain()被MFC深深的封装在其框架之中,最后直接由编译器编入应用程序。
	因此,我们必须站在面向对象这个巨人的肩膀(高度)上,来分析、审视由MFC创建的Windows应用。
	
	由MFC创建的应用其宏观执行的大致流程为:
	1、在进入程序入口函数AfxWinMain()前,首先在全局范围内创建一个应用程序对象,即由CWinApp或其子类创建的对象。
	2、在入口函数中调用应用程序对象的InitInstance()成员函数。
	3、由InitInstance()负责创建窗口、显示窗口并向窗口发送第一个WM_PAINT消息。	
	4、最后,由入口函数调用应用程序对象的成员函数Run()启动消息循环,然后程序在消息循环中不断收取并响应(处理)属于自己的消息。
	
	Windows的C++程序员习惯把类的定义放在.h文件中,把类的实现或程序的其它源代码放在.cpp文件中。我们这里也遵从这个习惯。
	
*/
#pragma once //在头文件开始处加入这条杂注,可保证头文件只被编译一次。

//这里的“afxwin.h”是用MFC创建窗口应用需要包含的头文件。
#include <afxwin.h>

//下面我们来讨论应用程序对象与框架(顶层)窗口对象的类定义。

/*
	这里的CMyApp是从CWinApp继承而来(CWinApp->CWinThread->CCmdTarget->CObject,大多数MFC的类都直接或间接派生于CObject),其实例代表
	上述的应用程序对象。

	我们只需要覆盖CWinApp中的InitInstance()成员函数即可。上以述及,这个函数完成了应用窗口的创建、显示并向窗口发送WM_PAINT消息的功能。
*/
class CMyApp : public CWinApp {
public:
	virtual BOOL InitInstance();
};


//这里的CMainWindow是从CFrameWnd继承而来(CFrameWnd->CWnd->CCmdTarget->CObject),其实例代表应用程序框架(顶层)窗口对象。
class CMainWindow : public CFrameWnd {
public:
	CMainWindow(); //这是CMainWindow的构造函数。
protected:
	afx_msg void OnPaint(); //这是响应WM_PAINT消息的处理程序(我们用afx_msg来标识消息处理程序)。
	DECLARE_MESSAGE_MAP() //这是定义消息映射的宏,只要应用中需要进行消息映射,就必须有这个宏定义。
};

源文件

/*
	这里是应用的原程序文件Hello.cpp。
	
	下面我们来讨论应用程序对象与框架(顶层)窗口对象的类的实现代码(源程序)。
	
	首先将应用的头文件"Hello.h"包含进来。然后创建一个全局范围的应用程序对象myApp。
*/
#include "Hello.h"

CMyApp myApp;

//这是CMyApp的InitInstance()成员函数的实现代码,其中的m_pMainWnd与m_nCmdShow为从其父类继承过来的两个数据成员。
BOOL CMyApp::InitInstance() {
	/*
		下面的程序首先在堆上创建一个框架窗口对象,并将指针赋予成员变量m_pMainWnd。
		然后按照m_nCmdShow方式显示这个窗口,最后调用UpdateWindow()成员函数向窗口发送一个WM_PAINT消息。这和用WindowsAPI创建窗口时的
		情形基本相同。

		值得注意的是,程序中从未见到用delete m_pMainWnd来显式删除这个动态创建的框架窗口对象的语句。实际上,窗口在被清除之前接收的
		最后一个消息是WM_NCDESTROY,在这个消息处理程序CWind::OnNcDestroy()中,调用了一个虚函数CWnd::PostNcDestroy(),而CFrameWnd正
		好覆盖了这个虚函数并在其中执行了delete this语句。显然,这条语句的作用正是窗口在自己的程序中最终删除了自己(堆上创建的窗口)。
	*/
	m_pMainWnd = new CMainWindow; 
	m_pMainWnd->ShowWindow(m_nCmdShow);
	m_pMainWnd->UpdateWindow();

	return TRUE;
}

//这是CMainWindow的构造函数的实现代码,其中覆盖了父类的虚函数Create()来实际创建具体的窗口。
CMainWindow::CMainWindow() {
	//为简单起见,这里仅指定了函数前两个形参的值,其它参数(还有6个)全部采用缺省值。
	Create(
		nullptr, //第一个参数指定了窗口的WNDCLASS名称。这里使用空指针表示使用主结构注册的WNDCLASS默认值。
		/*
			下面这个参数是窗口的标题(在标题栏中显示的文本)。这里的_T是一个宏,用来把字符串常量设置为中性(即如果在预处理器中定义
			了_UNICODE,编译器将字符看作UNICODE字符,否则将字符看作ANSI字符)。
		*/
		_T("The MFC Application")
	);
}

//下面就是WM_PAINT消息处理程序的实现代码。
void CMainWindow::OnPaint() {
	/*
		首先构造一个CPaintDC对象实例。CPaintDC类是从MFC的更一般的CDC(CPaintDC->CDC->CObject)类派生而来。
		MFC在CDC类中封装了Windows设备环境,其中包含绘制到屏幕、打印机和其它设备的成员函数。		
		CPaintDC分别在其构造函数和析构函数中调用WindowsAPI函数BeginPaint()和EndPaint()来获取和释放Windows设备句柄。
	*/
	CPaintDC dc(this); 

	CRect rt;	
	GetClientRect(&rt); //然后调用父类的GetClientRect()获得窗口客户区范围

	/*
		最后调用设备环境句柄的DrawText()成员函数在屏幕上输出字符串。这里的DrawText()成员函数是WindowsAPI的DrawText()函数在CPaintDC类
		中直接包装的典型例子。成员函数的参数与WindowsAPI中的雷同,在此不再赘述。
	*/
	dc.DrawText(
		_T("Hello, MFC"), //被输出的字符串。
		-1, //被输出字符串的字符个数或-1(如果是-1,则被输出的字符串将以空字符结尾)。
		&rt, //表示窗口客户区范围的CRect指针。
		/*
			下面的参数表示绘制选项的“|”运算组合。
			这里的DT_SINGLELINE | DT_CENTER | DT_VCENTER三项组合,表示将单行文本水平且垂直居中显示。
		*/
		DT_SINGLELINE | DT_CENTER | DT_VCENTER
	);
}

/*
	最后来看实现消息映射的宏。
	在BEGIN_MESSAGE_MAP()与END_MESSAGE_MAP()之间的每一条宏定义都代表一个消息映射。
*/
BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
	ON_WM_PAINT() //这个宏实现了WM_PAINT消息与处理程序OnPaint()的映射。
END_MESSAGE_MAP()

/*
	下面是在程序编译前的两个编译选项的设置,先在这里熟悉一下。
	1、使用静态库还是动态链接库的设置:
		在项目上,右键->属性->配置属性->常规—>项目默认值—>MFC的使用—>选择“在静态库中使用MFC”就好了,这是调用静态库的时候。
		如果调用DLL,就要选择“在共享DLL中使用MFC”。 
	2、入口点的定义:
		在项目上,右键->属性->链接器->系统->子系统,下拉框选择:窗口 (/SUBSYSTEM:WINDOWS)。
		或者:在项目上,右键->属性->链接器->高级->入口点,设置成:WinMainCRTStartup。
	
	我们现在就来启动VS2017的IDE,来编译和运行我们的窗口应用。	
*/

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值