用CSplitterWnd类创建分割窗口
在msdn里有一个例子viewex,演示了创建并使用分割窗口的方法。不过那个
程序稍微有点大。让我们依样画葫芦来搞个简单的例子。在msdn里有一个例子viewex,演示了创建并使用分割窗口的方法。不过那个程序稍微有点大。让我们依样画葫芦来搞个简单的例子。
用CSplitterWnd类可以做一个可以分割的窗口。不过要用这个类的话,得劳
动文档类,文档模板类和视图类这三个复杂类的大驾。
由于CView类的OnDraw函数是个纯虚函数,所以我们必须从CView类派生一个
自己的类CMyView并覆盖OnDraw函数。CDocument类可以直接用,但如果不从CDoc
ument类派生一个自己的类的话,文档类用处不大,所以我们也从CDocument派生
一个CMyDoc类。文档模板类嘛,我们就直接用CSingleDocTemplate类。
我们还要从CFrameWnd类派生一个CMyWnd类并覆盖OnCreateClient函数。
在CMyView类,CMyDoc类和CMyWnd类的声明里,必须加上DECLARE_DYNCREATE
(...),在类声明的外面必须加上IMPLEMENT_DYNCREATE(...)。这样才能正常使用
一个宏RUNTIME_CLASS。
由于CSingleDocTemplate类的构造函数需要一个资源ID为参数,所以我们要
用资源编辑器搞个菜单或别的什么资源,它的ID可以定为IDT_MYFRAME1。或者根
本不去做菜单直接在程序开头加个#define IDT_MYFRAME1=1来欺骗一下CSingleD
ocTemplate类的构造函数也可以。
创建可分割窗口的步骤:
1。在CMyWnd类里加个成员变量CSplitterWnd m_MySplitter;
2。在运用程序类的InitInstance函数里加上:
pDocTemplate = new CSingleDocTemplate(
IDT_MYFRAME1,
RUNTIME_CLASS(CDocument),
RUNTIME_CLASS(CMyWnd),
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
3。在CMyWnd的OnCreateClient函数里加上:
m_MySplitter.CreateStatic(this,1,2);
m_MySplitter.CreateView(0,0,
RUNTIME_CLASS(CMyView), CSize(250, 150), pContext);
m_MySplitter.CreateView(0,1,
RUNTIME_CLASS(CMyView), CSize(250, 0), pContext);
SetActiveView((CView*)m_MySplitter.GetPane(0,0));
return 1;
此时在OnCreateClient函数内部就不能去调用该函数的基类版本了。Create
Static的作用是创建分割窗口的框架,其第一个参数是说把框架窗口作为分割窗口
的父窗口。第二第三个参数表示该分割窗口有一行,两列,也就是有两个面板。
所以接下来得分别用CreateView来为每个面板创建视图。为简单起见这两个面板
我们都使用同一个视图,你完全可以先派生出两个视图类,然后每个面板使用自
己的视图。
CreateView函数的第一第二个参数用来指明为哪个面板创建视图。第一个参
数是行,从零开始,第二个参数是列,也从零开始。
好了,编译并运行程序,一个被分割成左右两部分的窗口出来了。
如果要创建被分成上下两半的窗口怎么办?只须创建两行一列的分割窗口就
可以了嘛。修改后的OnCreateClient函数里的代码如下:
m_MySplitter.CreateStatic(this,2,1);
m_MySplitter.CreateView(0,0,
RUNTIME_CLASS(CMyView), CSize(250, 150), pContext);
m_MySplitter.CreateView(1,0,
RUNTIME_CLASS(CMyView), CSize(250, 0), pContext);
SetActiveView((CView*)m_MySplitter.GetPane(0,0));
return 1;
我们还可以创建一个田字形的分割窗口。这只须创建两行两列的分割窗口就
可以了。修改后的OnCreateClient函数里的代码如下:
m_MySplitter.CreateStatic(this,2,1);
m_MySplitter.CreateView(0,0,
RUNTIME_CLASS(CMyView), CSize(250, 150), pContext);
m_MySplitter.CreateView(1,0,
RUNTIME_CLASS(CMyView), CSize(250, 0), pContext);
m_MySplitter.CreateView(0,1,
RUNTIME_CLASS(CMyView), CSize(150, 150), pContext);
m_MySplitter.CreateView(1,1,
RUNTIME_CLASS(CMyView), CSize(150, 150), pContext);
SetActiveView((CView*)m_MySplitter.GetPane(0,0));
return 1;
如果要创建被分割成三部分的窗口怎么办?这就稍微复杂点。必须先把窗口
分割成两个,再把其中一个面板分割成两个,即使用嵌套的分割窗口,这就出来
了三个面板了。我们举个例子,先把窗口分成上下两半,再把下面那个面板分成
左右两半。步骤:
1。再在CMyFrame类里加个成员变量:CSplitterWnd m_MySplitter2;
2。调用m_MySplitter的成员函数CreateStatic先创建一个分割成上下两半的分割
窗口框架。
3。调用m_MySplitter的成员函数CreateView在上面那个面板里创建视图。但是下
面那个面板我们就空着不创建视图。
4。调用函数:
m_MySplitter2.CreateStatic(&m_MySplitter,2,1,WS_CHILD|WS_VISIB
LE,
m_MySplitter.IdFromRowCol(1, 0));
其中最后一个参数的意思是指明我们的第二个嵌套的分割窗口将被创建在m_
MySplitter创建的分割窗口的第1行第0列那个面板里,也就是下半部那个面板里
。
5。调用m_MySplitter2.CreateView分别为新的嵌套的分割窗口的两个面板创建视
图。
修改后的CMyWnd::OnCreateClient函数里的代码如下:
m_MySplitter.CreateStatic(this,2,1);
m_MySplitter.CreateView(0,0,
RUNTIME_CLASS(CMyView), CSize(250, 100), pContext);
m_MySplitter2.CreateStatic(&m_MySplitter,2,1,WS_CHILD|WS_VISIBLE
,
m_MySplitter.IdFromRowCol(1, 0));
m_MySplitter2.CreateView(0,0,
RUNTIME_CLASS(CMyView), CSize(250, 100), pContext);
m_MySplitter2.CreateView(1,0,
RUNTIME_CLASS(CMyView), CSize(250, 0), pContext);
SetActiveView((CView*)m_MySplitter.GetPane(0,0));
return 1;
注意别忘了CMyWnd里再加一个 CSplitterWnd m_MySplitter2;
在我们这个例子里,所有的面板使用同一个视图类来创建视图,因此所有的
面板上都显示同样的东西。
下面是例子程序:
//这是个手工录入的mfc程序。编译时请一定在
//Project/settings的General项里的
//MicroSoft foundation class选项里选择
//“Use MFC in a shared DLL”
//该程序用msvc++6.0编译通过。
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"
class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
class CMyWnd : public CFrameWnd
{
DECLARE_DYNCREATE(CMyWnd)
private:
CSplitterWnd m_MySplitter;
CSplitterWnd m_MySplitter2;
public:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs,
CCreateContext *pContext);
DECLARE_MESSAGE_MAP()
};
class CMyView:public CView
{
DECLARE_DYNCREATE(CMyView)
public:
virtual void OnDraw( CDC* pDC ) ;
DECLARE_MESSAGE_MAP()
};
class CMyDoc:public CDocument
{
DECLARE_DYNCREATE(CMyDoc)
public:
DECLARE_MESSAGE_MAP()
};
CMyApp MyApp;
IMPLEMENT_DYNCREATE(CMyWnd, CFrameWnd)
IMPLEMENT_DYNCREATE(CMyView, CView)
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)
BEGIN_MESSAGE_MAP(CMyApp,CWinApp)
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyWnd,CFrameWnd)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyView,CView)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyDoc,CDocument)
END_MESSAGE_MAP()
BOOL CMyApp::InitInstance()
{
CSingleDocTemplate* pDocTemplate = new CSingleDocTemplate(
IDT_MYFRAME1,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyWnd),
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
OnFileNew();//该函数不但建立一个空文档,还创建主框架窗口
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
BOOL CMyWnd::OnCreateClient(LPCREATESTRUCT lpcs,CCreateContext *pConte
xt)
{
//这里的代码自己加。
return 1;
}
void CMyView::OnDraw(CDC *pDC)
{
pDC->TextOut(20,40,"分割窗口的面板");
}
注意: class CMy222Doc; class CMy222View : public CView { protected: // create from serialization only CMy222View(); DECLARE_DYNCREATE(CMy222View) // Attributes public: CMy222Doc* GetDocument();
从系统的CSplitterWnd类派生一个新类。
在类视图中右键,选择“添加”->“类”,在弹出窗口中选择MFC类,输入新类的名字CMySplitter,基类选择为CWnd(这里基类的选项里面没有CSplitterWnd,所以要先选择Cwnd)。然后把生成的MySplitter.h和MySplitter.cpp里面的三个地方的“Cwnd”改成“CSplitterWnd”。
MySplitter.h中:
class CMySplitter : public CSplitterWnd
Mysplitter.cpp中:
IMPLEMENT_DYNAMIC(CMySplitter, CSplitterWnd)
BEGIN_MESSAGE_MAP(CMySplitter, CSplitterWnd)
1. 双击分隔栏展开或者收起左边的一栏
重载OnLButtonDblClk函数:
void CMySplitterWnd::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//CSplitterWnd::OnLButtonDblClk(nFlags, point);
int left, min;
GetColumnInfo(0, left, min); //得到第0栏(即左边的一栏)的宽度
if(left == 0 || left == min) //如果当前已经是收起的状态
{
SetColumnInfo(0, 250, 10); //重新设置左边一栏的宽度,这里设置为250,即展开
}
else
{
SetColumnInfo(0, 0, 10); //重新设置左边一栏的宽度,这里设置为0,即收起
}
RecalcLayout(); //重新构建窗口布局
}
2. 设置分隔栏的宽度
在CMySplitter的构造函数中(这里是把宽度设为11像素):
m_cxSplitterGap = 11;
m_cxSplitter = 11;
几个相关变量的意义:
//int m_cxSplitter, m_cySplitter; // size of splitter bar
//int m_cxBorderShare, m_cyBorderShare; // space on either side of splitter
//int m_cxSplitterGap, m_cySplitterGap; // amount of space between panes
//int m_cxBorder, m_cyBorder; // borders in client area
3. 禁止拖动分隔栏的位置
(1)重载OnLButtonDown函数,改成什么都不做:
void CMySplitter::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//CSplitterWnd::OnLButtonDown(nFlags, point);
}
(2)重载OnMouseMove函数,也改成什么都不做:
void CMySplitter::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//CSplitterWnd::OnMouseMove(nFlags, point);
}
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/yuntongsf/archive/2009/06/09/4255244.aspx