[MFC]DlgDemo2程序:非模态对话框的基本应用

1. 非模态对话框的创建方法以及和模态对话框的不同之处:

    1) 首先是创建非模态对话框使用的是CDialog::Create而不是CDialog::DoModal;

    2) 那么最大的问题就来了,Create是从CWnd继承而来的用来创建普通窗口用的函数,这就导致了关闭对话框时和模态对话框的大不相同!!

    3) 由于使用Create创建对话框窗口了,因此关闭它就也要和关闭普通窗口一样,必须使用DestroyWindow来关闭窗口,DestroyWindow会接着触发PostNcDestroy,这完全就和关闭普通窗口一模一样了,因此这里最大的区别就是模态对话框关闭必须靠EndDialog,而非模态对话框的关闭必须使用DestroyWindow;

    4) 那么这里就要特别强调了,再关闭非模态对话框的时候就绝对!绝对!不能使用基类CDialog的OnOK和OnCancel函数,因为基类的这两个函数底层都会默认调用EndDialog;

!!因此,再使用非模态对话框时如果要使用默认的IDOK和IDCANCEL按钮,就必须!必须!手动覆盖OnOK和OnCancel函数,并删去里面调用基类相应函数的语句,而剩下的数据回送(UpdateData(TRUE))函数也需要自己手动调用了,因为UpdateData(TRUE)是在基类的OnOK和OnCancel函数中调用的,由于删去了这两个函数的调用,UpdateData(TRUE)必须自己手写上去了;

    5) 非模态对话框的对象绝对不能建立在局部栈上,必须建立在堆上!!

         i. 原因是显而易见的,因为模态对话框一旦被激活显示,则其上层窗口将无法被激活而必须等待对话框处理完成并关闭后才能被重新激活,这就导致了直到关闭模态对话框DoModel才会返回值,因此在打开和关闭模态对话框中间的时间段里肯定不会做其它事情,所以模态对话框的对象完全可以建立在局部栈上,因为创建后立即使用,使用完立即就删除;

         ii. 而非模态对话框其实就跟普通窗口差不多,其被显示期间仍然可以激活其上层的父窗口,因此Create一定是立马返回值的,而不是要等待对话框关闭才返回值,否则程序就会卡在这个地方而无法实现重新激活其上层父窗口的功能了,因此非模态对话框在建立之后根本无法推测其什么时候才会关闭(这是和模态对话框最大的不同之处),在关闭之前可能还会利用上层的父窗口完成一些任务,所以非模态对话框的对象绝对不能建立在临时栈上,而必须建立在堆上(new),什么时候想关闭了(按下退出按钮)再临时删除(delete,所以必须在退出按钮的处理程序中使用delete删除对象);

!!一般标准的做法就是在OnCancel中调用DestroyWindow,然后在PostNcDestroy中使用delete删除对象(DestroyWindow会自动触发PostNcDestroy);

    6) 在Win32 API编程中,使用非模态对话框就必须修改消息循环,使用::IsDialogMessage将消息转发给相应的对话框,但是在MFC中这些都已经自动实现了,程序员完全不用关心这些细节;


!!关于CDialog::Create:

        a. 函数原型:BOOL CDialog::Create(UINT nIDTemplate, CWnd* pParent = NULL);

        b. 第一个参数是要绑定的对话框的资源ID,这里就会奇怪了,CDialog在构造函数创建的时候已经绑定过一次资源ID了,为什么这里还要绑定?没办法,就是要再绑定一次;

        c. 第二个参数是所属窗口的指针,如果为NULL就代表父窗口为主框架窗口;


2. DlgDemo2程序的设计:

    1) 功能完全和DlgDemo1一样,只不过不同之处在于,由于DlgDemo2使用的是非模态对话框,可以不关闭并使用上层父窗口,因此这里就要求按下OK按钮后对话框并不关闭,而是直接时上层的视图窗口中的矩形按照用户的输入更新并显示,只有点击Cancel才能关闭对话框;

    2) 因此这里的OK按钮改名为Apply(应用),而Cancel按钮改为Close(关闭),但是这些只是按钮上文本的改变,ID仍然使用MFC默认的IDOK和IDCANCEL;

    3) 由于对话框的对象要建立在堆上,因此就为视图类增加一个新的成员,即COptionsDlg* m_pDlg,在视图类的构造函数中初始化为NULL,然后在Options菜单项的处理函数中new出对象赋给m_pDlg,并且这里还有一个非常重要的陷阱要介绍:那就是非模态对话框打开时还可以玩转上层窗口,这就意味着此时仍能打开上层窗口中的菜单并再次点击Options菜单项,这不就重复建立了多个对话框了吗?所以在Options的处理函数中必须要进行逻辑判断,即m_pDlg非空的时候才能创建对话框,否则就不能(意味着已经打开了一个,不能再重复打开了);

    4) 剩下的最大的难处就是无法在Options的处理函数中将对话框的数据回送到视图类的相应数据中,因为非模态对话框的关闭时间点无法预测,所以Options中Create对话框后剩下的语句会立马顺序执行完,程序会立即退出处理函数,这中间的过程太快,用户根本来不及往对话框中输入数据,因此程序必须通过其它方式将数据回送至视图类:

         i. 思路是使用消息传递的方法进行回送;

         ii. 在OnOK中使用SendMessage函数将数据打包在一个结构中并通过lParam回送至MainFrame中,SendMessage必须通过AfxGetMainWnd调用,所以只能先回送到MainFrame中;

         iii. 接着在MainFrame的该消息的处理程序中利用m_wndView.SendMessage继续将消息传递给视图类;

         iv. 在视图类的相应的消息处理函数中将lParam中包裹的数据打开并复制给其数据成员完成对话框往视图类的数据回送全过程;

!!!同样,在关闭对话框时,在PostNcDestroy中不仅要delete掉自己(即delete this),也希望将m_pDlg也置空,但是m_pDlg是视图类的成员,因此在对话框内部无法访问它,所以还是需要通过消息传递的机制来完成该任务:

         i. 在PostNcDestroy中使用AfxGetMainWnd->SendMessage将关闭消息发送至MainFrame;

         ii. MainFrame再将消息继续传递给CChildView;

         iii. 最后再CChildView中就可以顺利地将自己的成员m_pDlg置为NULL了;

!!因此这里我们需要自创两个消息了,一个就是WM_USER_APPLY,还有一个就是WM_USER_DESTROY,我们可以利用MFC预定义好的WM_USER消息ID来定义它们,WM_USER是MFC规定的用户可以自定义的消息ID的下界,MFC标准规定用户可以自定义的消息ID的范围是0x0400 ~ 0x7FFF,而WM_USER就等于0x0400,因此我们可以定义WM_USER_APPLY为WM_USER + 0x0100等;

!!在给自定义消息ID命名时最好加上USER中缀,以表示该消息是一个用户自定义的消息;


3. COptions类的实现:

    1) .h:

#if !defined(AFX_OPTIONSDLG_H__525087D4_B252_423F_BB70_3F77BE9E4DD5__INCLUDED_)
#define AFX_OPTIONSDLG_H__525087D4_B252_423F_BB70_3F77BE9E4DD5__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// OptionsDlg.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// COptionsDlg dialog

class COptionsDlg : public CDialog
{
// Construction
public:
	COptionsDlg(CWnd* pParent = NULL);   // standard constructor

// Dialog Data
	//{{AFX_DATA(COptionsDlg)
	enum { IDD = IDD_OPTIONS };
	int		m_nHeight;
	int		m_nWidth;
	int		m_nUnits;
	//}}AFX_DATA


// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(COptionsDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

	// 必须要覆盖OnOK和OnCancel避免其调用EndDialog函数
	virtual void PostNcDestroy(); // 在其中delete掉自身
	virtual void OnOK();
	virtual void OnCancel();
	//}}AFX_VIRTUAL

// Implementation
protected:

	// Generated message map functions
	//{{AFX_MSG(COptionsDlg)
		// NOTE: the ClassWizard will add member functions here
	afx_msg void OnReset();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_OPTIONSDLG_H__525087D4_B252_423F_BB70_3F77BE9E4DD5__INCLUDED_)
!!可以看到就比Demo1多了一个PostNcDestroy;

    2) .cpp文件:只显示出和Demo1不一样的地方

BEGIN_MESSAGE_MAP(COptionsDlg, CDialog)
	//{{AFX_MSG_MAP(COptionsDlg)
		// NOTE: the ClassWizard will add message map macros here
	ON_BN_CLICKED(IDC_RESET, OnReset)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COptionsDlg message handlers

void COptionsDlg::OnReset()
{
	m_nWidth = 4;
	m_nHeight = 2;
	m_nUnits = 0;
	
	UpdateData(FALSE);
}

void COptionsDlg::OnOK()
{
	UpdateData(TRUE); // 先更新数据

	// 将数据打包准备回送至MainFrame
	DLGDATAWRAP ddw;
	ddw.nWidth = m_nWidth;
	ddw.nHeight = m_nHeight;
	ddw.nUnits = m_nUnits;
	
	// 传送数据包的指针即可(利用lParam来传送)
	// !!注意:ddw是OnOK中创建的局部数据包,会随着OnOK的结束而被销毁
	// 但是SendMessage必须要该消息被处理完成之后(消息被处理完后会从消息队列中清除)才会返回
	// 所以在处理消息的全过程中ddw都始终存在,所以不必担心指针崩溃的问题!!
	AfxGetMainWnd()->SendMessage(WM_USER_APPLY, 0, (LPARAM)&ddw);
}

void COptionsDlg::OnCancel()
{
	DestroyWindow(); // 关闭窗口只需要关闭窗口,不用处理任何数据
}

void COptionsDlg::PostNcDestroy() // 该过程由DestoryWindow触发
{
	CDialog::PostNcDestroy(); // 必须调用基类的PostNcDestroy完成一些基础工作

	// 接着完成我们所关心的额外工作
	AfxGetMainWnd()->SendMessage(WM_USER_DESTROY, 0, 0); // 回送关闭消息,让视图将m_pDlg置空
	delete this; // 同时将自己删掉,完美!
}

!数据包的定义以及自定义消息的命名均在StdAfx.h中实现:

// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

#if !defined(AFX_STDAFX_H__650AA177_FB7D_42BA_8A4A_56312CDF152B__INCLUDED_)
#define AFX_STDAFX_H__650AA177_FB7D_42BA_8A4A_56312CDF152B__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxdtctl.h>		// MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>			// MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT

// 将非模态对话框中的数据回送到MainFrame的数据包的定义
typedef struct tagDLGDATAWRAP {
	int nWidth;
	int nHeight;
	int nUnits;
} DLGDATAWRAP;

// 对话框向MainFrame回送的消息
#define WM_USER_APPLY		(WM_USER + 0x0100)  // 点击对话框中“应用”所人工产生的消息
#define WM_USER_DESTROY		(WM_USER + 0x0101)  // 点击关闭按钮所人工产生的消息

// 以上两者同样也是MainFrame继续向CChildView传递的对象

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_STDAFX_H__650AA177_FB7D_42BA_8A4A_56312CDF152B__INCLUDED_)


4. MainFrame的实现:

    1) 仅仅就是多了WM_USER_APPLY和WM_USER_DESTROY的消息响应;

    2) .h:

protected:
	//{{AFX_MSG(CMainFrame)
	afx_msg void OnSetFocus(CWnd *pOldWnd);
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
		// NOTE - the ClassWizard will add and remove member functions here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	// 处理对话框回送的消息
	// 由于都是自定义的消息,因此消息处理程序需要使用MFC指定的一般形式
	afx_msg LRESULT OnApply(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnDestroy(WPARAM wParam, LPARAM lParam);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};
    3) .cpp:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	//{{AFX_MSG_MAP(CMainFrame)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code !
	ON_WM_SETFOCUS()
	ON_WM_CREATE()
	
	// 看一下自定义消息的消息映射,必须采用一般形式,即ON_MESSAGE
	ON_MESSAGE(WM_USER_APPLY, OnApply)
	ON_MESSAGE(WM_USER_DESTROY, OnDestroy)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// 处理回送消息的处理程序只需要将消息继续传递给视图类即可
// 返回值在本程序中没有意义,因此随便返回一个0即可

LRESULT CMainFrame::OnApply(WPARAM wParam, LPARAM lParam)
{
	m_wndView.SendMessage(WM_USER_APPLY, wParam, lParam);
	return 0;
}

LRESULT CMainFrame::OnDestroy(WPARAM wParam, LPARAM lParam)
{
	m_wndView.SendMessage(WM_USER_DESTROY, wParam, lParam);
	return 0;
}


5. 视图类的实现:

    1) 需要注意的是,WM_USER_APPLY和WM_USER_DESTROY实际上都是在视图类中得到真正的处理的;

    2) .h:

// ChildView.h : interface of the CChildView class
//
/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_CHILDVIEW_H__196A7993_6F8F_4841_A0C4_B90541587FBC__INCLUDED_)
#define AFX_CHILDVIEW_H__196A7993_6F8F_4841_A0C4_B90541587FBC__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// CChildView window

class CChildView : public CWnd
{
// Construction
public:
	CChildView();

// Attributes
public:

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CChildView)
	protected:
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
	//}}AFX_VIRTUAL

// Implementation
public:
	virtual ~CChildView();

	// Generated message map functions
protected:
	COptionsDlg* m_pDlg; // 将非模态对话框的指针作为数据成员
	int m_nUnits;
	int m_nHeight;
	int m_nWidth;
	//{{AFX_MSG(CChildView)
	afx_msg void OnPaint();
	afx_msg void OnFileOptions();

	// 两个处理MainFrame传递过来的消息,需要在视图类中得到真正的处理
	afx_msg LRESULT OnApply(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnDestroy(WPARAM wPram, LPARAM lParam);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CHILDVIEW_H__196A7993_6F8F_4841_A0C4_B90541587FBC__INCLUDED_)
    3) .cpp:

// ChildView.cpp : implementation of the CChildView class
//

#include "stdafx.h"
#include "DlgDemo2.h"

#include "OptionsDlg.h"
#include "ChildView.h"



#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CChildView

CChildView::CChildView()
{
	m_pDlg = NULL; // 要多初始化一个指针

	m_nWidth = 4;
	m_nHeight = 2;
	m_nUnits = 0;
}

CChildView::~CChildView()
{
}


BEGIN_MESSAGE_MAP(CChildView,CWnd )
	//{{AFX_MSG_MAP(CChildView)
	ON_WM_PAINT()
	ON_COMMAND(ID_FILE_OPTIONS, OnFileOptions)

	// 别忘了添加消息映射
	ON_MESSAGE(WM_USER_APPLY, OnApply)
	ON_MESSAGE(WM_USER_DESTROY, OnDestroy)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CChildView message handlers

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.dwExStyle |= WS_EX_CLIENTEDGE;
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

	return TRUE;
}

void CChildView::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here
	CBrush brush(RGB(255, 0, 255));
	CBrush* pOldBrush = dc.SelectObject(&brush);

	switch (m_nUnits)
	{
	case 0:
		dc.SetMapMode(MM_LOENGLISH);
		dc.Rectangle(0, 0, m_nWidth * 100, -m_nHeight * 100);
		break;

	case 1:
		dc.SetMapMode(MM_LOMETRIC);
		dc.Rectangle(0, 0, m_nWidth * 100, -m_nHeight * 100);
		break;

	case 2:
		dc.SetMapMode(MM_TEXT);
		dc.Rectangle(0, 0, m_nWidth, m_nHeight);
		break;
	}
	
	dc.SelectObject(pOldBrush);
	
	// Do not call CWnd::OnPaint() for painting messages
}

void CChildView::OnFileOptions() // Options菜单项中打开非模态对话框
{
	if (m_pDlg) // 如果指针非空就代表已经打开了一个对话框了,不能重复打开
		m_pDlg->SetFocus(); // 因此只要将焦点再聚到那个打开的对话框即可
	// 这是良好的Windows程序的最为标准的做法!!!一定要养成良好的习惯

	else { // 未打开过,创建并显示
		m_pDlg = new COptionsDlg; // 在堆上建立

		// 对话框数据初始化
		m_pDlg->m_nWidth = m_nWidth;
		m_pDlg->m_nHeight = m_nHeight;
		m_pDlg->m_nUnits = m_nUnits;

		m_pDlg->Create(IDD_OPTIONS); // 在内存中创建资源
		// Create并不会等待对话框关闭再返回而是直接执行下去了!!
		m_pDlg->ShowWindow(SW_SHOW); // 这才是真正的显示出来
	}
}

LRESULT CChildView::OnApply(WPARAM wParam, LPARAM lParam)
{
	DLGDATAWRAP* ddw = (DLGDATAWRAP*)lParam; // 对话框的数据包的指针通过lParam传送

	// 数据回填
	m_nWidth = ddw->nWidth;
	m_nHeight = ddw->nHeight;
	m_nUnits = ddw->nUnits;

	Invalidate(); // 数据更新后就重画矩形
	return 0; // 返回值无用,随意返回一个0即可
}

LRESULT CChildView::OnDestroy(WPARAM wPram, LPARAM lParam)
{
	m_pDlg = NULL; // 关闭对话框时将指针置空
	return 0;
}


!!!注意所有的.cpp文件!!一定要把所有用到的.h文件都include进去了!!否则很可能出现交叉引用报错,这种报错你很难找出原因,因为怎么检查语法都是正确的,极端一点可以把所有的.h文件都包含到每个.cpp文件中,其实是没关系的,因为所有头文件都有重复声明的保护!!

6. .rc:

//Microsoft Developer Studio generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// Chinese (P.R.C.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
#ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#endif //_WIN32

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE DISCARDABLE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE DISCARDABLE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE DISCARDABLE 
BEGIN
    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
    "#define _AFX_NO_OLE_RESOURCES\r\n"
    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
    "\r\n"
    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
    "#ifdef _WIN32\r\n"
    "LANGUAGE 9, 1\r\n"
    "#pragma code_page(1252)\r\n"
    "#endif //_WIN32\r\n"
    "#include ""res\\DlgDemo2.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
    "#include ""afxres.rc""         // Standard components\r\n"
    "#endif\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_DIALOG1 DIALOG DISCARDABLE  0, 0, 199, 148
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 10, "System"
BEGIN
    LTEXT           "&Width",IDC_STATIC,20,20,24,10,NOT WS_GROUP
    EDITTEXT        IDC_WIDTH,55,20,45,10,ES_AUTOHSCROLL
    LTEXT           "&Height",IDC_STATIC,20,35,24,10,NOT WS_GROUP
    EDITTEXT        IDC_HEIGHT,55,35,45,10,ES_AUTOHSCROLL
    GROUPBOX        "Units",IDC_STATIC,20,65,65,70
    CONTROL         "&Inches",IDC_INCHES,"Button",BS_AUTORADIOBUTTON | 
                    WS_GROUP | WS_TABSTOP,30,80,45,10
    CONTROL         "&Centimeters",IDC_INCHES2,"Button",BS_AUTORADIOBUTTON | 
                    WS_TABSTOP,30,95,45,10
    CONTROL         "&Pixels",IDC_INCHES3,"Button",BS_AUTORADIOBUTTON | 
                    WS_TABSTOP,30,110,45,10
    DEFPUSHBUTTON   "Apply",IDOK,125,20,50,14,WS_GROUP
    PUSHBUTTON      "Close",IDCANCEL,125,45,50,14,WS_GROUP
    PUSHBUTTON      "&Reset",IDC_RESET,125,70,50,14,WS_GROUP
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE 
BEGIN
    IDD_DIALOG1, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 192
        TOPMARGIN, 7
        BOTTOMMARGIN, 141
    END
END
#endif    // APSTUDIO_INVOKED

#endif    // Chinese (P.R.C.) resources
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDR_MAINFRAME           ICON    DISCARDABLE     "res\\DlgDemo2.ico"

/////////////////////////////////////////////////////////////////////////////
//
// Menu
//

IDR_MAINFRAME MENU PRELOAD DISCARDABLE 
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "&Options...",                 ID_FILE_OPTIONS
        MENUITEM "E&xit",                       ID_APP_EXIT
    END
    POPUP "&Edit"
    BEGIN
        MENUITEM "&Undo\tCtrl+Z",               ID_EDIT_UNDO
        MENUITEM SEPARATOR
        MENUITEM "Cu&t\tCtrl+X",                ID_EDIT_CUT
        MENUITEM "&Copy\tCtrl+C",               ID_EDIT_COPY
        MENUITEM "&Paste\tCtrl+V",              ID_EDIT_PASTE
    END
    POPUP "&Help"
    BEGIN
        MENUITEM "&About DlgDemo2...",          ID_APP_ABOUT
    END
END


/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//

IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE 
BEGIN
    "C",            ID_EDIT_COPY,           VIRTKEY, CONTROL, NOINVERT
    "V",            ID_EDIT_PASTE,          VIRTKEY, CONTROL, NOINVERT
    VK_BACK,        ID_EDIT_UNDO,           VIRTKEY, ALT, NOINVERT
    VK_DELETE,      ID_EDIT_CUT,            VIRTKEY, SHIFT, NOINVERT
    VK_F6,          ID_NEXT_PANE,           VIRTKEY, NOINVERT
    VK_F6,          ID_PREV_PANE,           VIRTKEY, SHIFT, NOINVERT
    VK_INSERT,      ID_EDIT_COPY,           VIRTKEY, CONTROL, NOINVERT
    VK_INSERT,      ID_EDIT_PASTE,          VIRTKEY, SHIFT, NOINVERT
    "X",            ID_EDIT_CUT,            VIRTKEY, CONTROL, NOINVERT
    "Z",            ID_EDIT_UNDO,           VIRTKEY, CONTROL, NOINVERT
END


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_ABOUTBOX DIALOG DISCARDABLE  0, 0, 235, 55
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About DlgDemo2"
FONT 8, "MS Sans Serif"
BEGIN
    ICON            IDR_MAINFRAME,IDC_STATIC,11,17,20,20
    LTEXT           "DlgDemo2 Version 1.0",IDC_STATIC,40,10,119,8,
                    SS_NOPREFIX
    LTEXT           "Copyright (C) 2015",IDC_STATIC,40,25,119,8
    DEFPUSHBUTTON   "OK",IDOK,178,7,50,14,WS_GROUP
END


#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//

VS_VERSION_INFO VERSIONINFO
 FILEVERSION 1,0,0,1
 PRODUCTVERSION 1,0,0,1
 FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
 FILEFLAGS 0x1L
#else
 FILEFLAGS 0x0L
#endif
 FILEOS 0x4L
 FILETYPE 0x1L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904B0"
        BEGIN
            VALUE "CompanyName", "\0"
            VALUE "FileDescription", "DlgDemo2 MFC Application\0"
            VALUE "FileVersion", "1, 0, 0, 1\0"
            VALUE "InternalName", "DlgDemo2\0"
            VALUE "LegalCopyright", "Copyright (C) 2015\0"
            VALUE "LegalTrademarks", "\0"
            VALUE "OriginalFilename", "DlgDemo2.EXE\0"
            VALUE "ProductName", "DlgDemo2 Application\0"
            VALUE "ProductVersion", "1, 0, 0, 1\0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END

#endif    // !_MAC


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE 
BEGIN
    IDD_ABOUTBOX, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 228
        TOPMARGIN, 7
        BOTTOMMARGIN, 48
    END
END
#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// String Table
//

STRINGTABLE PRELOAD DISCARDABLE 
BEGIN
    IDR_MAINFRAME           "DlgDemo2"
END

STRINGTABLE PRELOAD DISCARDABLE 
BEGIN
    AFX_IDS_APP_TITLE       "DlgDemo2"
    AFX_IDS_IDLEMESSAGE     "Ready"
END

STRINGTABLE DISCARDABLE 
BEGIN
    ID_INDICATOR_EXT        "EXT"
    ID_INDICATOR_CAPS       "CAP"
    ID_INDICATOR_NUM        "NUM"
    ID_INDICATOR_SCRL       "SCRL"
    ID_INDICATOR_OVR        "OVR"
    ID_INDICATOR_REC        "REC"
END

STRINGTABLE DISCARDABLE 
BEGIN
    ID_APP_ABOUT            "Display program information, version number and copyright\nAbout"
    ID_APP_EXIT             "Quit the application; prompts to save documents\nExit"
END

STRINGTABLE DISCARDABLE 
BEGIN
    ID_NEXT_PANE            "Switch to the next window pane\nNext Pane"
    ID_PREV_PANE            "Switch back to the previous window pane\nPrevious Pane"
END

STRINGTABLE DISCARDABLE 
BEGIN
    ID_WINDOW_SPLIT         "Split the active window into panes\nSplit"
END

STRINGTABLE DISCARDABLE 
BEGIN
    ID_EDIT_CLEAR           "Erase the selection\nErase"
    ID_EDIT_CLEAR_ALL       "Erase everything\nErase All"
    ID_EDIT_COPY            "Copy the selection and put it on the Clipboard\nCopy"
    ID_EDIT_CUT             "Cut the selection and put it on the Clipboard\nCut"
    ID_EDIT_FIND            "Find the specified text\nFind"
    ID_EDIT_PASTE           "Insert Clipboard contents\nPaste"
    ID_EDIT_REPEAT          "Repeat the last action\nRepeat"
    ID_EDIT_REPLACE         "Replace specific text with different text\nReplace"
    ID_EDIT_SELECT_ALL      "Select the entire document\nSelect All"
    ID_EDIT_UNDO            "Undo the last action\nUndo"
    ID_EDIT_REDO            "Redo the previously undone action\nRedo"
END

STRINGTABLE DISCARDABLE 
BEGIN
    AFX_IDS_SCSIZE          "Change the window size"
    AFX_IDS_SCMOVE          "Change the window position"
    AFX_IDS_SCMINIMIZE      "Reduce the window to an icon"
    AFX_IDS_SCMAXIMIZE      "Enlarge the window to full size"
    AFX_IDS_SCNEXTWINDOW    "Switch to the next document window"
    AFX_IDS_SCPREVWINDOW    "Switch to the previous document window"
    AFX_IDS_SCCLOSE         "Close the active window and prompts to save the documents"
END

STRINGTABLE DISCARDABLE 
BEGIN
    AFX_IDS_SCRESTORE       "Restore the window to normal size"
    AFX_IDS_SCTASKLIST      "Activate Task List"
END

#endif    // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#define _AFX_NO_SPLITTER_RESOURCES
#define _AFX_NO_OLE_RESOURCES
#define _AFX_NO_TRACKER_RESOURCES
#define _AFX_NO_PROPERTY_RESOURCES

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)
#endif //_WIN32
#include "res\DlgDemo2.rc2"  // non-Microsoft Visual C++ edited resources
#include "afxres.rc"         // Standard components
#endif

/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED


7. 最后再认识几个新的MFC注释宏:

    1) 第一个出现在OptionsDlg.h中,如果使用Wizard来为类添加数据成员,则在数据成员的的外围会用//{{AFX_DATA(CLASSTYPE) ... //AFX_DATA}}宏包围:

// Dialog Data
	//{{AFX_DATA(COptionsDlg)
	enum { IDD = IDD_OPTIONS };
	int		m_nHeight;
	int		m_nWidth;
	int		m_nUnits;
	//}}AFX_DATA
    2) 用Wizard添加的数据成员都会在构造函数中给出默认的初始化语句,这些语句包含在//{{AFX_DATA_INIT(CLASSTYPE) ... //AFX_DATA_INIT}}宏中:

COptionsDlg::COptionsDlg(CWnd* pParent /*=NULL*/)
	: CDialog(COptionsDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(COptionsDlg)
	m_nHeight = 0;
	m_nWidth = 0;
	m_nUnits = -1;
	//}}AFX_DATA_INIT
}
!!默认值是多少会根据具体情况而定,这里是根据被绑定的控件类型来定的,对于普通编辑框绑定int值默认初始为0,对于单选框绑定int初始为-1(表示哪项都没选);

    3) 用Wizard自动添加并绑定控件的数据成员会自动给出DDX和DDV函数,这些函数都会包围在//{{AFX_DATA_MAP(CLASSTYPE) ... //AFX_DATA_MAP}}中:

void COptionsDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(COptionsDlg)
	DDX_Text(pDX, IDC_HEIGHT, m_nHeight);
	DDV_MinMaxInt(pDX, m_nHeight, 1, 128);
	DDX_Text(pDX, IDC_WIDTH, m_nWidth);
	DDV_MinMaxInt(pDX, m_nWidth, 1, 128);
	DDX_Radio(pDX, IDC_INCHES, m_nUnits);
	//}}AFX_DATA_MAP
}
!!对话框数据交换在MFC中叫做数据映射;

你可能感兴趣的:(mfc,非模态对话框)