VC++ 6.0中实现三叉切分窗口与多视图 [转]
一、引用
当用户需要同时对文当的不同部分进行编辑时,常常会用到切分窗口;这些窗口可以都是相同的视,或者一个窗口为列表视,而另一个为树型视图。应用程序框架有多种方式来表示多视图,切分窗口是其中的方式之一。
切分窗口分为动态切分窗口和静态切分窗口,它们都是由CsplitterWnd类(MFC类库)来实现的,在这两种表示方式中,创建同一视图类的对象是比较容易的(Cview),而在同一应用程序使用两个或更多的视图类(如:ClistView、CtreeView等),相对来说则要困难一些。
动态切分功能多应用在编辑文本类的软件中,在实际的开发中,我们经常要用到的是静态切分功能。静态切分窗口是指在窗口创建时,切分窗口的窗格就已经创建好了,且窗格的数量和顺序不会改变,窗格为一个分隔条所分隔,用户可以拖动分隔条调整相应窗格的大小。静态切分窗口最多支持16行´16列的窗格,而且不同的窗格往往使用不同的视图类。本文主要阐述静态切分窗口。
二、实例
以单文档SDI应用程序为例,在框架客户区实现三叉切分窗口,且每个窗格使用不同的视图 。
实现步骤:
1、 利用VC++6.0 的AppWizard创建一个单文档SDI应用程序,项目名为Test。
2、 使用New Class对话框添加新的视图类:
CinfoView 基类为列表视图类ClistView
CLineView 基类为表单视图类CFormView
CMyEditView 基类为编辑视图类CEditView
要点:在添加ClineView之前,需要先创建一个对话模板资源,ID为IDD_FORMVIEW,
3、 在框架窗口类CMainFrame中声明一个CsplitterWnd类的成员变量m_wndSplitter1,用于第一次切分。
4、 使用ClassWizard为框架窗口类添加OnCreateClient函数。
注意:OnCreateClient函数的调用在OnCreate函数之后,在构造视图对象和产生视图窗口之前。
5、 在OnCreateClient函数中调用CsplitterWnd::CreateStatic,产生静态切分。该函数的原形如下:
BOOL CreateStatic( CWnd* pParentWnd, int nRows, int nCols, DWORD dwStyle =WS_CHILD | WS_VISIBLE, UINT nID =AFX_IDW_PANE_FIRST );
函数有5个参数,意义如下:
● pParentWnd:切分窗口的父窗口指针
● nRows:水平方向分隔窗口的数目
● nCols:垂直方向分隔窗口的数目
● dwStyle:切分窗口的风格
● nID:子窗口的ID值,默认为系统定义的AFX_IDW_PANE_FIRST
返回值:如果创建成功,返回非零值(TRUE),否则返回0(FALSE)。
m_wndSplitter1.CreateStatic(this, 2,1); // 切分为行列
6、 使用CreateView产生每个视图窗口
virtual BOOL CreateView( int row, int col, CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext );
函数有5个参数,意义如下:
● row:窗格的行标,从0开始
● col:窗格的列标,从0开始
● pViewClass:视图的执行期类CRuntimeClass指针,可以用宏RUNTIME_CLASS获得
● sizeInit:一个SIZE(或者CSize)类型的数据,指定窗格的初始大小
● pContext:一般是由父窗口传递过来,包含窗口的创建信息
返回值:如果创建成功,返回非零值(TRUE),否则返回0(FALSE)。
OnCreateClient函数的全部代码:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class CRect rect; GetClientRect(&rect); //产生第一次静态切分
m_wndSplitter1.CreateStatic(this, //父窗口指针 2, // 切分的行数 1); // 切分的列数 //为第一个窗格产生视图 m_wndSplitter1.CreateView(,, // 窗格的行、列序数 RUNTIME_CLASS(CTestView),//视图类 CSize(rect.Width(),rect.Height()-rect.Height()/),//初始化大小 pContext);//父窗口的创建参数 //为第二个窗格产生视图 m_wndSplitter1.CreateView(,, RUNTIME_CLASS(CMyEditView), CSize(rect.Width(),rect.Height()/), pContext); return TRUE;//不再调用基类的OnCreateClient函数 //return CFrameWnd::OnCreateClient(lpcs, pContext); }
在这里需注意3点:
① 必须为每个静态切分窗格创建视图窗口,不能漏掉一个;
② 必须包含相应的类的头文件,在MainFrm.cpp文件的开始包含一下头文件:
#include "TestView.h"
#include "MyEditView.h"
③产生静态切分后,就不能调用默认的基类的OnCreateClient函数。
7、 在视图窗口类CTestView中声明一个CsplitterWnd类的成员变量m_wndSplitter2,用于第二次切分。
8、 使用ClassWizard为视图窗口类CTestView添加OnCreate函数,在该函数中调用CreateStatic函数和CreateView函数,类似CMainFrame::OnCreateClient函数中的调用
代码如下:
int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{ if (CView::OnCreate(lpCreateStruct) == -)
return -; // TODO: Add your specialized creation code here
CRect rect;
GetClientRect(&rect); //获得窗口的创建信息指针
CCreateContext *pContext = (CCreateContext*) lpCreateStruct->lpCreateParams; //产生二次静态切分
m_wndSplitter2.CreateStatic(this,, ); //为第一个窗格产生视图
m_wndSplitter2.CreateView(,,// 窗格的行、列序数 RUNTIME_CLASS(CLineView),//视图类 CSize(rect.Width()/,rect.Height()),//初始化大小 pContext);//父窗口的创建参数 //为第二个窗格产生视图
m_wndSplitter2.CreateView(,, RUNTIME_CLASS(CInfoView), CSize(,), pContext); return ; }
注意:二次切分的父窗口是第一次切分的第一个窗格,其视图类是CTestView
9、使用ClassWizard为视图窗口类CTestView添加OnSize函数,在该函数中调用子函数
SwitchView(),子函数的代码如下:
void CTestView::SwitchView()
{ CRect rect; GetClientRect(&rect); int cx = rect.Width(); int cy = rect.Height(); m_wndSplitter2.MoveWindow(-,-,cx,cy+); m_wndSplitter2.SetColumnInfo(, cx/,); m_wndSplitter2.SetColumnInfo(, cx-cx/, ); m_wndSplitter2.RecalcLayout(); }
该子函数主要用于设置二次切分后的各列信息,通过CSplitterWnd::SetColumnInfo函数实现,原型为:void SetColumnInfo( int col, int cxIdeal, int cxMin );
由3 个参数,意义如下:
● col:切分窗口的列标识
● cxIdeal:列的实际宽度,单位为像素
● cxMin:列的最小宽度,单位为像素
本示例的运行结果如下:
10、因为每个CView派生类都已经继承了GetDocument()函数,因此只要在调用时直接调用无需再在其中声明GetDocument()函数了,调用后再进行类型强制转换应该就可以了。比方,在TestView.h中注释掉
// Attributes
// CTestDoc* GetDocument();
在TestView.cpp中注释掉
//CTestDoc* CTestView::GetDocument() // non-debug version is inline
//{
//ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTestDoc)));
//return (CTestDoc*)m_pDocument;
//}
并在OnDraw中试用如下代码
void CTestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc =(CTestDoc*)CTestView:: GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
三、总结
切分窗口的形式和每个窗格所使用的视图类可以根据实际需要来确定,以满足程序的不同应用。本示例使用了三叉切分,视图类使用了列表视图类CListView、表单视图类CFormView、编辑视图类CEditView,在VC++6.0下调试通过。
三叉切分的方法并不唯一,本文实例是我在实际开发中总结的一种方法,读者可以通过本例举一反三,掌握切分窗口与多视图相结合的精髓所在。
一、关于CSplitterWnd类
1、用来创建动态切分窗口
BOOL Create(CWnd* pParentWnd,int nMaxRows,int nMaxCols,SIZE sizeMin,CCreateContext* pContext,DWORD dwStyle,UINT nID);
2、用来创建静态切分窗口
BOOL CreateStatic(CWnd* pParentWnd,int nRows,int nCols,DWORD dwStyle,UINT nID)
3、为静态切分的窗口的网格填充视图
BOOL CreateView (int row,int col,CruntimeClass* pViewClass,SIZE sizeinit,CcreateContext* pContext);
4、参数说明
pParentWnd 切分窗口的父框架窗口。
nMaxRows,nMaxCols是创建的最大的列数和行数。
sizeMin是窗格的现实大小。
pContext 大多数情况下传给父窗口。
nID是字窗口的ID号.
二、创建嵌套分割窗口
1、动态分割窗口
动态分割窗口使用Create方法,例:m_wndSplitter.Create(this,2,2,CSize(100,100),pContext); 但是一般不使用动态分割,不实用
2、静态分割窗口(适用于SDI、MDI程序)
1)创建单文档ww,生成的视类为CWwView,从CFormView继承;再增加个视类或者从视类继承而来的派生类CView2、CView3。
2)在框架类CMainFrame的.cpp文件中加入头文件,并在CWwView类定义前加上 class CWwDoc;
#include "view2.h "
#include "view3.h "
#include "wwView.h " //注意这里,必须在CWwView类定义前加上class CWwDoc;否则编译条错误
3)在框架类CMainFrame中增加成员:
CSplitterWnd m_wndSplitter1;
CSplitterWnd m_wndSplitter2;
4)利用ClassWizard重载CMainFrame::OnCreateClient()函数
//--------------------------------------------------
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
//创建一个行列
m_wndSplitter1.CreateStatic(this,,); //将CWwView连接到行列窗格上
m_wndSplitter1.CreateView(,,RUNTIME_CLASS(CWwView),CSize(,),pContext); //将窗口右边再分开行列
m_wndSplitter2.CreateStatic(&m_wndSplitter1,,,WS_CHILD|WS_VISIBLE, m_wndSplitter1.IdFromRowCol(, )); m_wndSplitter2.CreateView(,,RUNTIME_CLASS(CView2),CSize(,),pContext); m_wndSplitter2.CreateView(,,RUNTIME_CLASS(CView3),CSize(,),pContext); return TRUE;
}
//-------------------------------------------------
注意:
① 必须为每个静态切分窗格创建视图窗口,不能漏掉一个;
② 如果从一个CformView类继承的视类,此对话框要作如下设置
style=Child
Border=None
Visible=不选中
③ 若在CWwView窗口上放入一TreeCtrl,为了在改变窗口时随窗口大小而改变(类似CB中的居中),可以在CWwView类的WM_SIZE中添加代码如下:
//-------------------------------------------------
void CWwView::OnSize(UINT nType, int cx, int cy)
{
CFormView::OnSize(nType, cx, cy); // TODO: Add your message handler code here
if (GetSafeHwnd())
{
CRect rect;
GetClientRect(&rect); if (m_TreeCtrl.GetSafeHwnd())
m_TreeCtrl.MoveWindow(&rect);
}
}
//------------------------------------------------ //在WM_ONINITALUPDATE消息中,添加初始化数据
void CWwView::OnInitialUpdate()
{
CFormView::OnInitialUpdate(); GetParentFrame()-> RecalcLayout(); ResizeParentToFit(); //上面的代码不用管,是啥就是啥,
m_TreeCtrl.InsertItem( "ListCtrl View ",, ); m_TreeCtrl.InsertItem( "EditCtrl View ",, ); }
三、实现各个分割区域的通信
点击Button1按钮,在CView2中显示文字
1、在CWwView的.cpp文件中加入:
#include "view2.h "
#include "MainFrm.h "
2、添加按钮代码:
//-------------------------------------------------
void CWwView::OnButton1()
{
//得到一SplitterView的指针
CView2 *pView=(CView2*)(((CMainFrame*)AfxGetMainWnd())-> m_wndSplitter2.GetPane(,)); //定义View的DC
CClientDC dc(pView); dc.MoveTo(,); dc.LineTo(,); dc.TextOut(,, "m_wndSplitter2的行列就是CView2 ");
}
//-------------------------------------------------
转自:http://www.cppblog.com/Lee7/archive/2008/12/22/70036.html
VC++ 6.0中实现三叉切分窗口与多视图 [转]的更多相关文章
- VC++6.0中ClassView中类消失 解决方案[转自网络]
有时候在VC++6.0中编程会出现这样一个问题,由于对C...View类的操作后,在窗口左边ClassView框中的C...View类会消失,这种操作通常是在C...View类中右击点“Add Win ...
- VC++ 6.0 中使用 MSComm.ocx
很多人喜欢单独安装VC++6.0,而不是完整安装VS,这样占用空间比较少,启动也快.但是要使用某些ActiveX控件的时候却会出现许可证问题(requires a design-time licenc ...
- vc++6.0中查看函数栈的结构
栈:一种后进先出的数据结构 比如:弹夹 函数调用的约定 传参顺序 传参媒介 如何传递返回值 平衡参数(堆栈平衡):有且只有被调方(callee)和调用方(caller)一方执行 _cdell (c ...
- wxWidgets编译和在VC 6.0中的配置
1. 安装 运行wxMSW-2.8.3-Setup1.exe,将之安装到不带空格符号的目录中,本例为C:/wxWidgets-2.8.3: 2. 编译和配置 (1) 用VC6.0编译 进入C: ...
- VC++6.0中不兼容问题
记得上次用VC++6.0已经是很长一段时间之前的事情了.这次由于需要学习计算机图形学,要开始学这写一些算法之类的,我又开始了VC++之旅. 重新安装一个vc++,我用的是Visual C++ 6.0( ...
- VC++ 6.0中添加库文件和头文件
附加头文件包含 VC6.0中: VC6.0默认include包含路径:Tools>Options>Directories>Include files. 对于特定项目的头文件包含,在& ...
- VC 6.0中添加库文件和头文件 【转】
本文转载自:http://blog.sina.com.cn/s/blog_9d3971af0102wxjq.html 加头文件包含 VC6.0中: VC6.0默认include包含路径:Tools&g ...
- 介绍静态链接库和动态链接库的差别,及在VC++6.0中的建立和使用
首先介绍一下链接库:链接库分为动态链接库和静态链接库两种 LIB是静态链接库,在程序编译连接的时候是静态链接,其相应的文件格式是.lib. 即当程序採用静态链接库的时候..lib文件里的函数被链接到终 ...
- VC++6.0中碰到Cannot access the ClassView information file.ClassView information will not be avaible.的解决方法
一般情况下是由于类视图文件损坏了,这是经常会发生的现象. 解决步骤: 1.关闭工程,2.删除工程下.clw .ncb 文件及/debug目录,3.重建工程build all. 具体解释如下: dsp ...
随机推荐
- Java之路
Java程序员 高级特性 反射.泛型.注释符.自动装箱和拆箱.枚举类.可变参数.可变返回类型.增强循环.静态导入 核心编程 IO.多线程.实体类.集合类.正则表达式.XML和属性文件 图形编程 AWT ...
- Arduino中的数据类型范围
注意int不是4字节而仅仅是2字节!!! int: -32,768 ~ 32,767 (2字节) long: 4字节 http://www.arduino.cc/en/Reference/Int
- 最全的PHP开发Android应用程序
第一部分是指在Android系统的手机上直接写PHP脚本代码并立即运行: 第二部分则继续讲解如何把写好的PHP脚本代码打包成akp安装文件. 首先,在手机上安装两个apk包. 一个是SL4A(Scri ...
- Linux下信号的简单使用
1,1个main, 包含2个while, 不要被两个while中的sleep所迷惑,这里只有main()这一个主线程(进程)在运行,程序会按照自上而下顺序执行. 遇到第1个while循环中的sleep ...
- .net core学习
http://www.cnblogs.com/artech/ http://www.blogs8.cn/posts/AA0E630 http://pan.baidu.com/s/1bo4fJ47 ht ...
- [Everyday Mathematic]20150216
设 $A,B,C$ 是同阶方阵, 试证: $$\bex (A-B)C=BA^{-1}\ra C(A-B)=A^{-1}B. \eex$$
- HTTP协议的状态码
对于Web编程人员来说,熟悉了解HTTP协议的状态码是很有必要的,很多时侯可能根据HTTP协议的状态码很快就能定位到错误信息!今天整理了一下所有HTTP状态码. HTTP状态码(HTTP Status ...
- org.unsaved transient instance - save the transient instance before flushing: bug解决方案
最近开发和学习过程中,遇到很多零碎的知识点,在此简单地记录下: 1.遇如下bug: org.unsaved transient instance - save the transient instan ...
- Anychart 破解备注
由于项目里用到anychart组件,第一次破解了,后来升级再破解时忘了方法,所以在这里备注一下. 首先需要的工具: swfc (http://www.buraks.com/swifty/swfc.h ...
- Leetcode 210 Course Schedule II
here are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prere ...