65.9K
CodeProject 正在变化。 阅读更多。
Home

带分割窗口的 SDI

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (65投票s)

2006年8月26日

CPOL

7分钟阅读

viewsIcon

338230

downloadIcon

4425

创建一个带分割窗口的SDI,而无需文档/视图架构的所有额外冗余。

Sample Image - SplitWindow.jpg

引言

您是否曾想在程序中使用分割窗口,但又不想使用文档/视图架构的所有额外冗余?

在新项目向导中,为了使“分割窗口”复选框可用,您必须选择“文档/视图架构支持”。如果您只需要一个分割的主窗口,这会在您的项目中添加许多不必要的额外代码。

在本文中,我将引导您创建一个简单的SDI,它带有一个分割的主窗口、一个工具栏和一个状态栏。窗口将分为左右两个窗格,它们基于资源,可以像创建简单的基于对话框的应用程序一样在资源编辑器中轻松修改。

这些说明和项目文件适用于Visual Studio 2005;虽然它们可能在旧版本的Visual Studio中有效,但您需要自行适应。

启动Visual Studio并创建一个新项目。选择MFC应用程序,为您的项目命名,然后单击“确定”。

单击“下一步”。

为了尽可能简单,我们将为项目使用最少的选项。

选择“单文档”,取消选中“文档/视图架构”,取消选中“使用Unicode库”,然后选择“在静态库中使用MFC”。单击“下一步”。

我们不需要任何数据库支持,因此只需单击“下一步”。

在此页面上,我们将保留默认设置。这将为我们提供一个状态栏和一个工具栏。SDI项目中不错的配置。点击“下一步”。

取消选中“ActiveX控件”和“通用控件清单”;除非您知道要在项目中使用ActiveX控件和新的XP特定控件,否则没有理由增加额外的开销。点击“下一步”。

如果他们让我们选择我们想要什么样的子视图就好了,但他们没有,所以只需点击“完成”。

编译并运行项目。

请注意,标题栏上的图标设置为默认图标,而不是项目资源文件中定义的图标。这是Visual Studio中多年来一直存在的错误。以下是修复方法。

在IDE中,选择类视图并双击“InitInstance”。

您应该会看到:

要更改标题栏上的图标,首先我们需要创建一个图标,然后我们需要告诉主应用程序窗口使用它。将以下代码放在“UpdateWindow”之后但在“return”之前。

//Create and load the titlebar icon
HICON hIcon;
hIcon = LoadIcon(IDR_MAINFRAME);    
AfxGetMainWnd()->SendMessage(WM_SETICON,TRUE,(LPARAM)hIcon);

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

您的“InitInstance”现在应该如下所示

现在当您编译并运行时,您应该会在标题栏上看到资源定义的图标。

您现在可以使用资源编辑器将图标更改为您想要的任何内容。

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

由于分割将在客户区中,因此其代码将需要位于CMainFrame中名为OnCreateClient的覆盖函数中。

在类视图中,选择CMainFrame。在属性区域中,按下“重写”按钮,向下滚动到“OnCreateClient”并使用右侧的组合框添加函数。

将以下代码添加到OnCreateClient函数中

// create splitter window
if (!m_wndSplitter.CreateStatic(this, 1, 2))
    return FALSE;

这将为我们创建一个静态分割窗口,它将有一行两列。

但是等等,不要急着编译。我们仍然需要告诉分割器在每个窗格中显示什么,并且我们需要删除Visual Studio为我们创建的旧视图。

对于本教程,让我们使用基于资源的表单。这将使添加控件和将此项目用作构建其他应用程序的模板变得容易。

切换到资源视图,展开对话框叶,右键单击并选择“插入对话框”。这将插入一个新的对话框资源并在资源编辑器中打开它。

删除“确定”和“取消”按钮。右键单击对话框并选择“属性”。

在属性中,更改

  • 边框为“无”。
  • 控件为“真”。
  • ID为“IDD_FORM_LEFT”。
  • 样式为“子”。

现在以同样的方式添加一个新对话框,但将ID设置为:IDD_FORM_RIGHT

在资源视图中,双击IDD_FORM_LEFT。这将在资源编辑器中打开左侧表单。右键单击编辑器中的对话框并选择“添加类”。

将基类更改为“CFormView”,名称更改为“CFormLeft”,然后点击“完成”。

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”,然后选择“删除”。在弹出的框中,按下“删除”按钮。

以同样的方式删除“ChildView.cpp”。

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

此时它不执行任何操作,但您可以使用资源编辑器添加控件。

但是,每个窗格中的控件只能影响同一窗格中的控件。为了让左窗格中的控件影响右窗格中的控件,我们需要重新路由一些消息。

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

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

SetTarget函数中,添加代码

m_target = m_cwnd;

您应该会看到:

接下来我们需要重写OnCommand函数。在类视图中选择“CFormLeft”。点击“重写”按钮,向下滚动到OnCommand并使用下拉框添加函数。

OnCommand函数中,添加以下代码

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

您应该会看到:

这将把此窗体的消息发送到我们设置的目标窗口。现在我们想将目标设置为右窗格中的窗体。

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

//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”。点击“完成”。

在资源编辑器中打开IDD_FORM_LEFT并添加一个按钮。

ID更改为IDC_BUTTON_HELLO,标题更改为“Say Hello”。

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

OnBnClickedButtonHello函数中,添加以下代码

m_hello.SetWindowText("Hello Window Splitter!");

您的函数应该如下所示

编译并运行您的程序。单击“Say Hello”按钮,您应该会看到右窗格中的文本发生变化。现在尝试拖动分割条,您应该会看到右窗格中的文本随分割条移动。

希望本文对您有所帮助。

© . All rights reserved.