MFC学习2:MFC框架(基于对话框)

本文主要说明,从win32到MFC,有哪些新东西。

1基于对话框的MFC结构

1 新建空win32项目

修改属性

(选择静态库而不是动态dll库

a)静态链接(Static Linking):是将MFC库的代码编译到应用程序中,生成一个独立的可执行文件。
b)动态链接(Dynamic Linking):是将MFC库的代码编译成动态链接库(DLL),在运行时,应用程序需要依赖于外部的MFC库文件。
c)静态链接占用执行文件的空间大,动态链接占用的执行文件空间小。但是不能独立运行有依赖行,可能存在产品安全问题。
d)动态链接因为代码都在很多个DLL中,在调试时按F11不可以见MFC源码,而静态链接一般按F11就能进入MFC的源码进行了解。)
 

增加对话框资源

2 新建类

类名随便,但是要继承自 CWinApp类(MFC中的一个重要基类,启动管理类)

其中重要的虚函数

3 代码

首先包含头文件  <afxwin.h>  (afx开头的都是MFC的)

其次添加  #define _AFXDLL (如果报错:正在用 /MD 或 /MDd 编译选项(动态链接 CRT 库)构建 MFC 应用程序,但没有定义 _AFXDLL

CAppLearmFrame.h 文件

#pragma once

#define _AFXDLL
#include <afxwin.h> //afx开头的都是MFC

class CAppLearmFrame :public CWinApp
{
	BOOL InitInstance() override;  //作为MFC框架的起点 必须有
	int ExitInstance() override;
};

CAppLearmFrame.cpp 文件

#include "CAppLearmFrame.h"


CAppLearmFrame a;  //必须有的,CWinApp 中的pApp 和 pThread指针 都指向这个a

BOOL CAppLearmFrame::InitInstance()
{
	MessageBox(NULL, L"123",L"666", 0);

	return FALSE;
}
int CAppLearmFrame::ExitInstance()
{
	return 0;
}


//不需要winmain 该函数被MFC框架内部接管了

以上运行弹出一个MessageBox

4 绑定资源的对话框

CAppLearmFrame.h 文件中添加 

//#include <afxdialogex.h> CDialogEx 需要包含此头文件
#include "resource.h"

对于前面建立的dialog对话框,修改CAppLearmFrame.cpp 文件

BOOL CAppLearmFrame::InitInstance()
{
    //弹出对话框
	CDialog dlg(IDD_DIALOG1);
	dlg.DoModal();

	return FALSE;
}

另,对于直接生成的MFC项目(对话框的),app文件InitInstance()函数中有用的代码也就这两句


BOOL CMFClearnNew1App::InitInstance()
{
	// InitCommonControlsEx() is required on Windows XP if an application
	// manifest specifies use of ComCtl32.dll version 6 or later to enable
	// visual styles.  Otherwise, any window creation will fail.
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// Set this to include all the common control classes you want to use
	// in your application.
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();


	AfxEnableControlContainer();

	// Create the shell manager, in case the dialog contains
	// any shell tree view or shell list view controls.
	CShellManager *pShellManager = new CShellManager;

	// Activate "Windows Native" visual manager for enabling themes in MFC controls
	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

	// Standard initialization
	// If you are not using these features and wish to reduce the size
	// of your final executable, you should remove from the following
	// the specific initialization routines you do not need
	// Change the registry key under which our settings are stored
	// TODO: You should modify this string to be something appropriate
	// such as the name of your company or organization
	SetRegistryKey(_T("Local AppWizard-Generated Applications"));

	CMFClearnNew1Dlg dlg; //就这句
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();//还有这个,别的都可以删了
	if (nResponse == IDOK)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with OK
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with Cancel
	}
	else if (nResponse == -1)
	{
		TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
		TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
	}

	// Delete the shell manager created above.
	if (pShellManager != nullptr)
	{
		delete pShellManager;
	}

#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
	ControlBarCleanUp();
#endif

	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	return FALSE;
}

和下面的效果一样:

BOOL CMFClearnNew1App::InitInstance()
{
	 InitCommonControlsEx() is required on Windows XP if an application
	 manifest specifies use of ComCtl32.dll version 6 or later to enable
	 visual styles.  Otherwise, any window creation will fail.
	//INITCOMMONCONTROLSEX InitCtrls;
	//InitCtrls.dwSize = sizeof(InitCtrls);
	 Set this to include all the common control classes you want to use
	 in your application.
	//InitCtrls.dwICC = ICC_WIN95_CLASSES;
	//InitCommonControlsEx(&InitCtrls);

	//CWinApp::InitInstance();


	//AfxEnableControlContainer();

	 Create the shell manager, in case the dialog contains
	 any shell tree view or shell list view controls.
	//CShellManager *pShellManager = new CShellManager;

	 Activate "Windows Native" visual manager for enabling themes in MFC controls
	//CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

	 Standard initialization
	 If you are not using these features and wish to reduce the size
	 of your final executable, you should remove from the following
	 the specific initialization routines you do not need
	 Change the registry key under which our settings are stored
	 TODO: You should modify this string to be something appropriate
	 such as the name of your company or organization
	//SetRegistryKey(_T("Local AppWizard-Generated Applications"));

	CMFClearnNew1Dlg dlg;
	//m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
//	if (nResponse == IDOK)
//	{
//		// TODO: Place code here to handle when the dialog is
//		//  dismissed with OK
//	}
//	else if (nResponse == IDCANCEL)
//	{
//		// TODO: Place code here to handle when the dialog is
//		//  dismissed with Cancel
//	}
//	else if (nResponse == -1)
//	{
//		TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
//		TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
//	}
//
//	// Delete the shell manager created above.
//	if (pShellManager != nullptr)
//	{
//		delete pShellManager;
//	}
//
//#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
//	ControlBarCleanUp();
//#endif
//
//	// Since the dialog has been closed, return FALSE so that we exit the
//	//  application, rather than start the application's message pump.
	return FALSE;
}

5 接收消息

1 给对话框创建类 进入类向导

下拉菜单选择 MFC Class,或者选择添加类

注意基类和关联的对话框ID

然后生成的类中会有自动生成的代码。

也可以建立空类手动添加内容:

然后生成的类,手动添加如下:

CMainDlg.h文件

#pragma once

#define _AFXDLL
#include <afxwin.h>    // MFC 基类
#include <afxext.h>    // MFC 扩展类
#include <afxdialogex.h>  // 对话框类
#include "resource.h"

class CMainDialog : public CDialogEx
{
public:
    CMainDialog(CWnd* pParent = nullptr); // 标准构造函数

protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

protected:
    DECLARE_MESSAGE_MAP()
};

CMainDlg.cpp文件

#include "CMainDialog.h"


CMainDialog::CMainDialog(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_DIALOG1, pParent)
{
}

void CMainDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    // DDX 控件变量
}

BEGIN_MESSAGE_MAP(CMainDialog, CDialogEx)
    // 添加消息映射
END_MESSAGE_MAP()

修改CAppLearmFrame.h 文件

#pragma once

#define _AFXDLL
#include <afxwin.h> //afx开头的都是MFC
//#include <afxdialogex.h> CDialogEx 需要包含此头文件
//#include "resource.h"
#include "CMainDialog.h"

class CAppLearmFrame :public CWinApp
{
	BOOL InitInstance() override;  //作为MFC框架的起点 必须有
	int ExitInstance() override;
};

修改CAppLearmFrame.cpp 文件

#include "CAppLearmFrame.h"


CAppLearmFrame a;  //必须有的,CWinApp 中的pApp 和 pThread指针 都指向这个a

BOOL CAppLearmFrame::InitInstance()
{
/*	CDialog dlg(IDD_DIALOG1);
	dlg.DoModal(); */  //使用生成MFC框架的对话框项目,其中的有用的代码也就这两句(别的删掉都可以)

	CMainDialog dlg;
	dlg.DoModal();

	return FALSE;
}
int CAppLearmFrame::ExitInstance()
{
	return 0;
}


//不需要winmain 该函数被MFC框架内部接管了

2 创建消息

进入类向导

选择对话框的类,选择消息,双击即可添加

按键 消息

内部 m_hWnd 核心指针

6 对比一下mfc对话框的

比如仅队话框的项目,结构如下:

红框的四个文件

就对应上面WIN32中的CAppLearmFrame.h、CAppLearmFrame.cpp和CMainDlg.h、CMainDlg.cpp

内容区别

1 xxxAPP类的h文件:

增加了构造函数和消息的map,并添加了全局变量theApp的extern声明

2 xxxAPP类的cpp文件:

m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

这意味着应用程序支持重启管理器,并且已经设置了相应的标志来表示它支持重启功能。具体来说,AFX_RESTART_MANAGER_SUPPORT_RESTART 是一个常量,用于表示应用程序支持在用户注销或系统重启时恢复未完成的操作。这通常是为了处理那些由于系统更新或其他重要事件而被中断的应用程序操作。

当应用程序使用MFC框架并启用了这个标志时,如果用户注销或系统重启时应用程序正在运行一个长时间的操作(例如文件保存或网络请求),Windows会提示用户该应用程序需要重启来完成未完成的操作,并在适当的时机重启应用程序。这为应用程序提供了一个优雅的方式来处理可能的长时间操作中断情况。

InitInstance里面就那两句话有用(还有return),别的可删。

3 Dlg的h文件

   继承自 CDialogEx

   新增了 Onpait函数(用于绘图)以及OnQueryDragIcon()函数

void CMFClearnNew1Dlg::OnPaint() 是一个虚函数,通常是在MFC应用程序中处理窗口绘制的事件。当对话框或窗口需要重新绘制时(例如最大化、最小化或者覆盖其他窗口后恢复时),系统会调用这个函数。

在这个函数中,你可以使用 GDI(图形设备接口)函数来绘制你的窗口内容,比如文本、形状或图像。通常,MFC会为每个对话框或窗口自动生成这个函数的框架,你可以在其中添加自定义绘图代码。

基本流程如下:

  1. 接收 WM_PAINT 消息:当窗口需要重绘时,系统向其发送 WM_PAINT 消息。
  2. 调用 OnPaint:应用程序的消息映射机制会将这个消息映射到 OnPaint() 函数。
  3. 绘制内容:在 OnPaint() 中,你可以执行所有需要的绘图操作。

注意:在绘图前,通常要获取设备上下文(DC),例如使用 BeginPaint() 函数。绘制完成后,使用 EndPaint() 来释放DC。

示例代码:

void CMFClearnNew1Dlg::OnPaint()
{
    CPaintDC dc(this); // 创建设备上下文

    // 示例绘制文本
    dc.TextOut(10, 10, _T("Hello, MFC!"));
}
//这段代码在对话框上绘制文本“Hello, MFC!”。你可以根据需要自定义绘制的内容。

HCURSOR CMFClearnNew1Dlg::OnQueryDragIcon() 是一个函数,通常在MFC(Microsoft Foundation Classes)应用程序中用于查询拖放操作的图标。

MFC是一个用于开发Windows桌面应用程序的库。当你尝试拖放某个项目(例如文件或应用程序窗口)时,该函数会被调用。该函数返回拖动操作应使用的光标。简单来说,当你拖拽一个窗口图标时,该函数告诉系统应该使用哪个图标作为拖拽的视觉表示。

这个函数是自动生成的,意味着它通常是在创建MFC应用程序时由开发环境自动生成的。对于简单的应用程序,这个函数通常不是开发者关心的主要部分,因为它更多地是用于特定的应用程序逻辑的实现或UI反馈的细节部分。对于大部分标准应用来说,开发者可能不需要修改这个函数的内容,除非你有特定的需求来改变拖拽时的图标。

构造函数中:

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

加载界面的图标,对应资源位置:

在OnInitDialog() 函数中:

SetIcon(m_hIcon, TRUE);			// Set big icon
SetIcon(m_hIcon, FALSE);		// Set small icon

设置图标

如果修改图标,可以同名直接替换资源;也可以导入新的资源,然后修改构造函数的ID名称

预编译头文件


a)早期VC4-VS2015版本的预编译头文件是stdafx.h
b)VS2017-VS2022之后名字改为pch.h
c)在MFC中属于所有头文件的头。
d)必须在所有cpp的最上一行是#include "pch.h"
强制每个cpp包含这个东西:
错误    C1010    在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "pch.h"”?    
 

7 对话框类

   对话框程序对象的生命期

  a)CDialog::DoModal()函数弹出对话框,在这个函数阻塞期间对象内是有句柄(不为空)
  b)执行DoModal()之前,和阻塞结束对话框关闭后,句柄都是NULL。
  c)因此DoModal之前和之后都不能执行控件和窗口操作。

<未完待续>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值