在图像处理等多窗口应用程序中,通常要在屏幕上同时显示若干个窗口,以显示进行图像处理前和处理后的图像信息,或者在每个窗口中分别显示图像的细节和概貌。为了实现上述功能,可以采用MDI的多文档模式进行处理,但是多文档的程序设计和维护相对单文档应用程序而言相对复杂,而且如果要在屏幕上同时显示窗口,通常要调用窗口重叠函数进行管理,窗口的位置也往往需要用鼠标人为设定,过多的人为干预也降低了程序使用的效率。因此,对于某些应用程序,如果能够用分割视图来实现屏幕绘图和显示,无疑会降低程序使用者的操作强度,显示更加直观和方便。
本文介绍了一种混合分割视图的实现方法,即在Visual C++中,同时出现基于CView类的普通视图和基于CFormView类的窗体视图,且视图之间存在着二次(或多次)再分割,即视窗里面又包含视窗,如图所示为要涉设计的界面形式。
界面内共含有一个框架和五个视窗,视窗Left、视窗Right、视窗Zoom、视窗Control和视窗" Info。视窗Left、 Right和 Zoom分别显示左右图像窗口的图像和经过高倍放大后的图像,这几个视窗的基类都是CView;视窗Control用来 进行仪器控制和图像操作,视窗Info用来显示系统的当前信息和工作进程和状态,这两个视窗都从CFormView派生出来。
为了实现上述功能,首先用AppWizard生成一单文档应用程序,并自定义生成的默认视类为CZoomView,用来显放大的图像。
接下来,通过如下步骤,创建另外四个视窗:
1、用ClassWizard为应用程序创建一个新类CFixedSplitter,基类为CMDIChildWnd,然后在该类中将所有CMDIChildWnd的地方替换为CsplitterWnd(因为ClassWizard不支持直接从CsplitterWnd类派生子类);
2、在CMainFrame类里声明分割视图的变量:
CFixedSplitter SplitterH1; file://水平分割视窗1
CFixedSplitter SplitterH2; file://水平分割视窗2
CFixedSplitter SplitterV; file://垂直分割视窗
3、用ClassWizard为应用程序添加四个新类,其中CLeftView和CrightView从Cview类派生,CControlView和CinfoView从CFormView类中派生;用资源管理器为两个CFormView类指定相应的对话框资源;注意这里一定要通过交互操作将两对话框的风格(属性)设置为WS_CHILD=On,WS_BORDER=Off,WS_VISIBLE=Off,WS_CAPTION=Off,即无标题、无边框、不可见的子窗口,如果这项工作没有作,编译时虽然能够通过,但运行时将会出现断言ASSERT错误;
4、在CMainFrame类的OnCreateClient函数中添加代码,创建分割视图
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
BOOL rtn=SplitterV.CreateStatic(this,1,2); file://首先将窗口客户区分割为一行两列;
file://将左客户区再分割为三行一列,并以上面分割的左视窗作为父窗口;
SplitterH1.CreateStatic(&SplitterV, 3, 1, WS_CHILD | WS_VISIBLE | WS_BORDER,
SplitterV.IdFromRowCol(0,0));
file://将右客户区再分割为两行一列,并以上面分割的右视窗作为父窗口;
SplitterH2.CreateStatic(&SplitterV, 2, 1, WS_CHILD | WS_VISIBLE | WS_BORDER,
SplitterV.IdFromRowCol(0,1));
file://创建各自视图,并调用RUNTIME_CLASS运行库指定各视图的管理类
SplitterH1.CreateView(0, 0, RUNTIME_CLASS(CViewL), CSize(0, 0), pContext);
SplitterH1.CreateView(1, 0, RUNTIME_CLASS(CViewR), CSize(0, 0), pContext);
SplitterH1.CreateView(2, 0, RUNTIME_CLASS(CControlView), CSize(0,0), pContext);
SplitterH2.CreateView(0, 0, RUNTIME_CLASS(CZoomView), CSize(0, 0), pContext);
SplitterH2.CreateView(1, 0, RUNTIME_CLASS(CInfoView), CSize(0, 0), pContext);
file://设置水平和垂直分割条的初始位置
SplitterV.SetColumnInfo(0,Ver_Sp_Pos,0); file://Ver_Sp_Pos为预定分割条的位置
SplitterH1.SetRowInfo(0,Hor_Sp_Pos,0); file://Hor_Sp_Pos为预定分割条的位置
SplitterH1.SetRowInfo(1,Hor_Sp_Pos,0);
SplitterH2.SetRowInfo(0,576,0);
return rtn;
file://return CFrameWnd::OnCreateClient(lpcs, pContext); file://覆盖此函数,否则视图无法显示;
}
这样编译运行后,程序的界面基本上就有了模样。但是当鼠标移动到分割条位置始,鼠标的形状将会发生变化,呈现出拖动状态的图标,当按下鼠标左键并进行拖动操作时,分割条的位置将随鼠标的移动发生变化。如果程序需要禁止分割条的移动操作,那么还需要继续以下操作:
在CfixedSplitteWnd类中重载以下函数,以禁止鼠标拖动和光标变化:
void CFixedSplitterWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
CWnd::OnLButtonDown(nFlags, point); file://最后修改成CWnd的函数
file://CSplitterWnd::OnLButtonDown(nFlags, point); file://替换默认的函数
}
BOOL CFixedSplitterWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
return CWnd::OnSetCursor(pWnd, nHitTest, message);
file://return CSplitterWnd::OnSetCursor(pWnd, nHitTest, message);
}
void CFixedSplitterWnd::OnMouseMove(UINT nFlags, CPoint point)
{
CWnd::OnMouseMove(nFlags, point);
file://CSplitterWnd::OnMouseMove(nFlags, point);
}
接下来就可以象在多文档重叠窗口一样,管理自己的各自视图,每个视图可以分别显示各自的文档内容,非常方便。程序中创建了两个小的窗口显示概貌图像,并用一个大窗口显示高倍放大的细节图像。通过在控制窗体中进行操作,协调各视图的工作进程,并将当前的运行结果用动画等形式显示在信息窗体中。
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/