21、MFC 文档/视图架构与 AppWizard 使用指南

MFC 文档/视图架构与 AppWizard 使用指南

1. MFC 文档/视图架构基础概念

在 MFC(Microsoft Foundation Classes)应用程序开发中,文档/视图架构是一个核心概念。文档类( CDocument )用于表示应用程序的数据,而视图类( CView )则负责将文档数据展示给用户,并提供用户修改数据的接口。框架窗口类( CFrameWnd )则是应用程序的主窗口,包含菜单栏、工具栏和状态栏等,为视图提供一个容器。

2. 视图类( CView )及其相关函数

视图类是 CWnd 的子类,它提供了视图的基本功能,包括保存关联文档的指针。一个典型的视图类通常会重写以下几个继承的函数:
- GetDocument() :用于获取关联文档的指针。
- OnUpdate() :当文档数据发生变化时,由文档的 UpdateAllViews() 函数调用,用于更新视图项。
- OnDraw() :负责在视图中进行绘制操作。

以下是一个 CStockPriceView 类的示例,它为 CStockPriceDoc 类创建视图:

class CStockPriceView : public CView
{
protected:
    DECLARE_DYNCREATE(CStockPriceView)
private:
    // member variables
    CString m_StockSymbol;
    CString m_StockPriceText;
    CString* m_History;
public:
    CStockPriceView(); // constructor
    // member functions
    CStockPriceDoc* GetDocument();
    virtual void OnDraw(CDC*);
    virtual void OnUpdate(CView*, LPARAM, CObject*);
    DECLARE_MESSAGE_MAP()
};
2.1 GetDocument() 函数

视图与单个文档关联,框架将文档的指针保存在视图的 m_pDocument 成员变量中。 GetDocument() 函数的声明如下:

CDocument* GetDocument() const;

由于返回值类型为 CDocument* ,因此需要将指针转换为文档类的实际类型。 CStockPriceView 类的 GetDocument() 函数示例如下:

CStockPriceDoc* CStockPriceView::GetDocument()
{
    return (CStockPriceDoc*)m_pDocument;
}
2.2 OnUpdate() 函数

视图的 OnUpdate() 函数由文档的 UpdateAllViews() 函数调用。在 OnUpdate() 函数中,视图通常会获取文档的指针,更新必要的视图项,然后使窗口无效,以便调用 OnDraw() 函数。 OnUpdate() 函数的声明如下:

virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);

以下是 CStockPriceView 类的 OnUpdate() 函数示例:

void CStockPriceView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
    // get a pointer to the document
    CStockPriceDoc* pDoc = GetDocument();
    // update the symbol and current price
    m_StockSymbol = pDoc->m_StockSymbol;
    m_StockPriceText.Format("%lf", pDoc->m_CurrentPrice);
    // update the price history
    if (m_History)
    {
        delete[] m_History;
    }
    m_Length = pDoc->m_PriceHistory.GetSize();
    m_History = new CString[m_Length];
    for (int i = 0; i < m_Length; i++)
    {
        m_History[i].Format("%lf", pDoc->m_PriceHistory.ElementAt(i));
    }
    // invalidate the window
    CView::OnUpdate(pSender, lHint, pHint);
}
2.3 OnDraw() 函数

OnDraw() 函数与 OnPaint() 函数类似,但 OnDraw() 函数不实例化设备上下文,而是将设备上下文作为参数传递进来。 OnDraw() 函数的声明如下:

virtual void OnDraw(CDC* pDC) = 0;

OnDraw() 是一个纯虚函数,因此继承自 CView 的类必须重写该函数。以下是 CStockPriceView 类的 OnDraw() 函数示例:

void CStockPriceView::OnDraw(CDC* pDC)
{
    // display the stock symbol and price
    pDC->TextOut(10, 20, m_StockSymbol);
    pDC->TextOut(10, 50, m_StockPriceText);
    // display the price history
    for (int index = 0; index < m_Length; index++)
    {
        pDC->TextOut(10, 80 + index * 15, m_History[index]);
    }
}
3. 框架窗口类( CFrameWnd

CFrameWnd 类是文档/视图应用程序的主窗口,包含菜单栏、工具栏和状态栏等。以下是 CMainFrame 类的定义示例:

class CMainFrame : public CFrameWnd
{
public:
    CMainFrame();
    DECLARE_DYNCREATE(CMainFrame)
protected:
    CStatusBar m_wndStatusBar;
    CToolBar m_wndToolBar;
    DECLARE_MESSAGE_MAP()
};
4. 文档模板类( CDocTemplate

CDocTemplate 类用于建立文档类、视图类和主框架之间的关联。根据应用程序是否支持单文档界面(SDI)或多文档界面(MDI),可以选择使用 CSingleDocTemplate CMultiDocTemplate 类。

以下是创建 SDI 文档模板的示例:

BOOL CStockPriceApp::InitInstance()
{
    // create the document template for SDI
    CSingleDocTemplate* pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CStockPriceDoc),
        RUNTIME_CLASS(CMainFrame),
        RUNTIME_CLASS(CStockPriceView));
    // add the template to the application
    AddDocTemplate(pDocTemplate);
    return TRUE;
}
5. MFC 应用程序类型

MFC 应用程序通常可以分为以下三类:
- 对话框应用程序 :主窗口是对话框,不使用文档/视图架构。例如 Windows 拨号网络程序。
- 单文档界面(SDI)应用程序 :使用文档/视图架构,一次只能打开一个文档。
- 多文档界面(MDI)应用程序 :与 SDI 应用程序类似,但可以同时打开多个文档。

6. 使用 MFC AppWizard 创建应用程序

Visual C++ 提供了 AppWizard 工具,用于创建 MFC 应用程序的基本架构。以下是使用 AppWizard 创建 MFC 应用程序的步骤:
1. 打开 Visual C++,选择“File” -> “New”,在“Projects”选项卡中选择“MFC AppWizard (exe)”。
2. 在“Project name”窗口中输入项目名称,并可选择更改项目位置。
3. 点击“OK”按钮,进入 MFC AppWizard。

6.1 选择应用程序类型

在 MFC AppWizard 的第一步,需要选择应用程序的类型,包括对话框应用程序、SDI 应用程序或 MDI 应用程序。

6.2 创建对话框应用程序

如果选择创建对话框应用程序,后续步骤如下:
1. 步骤 2 :选择应用程序的功能,如“About box”、“Context-sensitive Help”、“3D controls”等,还可以选择支持的技术,如“Automation”、“ActiveX Controls”、“Windows Sockets”等。最后输入对话框的标题。
2. 步骤 3 :选择项目风格(默认为“MFC Standard”),指定是否生成源代码注释,以及选择 MFC 库的链接方式(静态链接或共享 DLL)。
3. 步骤 4 :查看要生成的类名,可更改应用程序类的名称。
4. 点击“Finish”按钮,确认生成项目。

以下是 AppWizard 生成的 CStockPriceApp 类的示例代码:

// StockPrice.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "stockPrice.h"
#include "stockPriceDlg.h"

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

// CStockPriceApp
BEGIN_MESSAGE_MAP(CStockPriceApp, CWinApp)
    //{{AFX_MSG_MAP(CStockPriceApp)
    // NOTE - the ClassWizard will add and remove mapping macros here.
    // DO NOT EDIT what you see in these blocks of generated code!
    //}}AFX_MSG
    ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()

// CStockPriceApp construction
CStockPriceApp::CStockPriceApp()
{
    // TODO: add construction code here.
    // Place all significant initialization in InitInstance
}

// The one and only CStockPriceApp object
CStockPriceApp theApp;

// CStockPriceApp initialization
BOOL CStockPriceApp::InitInstance()
{
    AfxEnableControlContainer();

    // 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.
#ifdef _AFXDLL
    Enable3dControls();
#else
    Enable3dControlsStatic();
#endif

    CStockPriceDlg dlg;
    m_pMainWnd = &dlg;
    int nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
        // Call this when using MFC in a shared DLL
        // Call this when linking to MFC statically
        // 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
    }

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

通过使用 MFC AppWizard 和资源编辑器,可以快速开发 MFC 应用程序,将重点放在解决实际问题上,而无需编写重复的 MFC 架构代码。

以下是一个简单的 mermaid 流程图,展示了 MFC AppWizard 创建对话框应用程序的流程:

graph TD;
    A[开始] --> B[选择 MFC AppWizard (exe)];
    B --> C[输入项目名称和位置];
    C --> D[选择应用程序类型: 对话框应用程序];
    D --> E[选择应用程序功能和支持技术];
    E --> F[选择项目风格和 MFC 库链接方式];
    F --> G[查看并修改生成的类名];
    G --> H[点击 Finish 完成项目生成];

综上所述,MFC 的文档/视图架构和 AppWizard 工具为开发者提供了强大的功能和便利,帮助开发者更高效地开发 Windows 应用程序。在实际开发中,开发者可以根据具体需求选择合适的应用程序类型,并利用 AppWizard 生成基本架构,然后在此基础上进行个性化开发。同时,对于视图类中的 GetDocument() OnUpdate() OnDraw() 等函数的理解和使用,也是实现数据展示和交互的关键。

MFC 文档/视图架构与 AppWizard 使用指南

7. 各函数及类的作用总结

为了更清晰地理解 MFC 文档/视图架构中各个部分的作用,下面通过表格进行总结:
| 类/函数 | 作用 |
| ---- | ---- |
| CDocument | 表示应用程序的数据,是数据的载体 |
| CView | 展示文档数据给用户,并提供用户修改数据的接口,包含 GetDocument() OnUpdate() OnDraw() 等重要函数 |
| CFrameWnd | 应用程序的主窗口,包含菜单栏、工具栏和状态栏,为视图提供容器 |
| CDocTemplate | 建立文档类、视图类和主框架之间的关联 |
| GetDocument() | 获取关联文档的指针,方便视图访问文档数据 |
| OnUpdate() | 当文档数据变化时,更新视图项并触发 OnDraw() 函数 |
| OnDraw() | 在视图中进行绘制操作,展示数据 |

8. 不同应用程序类型的特点对比

MFC 应用程序的三种类型各有特点,以下是详细对比:
| 应用程序类型 | 特点 | 适用场景 |
| ---- | ---- | ---- |
| 对话框应用程序 | 主窗口为对话框,不使用文档/视图架构,提供与用户交互的控件,无文档打开关闭操作 | 简单的交互程序,如计算器、音量控制程序 |
| 单文档界面(SDI)应用程序 | 使用文档/视图架构,一次只能打开一个文档 | 专注于单个文档处理的程序,如记事本 |
| 多文档界面(MDI)应用程序 | 与 SDI 类似,但可同时打开多个文档 | 需要同时处理多个文档的程序,如文本编辑器可同时打开多个文本文件 |

9. MFC AppWizard 生成代码的分析

AppWizard 生成的代码包含了很多有用的信息和结构,下面以 CStockPriceApp 类为例进行分析:

// StockPrice.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "stockPrice.h"
#include "stockPriceDlg.h"

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

// CStockPriceApp
BEGIN_MESSAGE_MAP(CStockPriceApp, CWinApp)
    //{{AFX_MSG_MAP(CStockPriceApp)
    // NOTE - the ClassWizard will add and remove mapping macros here.
    // DO NOT EDIT what you see in these blocks of generated code!
    //}}AFX_MSG
    ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()

// CStockPriceApp construction
CStockPriceApp::CStockPriceApp()
{
    // TODO: add construction code here.
    // Place all significant initialization in InitInstance
}

// The one and only CStockPriceApp object
CStockPriceApp theApp;

// CStockPriceApp initialization
BOOL CStockPriceApp::InitInstance()
{
    AfxEnableControlContainer();

    // 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.
#ifdef _AFXDLL
    Enable3dControls();
#else
    Enable3dControlsStatic();
#endif

    CStockPriceDlg dlg;
    m_pMainWnd = &dlg;
    int nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
        // Call this when using MFC in a shared DLL
        // Call this when linking to MFC statically
        // 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
    }

    // Since the dialog has been closed, return FALSE so that we exit the
    // application, rather than start the application's message pump.
    return FALSE;
}
  • 头文件包含 :包含了必要的头文件,如 stdafx.h stockPrice.h stockPriceDlg.h ,确保程序能正常访问相关类和资源。
  • 调试相关宏 #ifdef _DEBUG 部分的代码用于调试模式下的内存管理和文件跟踪。
  • 消息映射 BEGIN_MESSAGE_MAP END_MESSAGE_MAP 之间定义了消息映射,这里处理了 ID_HELP 命令。
  • 构造函数 CStockPriceApp::CStockPriceApp() 中提示开发者可添加初始化代码,但重要初始化应放在 InitInstance() 函数中。
  • InitInstance() 函数 :这是应用程序初始化的关键函数,它启用控件容器,根据不同的 MFC 库链接方式进行 3D 控件初始化,创建对话框实例,调用 DoModal() 显示对话框,并根据对话框返回值进行相应处理。
10. 实际开发中的注意事项

在使用 MFC 文档/视图架构和 AppWizard 进行开发时,有以下几点需要注意:
- 代码注释 :AppWizard 生成的代码中有很多注释,这些注释对于理解代码结构和添加自定义代码非常有帮助,应仔细阅读并遵循注释提示。
- 消息映射 :消息映射部分由 ClassWizard 管理,不要手动修改生成的代码块,否则可能导致编译错误或程序异常。
- 内存管理 :在使用动态分配内存时,如 CStockPriceView 类中的 m_History 数组,要注意及时释放内存,避免内存泄漏。
- MFC 库链接方式 :选择 MFC 库链接方式时,要考虑目标平台是否安装了 MFC DLL,以及可执行文件大小的需求。

11. 未来开发建议
  • 功能扩展 :在生成基本架构后,可以根据实际需求添加更多的功能,如数据处理、网络通信等。例如,在对话框应用程序中添加网络通信功能,可以在选择支持技术时勾选“Windows Sockets”,然后在代码中实现网络连接和数据传输逻辑。
  • 用户界面优化 :利用 MFC 提供的丰富控件和资源编辑器,优化用户界面,提高用户体验。可以调整对话框的布局、添加图标和样式等。
  • 性能优化 :对于处理大量数据的应用程序,要注意性能优化。可以采用缓存机制、多线程处理等技术,提高程序的运行效率。

以下是一个 mermaid 流程图,展示了在 MFC 开发中从创建项目到功能扩展的整体流程:

graph TD;
    A[开始] --> B[使用 AppWizard 创建项目];
    B --> C[分析生成的代码结构];
    C --> D[根据需求修改代码];
    D --> E[添加功能扩展];
    E --> F[优化用户界面];
    F --> G[进行性能优化];
    G --> H[测试和发布程序];

通过以上对 MFC 文档/视图架构和 AppWizard 的详细介绍,开发者可以更好地掌握 MFC 开发的核心要点,利用这些工具和技术高效地开发出高质量的 Windows 应用程序。在实际开发过程中,不断积累经验,灵活运用各种技术和方法,以满足不同的项目需求。

【完美复现】面向配电网韧性提升的移动储能预布局动态调度策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于IEEE33节点的配电网韧性提升方法,重点研究了移动储能系统的预布局动态调度策略。通过Matlab代码实现,提出了一种结合预配置和动态调度的两阶段优化模型,旨在应对电网故障或极端事件时快速恢复供电能力。文中采用了多种智能优化算法(如PSO、MPSO、TACPSO、SOA、GA等)进行对比分析,验证所提策略的有效性和优越性。研究不仅关注移动储能单元的初始部署位置,还深入探讨其在故障发生后的动态路径规划电力支援过程,从而全面提升配电网的韧性水平。; 适合人群:具备电力系统基础知识和Matlab编程能力的研究生、科研人员及从事智能电网、能源系统优化等相关领域的工程技术人员。; 使用场景及目标:①用于科研复现,特别是IEEE顶刊或SCI一区论文中关于配电网韧性、应急电源调度的研究;②支撑电力系统在灾害或故障条件下的恢复力优化设计,提升实际电网应对突发事件的能力;③为移动储能系统在智能配电网中的应用提供理论依据和技术支持。; 阅读建议:建议读者结合提供的Matlab代码逐模块分析,重点关注目标函数建模、约束条件设置以及智能算法的实现细节。同时推荐参考文中提及的MPS预配置动态调度上下两部分,系统掌握完整的技术路线,并可通过替换不同算法或测试系统进一步拓展研究。
先看效果: https://pan.quark.cn/s/3756295eddc9 在C#软件开发过程中,DateTimePicker组件被视为一种常见且关键的构成部分,它为用户提供了图形化的途径来选取日期时间。 此类控件多应用于需要用户输入日期或时间数据的场景,例如日程管理、订单管理或时间记录等情境。 针对这一主题,我们将细致研究DateTimePicker的操作方法、具备的功能以及相关的C#编程理念。 DateTimePicker控件是由.NET Framework所支持的一种界面组件,适用于在Windows Forms应用程序中部署。 在构建阶段,程序员能够通过调整属性来设定其视觉形态及运作模式,诸如设定日期的显示格式、是否展现时间选项、预设的初始值等。 在执行阶段,用户能够通过点击日历图标的下拉列表来选定日期,或是在文本区域直接键入日期信息,随后按下Tab键或回车键以确认所选定的内容。 在C#语言中,DateTime结构是处理日期时间数据的核心,而DateTimePicker控件的值则表现为DateTime类型的实例。 用户能够借助`Value`属性来读取或设定用户所选择的日期时间。 例如,以下代码片段展示了如何为DateTimePicker设定初始的日期值:```csharpDateTimePicker dateTimePicker = new DateTimePicker();dateTimePicker.Value = DateTime.Now;```再者,DateTimePicker控件还内置了事件响应机制,比如`ValueChanged`事件,当用户修改日期或时间时会自动激活。 开发者可以注册该事件以执行特定的功能,例如进行输入验证或更新关联的数据:``...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值