创建简单的MFC SDI应用程序

在开发MFC应用程序时,有时候只需要一个简单的分割窗口界面,而不需要文档/视图架构带来的额外代码。本文将指导创建一个包含分割主窗口、工具栏和状态栏的简单SDI应用程序。这个窗口将被分割成左右两个部分,这两个部分都是基于资源的,并且可以在资源编辑器中轻松修改,就像创建一个基于对话框的简单应用程序一样。

创建项目

首先,打开Visual Studio并创建一个新的MFC应用程序项目。给项目命名,然后点击“OK”。接下来,选择“单文档”,取消勾选“文档/视图架构”,取消勾选“使用Unicode库”,并选择“在静态库中使用MFC”。继续点击“Next”,不需要数据库支持,保持默认设置,这将为项目添加状态栏和工具栏。然后取消勾选“ActiveX控件”和“公共控件清单”,除非确定项目中需要使用ActiveX控件和新的XP特定控件,否则没有必要增加额外的开销。点击“Finish”完成项目创建。

编译并运行项目

编译并运行项目后,会注意到标题栏上的图标被设置为了默认图标,而不是项目资源文件中定义的图标。这是一个在Visual Studio中存在多年的bug。以下是如何修复它的方法。

在IDE中,选择类视图并双击“InitInstance”。应该看到以下代码:

CWinApp::InitInstance();

为了改变标题栏上的图标,首先需要创建一个图标,然后告诉主应用程序窗口使用它。在“UpdateWindow”之后但“return”之前添加以下代码:

HICON hIcon; hIcon = LoadIcon(IDR_MAINFRAME); AfxGetMainWnd()->SendMessage(WM_SETICON, TRUE, (LPARAM)hIcon);

与可能认为的不同,LoadIcon实际上并不加载图标,它只是创建图标。必须使用SendMessage告诉应用程序使用新图标。

添加分割窗口

现在,是时候添加承诺的分割窗口了。为了拥有一个分割窗口,将使用一个名为CSplitterWnd的类。在类视图中,右键点击CMainFrame并选择“添加变量”。将访问权限更改为“Protected”,变量类型更改为“CSplitterWnd”,变量名称更改为“m_wndSplitter”,然后点击“Finish”。

由于分割将在客户区进行,因此代码需要在CMainFrame中的一个名为OnCreateClient的重写函数中。在类视图中,选择CMainFrame。在属性区域,按下“Overrides”按钮并滚动到“OnCreateClient”并添加函数。

if (!m_wndSplitter.CreateStatic(this, 1, 2)) return FALSE;

这将为创建一个静态分割窗口,它将有一个行和两列。但是,不要急于编译。仍然需要告诉分割器在每个窗格中显示什么,并且需要摆脱Visual Studio为创建的旧视图。

使用资源编辑器

为了本教程,让使用基于资源的表单。这将使添加控件变得容易,并使这个项目成为构建其他应用程序的模板。切换到资源视图,展开对话框叶,右键单击并选择“插入对话框”。这将插入一个新的对话框资源并在资源编辑器中打开它。

删除“OK”和“Cancel”按钮。右键单击对话框并选择属性。在属性中,更改:

  • 边框为“None”。
  • 控件为“True”。
  • ID为“IDD_FORM_LEFT”。
  • 样式为“Child”。

现在以相同的方式添加一个新的对话框,但将ID更改为IDD_FORM_RIGHT。

在资源视图中,双击IDD_FORM_LEFT。这将在资源编辑器中打开左侧表单。右键单击编辑器中的对话框并选择“添加类”。将基类更改为“CFormView”,名称更改为“CFormLeft”,然后点击“Finish”。重复此过程对IDD_FORM_RIGHT资源进行操作,但将类名称更改为CFormRight。

实现分割视图

现在有了分割器要显示的视图。在MainFrm.cpp中,添加头文件行:

#include "FormLeft.h" #include "FormRight.h"

滚动到OnCreateClient函数并添加分割器的创建视图调用。在分割器创建之后但在返回之前添加以下代码:

if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CFormLeft), CSize(125, 100), pContext) || !m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CFormRight), CSize(100, 100), pContext)) { m_wndSplitter.DestroyWindow(); return FALSE; }

OnCreateClient函数现在应该看起来像这样。

删除旧视图

现在需要摆脱Visual Studio为创建的旧视图以及任何对旧视图的使用。

滚动到OnCmdMsg函数并删除:

if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;

滚动到OnSetFocus函数并删除:

m_wndView.SetFocus();

滚动到OnCreate函数并删除:

// create a view to occupy the client area of the frame if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL)) { TRACE0("Failed to create view window\n"); return -1; }

在MainFrm.h的顶部,删除:

#include "ChildView.h"

向下滚动并删除:

CChildView m_wndView;

在解决方案资源管理器中,右键单击“ChildView.h”,然后选择“Remove”。在弹出框中,按“Delete”按钮。以相同的方式删除“ChildView.cpp”。

编译并运行

现在可以编译并运行了,将拥有一个带有分割窗口的SDI。试试它,拖动分割条:

目前它还没有任何功能,但可以添加控件并使用资源编辑器。

然而,每个窗格中的控件只能影响同一窗格中的控件。为了使左侧窗格中的控件影响右侧窗格中的控件,需要重新路由一些消息。

在类视图中,右键单击“CFormLeft”并选择“添加变量”。将访问权限设置为“protected”,类型设置为“CWnd*”,名称设置为“m_target”。点击“Finish”。

在类视图中,右键单击“CFormLeft”并选择“添加函数”。将返回类型设置为“void”,名称设置为“SetTarget”,并添加一个名为“m_cwnd”的参数类型为“CWnd*”。点击“Finish”。

在类视图中选择“CFormLeft”。点击Overrides按钮并滚动到OnCommand并使用下拉框添加函数。

在OnCommand函数中添加以下代码:

if (m_target) { m_target->SendMessage(WM_COMMAND, wParam, lParam); } else { CFormView::OnCommand(wParam, lParam); } return true;

在CMainFrame的OnCreateClient函数中,在分割器创建视图之后但在返回之前添加以下代码:

//set the target for mapped messages ((CFormLeft*)m_wndSplitter.GetPane(0, 0))->SetTarget(m_wndSplitter.GetPane(0, 1));

添加控件并测试

打开IDD_FORM_RIGHT资源编辑器并添加一个静态文本控件。将ID更改为IDC_STATIC_HELLO,标题更改为“点击按钮”,并设置文本对齐方式为居中。

右键单击静态控件并选择“添加变量”。点击控件类型复选框,类型设置为“CStatic”,名称设置为“m_hello”。点击“Finish”。

打开IDD_FORM_LEFT资源编辑器并添加一个按钮。将ID更改为IDC_BUTTON_HELLO,标题更改为“Say Hello”。

右键单击按钮并选择“添加事件处理程序”。选择消息类型BN_CLICKED和类列表中的“CFormRight”,然后点击“Add”和“Edit”。

在OnBnClickedButtonHello函数中添加以下代码:

m_hello.SetWindowText("Hello Window Splitter!");
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485