友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
深入浅出MFC第2版(PDF格式)-第94部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
图13…2 分裂窗口的不同窗口可以观察同一Document 资料的不同区域。
但是我们发现,不论是同源子窗口或分裂窗口的窗口,都是以相同的方式(也就是同一
个CMyView::OnDraw )表现Document 内容。如果我们希望表达力丰富一些,如何是好?
到现在为止我们并没有看到任何一个Scribble 版本具备了多种显像能力。
窗口的动态分裂
动态分裂窗口由CSplitterWnd 提供服务。这项技术已经在第11 章的Scribble Step4 示范
过了。它并没有多重显像的能力,因为每一个窗口所使用的View 类别完全相同。当第
704
…………………………………………………………Page 767……………………………………………………………
第 13 章 多重文件與多重顯示
一个窗口形成(也就是分裂窗口初产生的时候),它将使用Document Template 中登记
的View 类别,作为其View 类别。尔后当分裂发生,也就是当使用者拖拉滚动条之上名
为分裂棒(splitter box)的横杆,导至新窗口诞生,程序就以「动态生成」的方式产生出
新的View 窗口。
因此,View 类别一定必须支持动态生成,也就是必须使用DECLARE_DYNCREATE 和
IMPLEMENT_DYNCREATE 宏。请回顾第8章。
AppWizard 支持动态分裂窗口。当你在AppWizard 步骤四的【Advanced 】对话框的
【Windows Styles 】附页中选按【Use split window 】选项:
你的程序比起一般未选【Use split window 】选项者有如下差异(阴影部份):
705
…………………………………………………………Page 768……………………………………………………………
第篇 深入 MFC 程式設計
// in CHILDFRM。H
class CChildFrame : public CMDIChildWnd
{
。。。
protected:
CSplitterWnd m_wndSplitter;
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CChildFrame)
public:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs; CCreateContext* pContext);
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
//}}AFX_VIRTUAL
。。。
};
// in CHILDFRM。CPP
BOOL CChildFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/;
CCreateContext* pContext)
{
return m_wndSplitter。Create( this;
2; 2; // TODO: adjust the number of rows; columns
CSize( 10; 10 ); // TODO: adjust the minimum pane size
pContext );
}
◆ CSplitterWnd::Create 的详细规格请回顾第11 章。
这些其实也就是我们在第11 章为Scribble Step4 亲手加上的码。如果你一开始就打定主
意要使用动态分裂窗口,如上便是了。
窗口(Panes )之间的同步更新,其机制着落在两个虚拟函数CDocument::UpdateAllViews
和CView::OnUpdate 身上,与第11 章的情况完全相同。
动态分裂的实作,非常简单。但它实在称不上「怎么样」!除了拥有「动态」增减窗口
的长处之外,短处有二:第一,每一个窗口都使用相同的View 类别,因此显示出来的
东西千篇一律;第二,窗口之间并非完全独立。同一水平列的窗口,使用同一个垂直卷
轴;同一垂直行的窗口,使用同一个水平滚动条,如图13…2。
706
…………………………………………………………Page 769……………………………………………………………
第 13 章 多重文件與多重顯示
窗口的静态分裂
动态分裂窗口的短处正是静态分裂窗口的长处, 动态分裂窗口的长处正是静态分裂窗口
的短处。
静态分裂窗口的窗口个数一开始就固定了,窗口所使用的view 必须在分裂窗口诞生之
际就准备好。每一个窗口的活动完全独立自主,有完全属于自己的水平滚动条和垂直滚动条。
静态分裂窗口的窗口个数限制是16 列x 16 行,
动态分裂窗口的窗口个数限制是2 列x 2 行。
欲使用静态分裂窗口,最方便的办法就是先以AppWizard 产生出动态分裂码(如上一节
所述),再修改其中部份程序。
不论动态分裂或静态分裂,分裂窗口都由CSplitterWnd 提供服务。动态分裂窗口的诞生
是靠CSplitterWnd::Create,静态分裂窗口的诞生则是靠CSplitterWnd::CreateStatic。为了
静态分裂,我们应该把上一节由AppWizard 产生的函数码改变如下:
707
…………………………………………………………Page 770……………………………………………………………
第篇 深入 MFC 程式設計
BOOL CChildFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/;
CCreateContext* pContext)
{
//产生静态分裂窗口,横列为1,纵行为2。
m_wndSplitter。CreateStatic(this; 1; 2);
//产生第一个窗口(标号0;0)的view 窗口。
m_wndSplitter。CreateView(0; 0; RUNTIME_CLASS(CTextView);
CSize(100; 0); pContext);
//产生第二个窗口(标号0;1)的view 窗口。
m_wndSplitter。CreateView(0; 1; RUNTIME_CLASS(CBarView);
CSize(0; 0); pContext);
}
这会产生如下的分裂窗口:
m_wndSplitter。CreateStatic(this; 1; 2)
产生静态分裂窗口,横列为1 纵行为2 。
m_wndSplitter。CreateView(0; 0; ;CSize(100;0)。。。)
产生第一个窗口(标号0;0 )
m_wndSplitter。CreateView(0; 1; ;CSize(0;0)。。。)
产生第二个窗口(标号0;1 )
Splitter
0;0 0;1
窗口( ) 窗口( )
窗
口
初
始
高
度
100 剩余宽度
Splitter 窗口初始宽度
708
…………………………………………………………Page 771……………………………………………………………
第 13 章 多重文件與多重顯示
CreateStatic 和CreateView
静态分裂用到两个CSplitterWnd 成员函数:
CreateStat ic :
这个函数的规格如下:
BOOL CreateStatic( CWnd* pParentWnd; int nRows; in nCols;
DWORD dwStyle = WS_CHILD | WS_VISIBLE;
UINT nID = AFX_IDW_PANE_FIRST );
第一个参数代表此分裂窗口之父窗口。第二和第三参数代表横列和纵行的个数。第四个
参数是窗口风格,预设为WS_CHILD | WS_ VISIBLE,第五个同时也是最后一个参数代表
窗口(也是一个窗口)的ID 起始值。
CreateView
这个函数的规格如下:
virtual BOOL CreateView( int row; int col; CRuntimeClass* pViewClass;
SIZE sizeInit; CCreateContext* pContext );
第一和第二参数代表窗口的标号(从0 起算)。第三参数是View 类别的CRuntimeClass
指针,你可以利用RUNTIME_CLASS 宏(第3章和第8章提过)取此指针,也可以利
用OnCreateClient 的第二个参数CCreateContext* pContext 所储存的一个成员变量
m_pNewViewClas s 。你大概已经忘了这个变量吧,但我早提过它了,请看第8章的
「
CDocTemplate 管理CDocument / CView / CFrameWnd」一节。所以,对于已在
CMultiDocTemplate 中登记过的View 类别,此处可以这么写:
// 产生第一个窗口(标号0;0)的view 窗口。
m_wndSplitter。CreateView(0; 0; RUNTIME_CLASS(CMyView);
CSize(100; 0); pContext);
也可以这么写:
m_wndSplitter。CreateView(0; 0; pContext…》m_pNewViewClass;
CSize(100; 0); pContext);
709
…………………………………………………………Page 772……………………………………………………………
第篇 深入 MFC 程式設計
让我再多提醒你一些,第8章的「CDocTemplate 管理CDocument / CView / CFrameWnd 」
一节主要是说明当使用者打开一份文件,MFC 内部有关于Document / View / Frame 「三
位一体」的动态生成过程。其中View 的动态生成是在CFrameWnd::OnCreate 被唤起
后,经历一连串动作,最后才在CFrameWnd::CreateView 中完成的:
CFrameWnd::OnCreate
CFrameWnd::OnCreate
CFrameWnd::OnCreateHelper
CFrameWnd::OnCreateHelper
CFrameWnd::OnCreateClient
CFrameWnd::OnCreateClient
CFrameWnd::CreateView
CFrameWnd::CreateView
而我们现在,为了分裂窗口,正在改写其中第三个虚拟函数CFrameWnd::OnCreateClient
呢!
好了,回过头来,CreateView 的第四参数是窗口的初始大小,CSize(100; 0) 表示窗口宽
度为100 个图素。高度倒是不为0,对于横列为1 的分裂窗口而言,窗口高度永远为
窗口高度,Framework 并不理会你在CSize 中写了什么高度。至于第二个窗口的大小
CSize(0; 0) 道理雷同,Framework 并不加理会其值,因为对于纵行为2 的分裂窗口而
言,右边窗口的宽度永远是窗口总宽度减去左边窗口的宽度。
程序进行中如果需要窗口的大小,只要在OnDraw 函数(通常是这里需要)中这么写即
可:
RECT rc; this…》GetClientRect(&rc);
CreateView 的第五参数是CCreateContext 指针。我们只要把OnCreateClient 获得的第
二个参数依样画葫卢地传下去就是了。
710
…………………………………………………………Page 773……………………………………………………………
第 13 章 多重文件與多重顯示
窗口的静态三叉分裂
分裂的方向可以无限延伸。我们可以把一个静态分裂窗口的窗口再做静态分裂,下面的
程序代码展现了这种可能性:
// in header file
class CChildFrame : public CMDIChildWnd
{
。。。
protected:
CSplitterWnd m_wndSplitter1;
CSplitterWnd m_wndSplitter2;
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CChildFrame)
public:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs; CCreateContext* pContext);
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
//}}AFX_VIRTUAL
。。。
};
// in implementation file
BOOL CChildFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/;
CCreateContext* pContext)
{
// 产生静态分裂窗口,横列为 1,纵行为2。
m_wndSplitter1。CreateStatic(this; 1; 2);
// 产生分裂窗口的第一个窗口(标号 0;0)的view 窗口。
m_wndSplitter1。CreateView(0; 0; RUNTIME_CLASS(CTextView);
CSize(300; 0); pContext);
// 产生第二个分裂窗口,横列为2,纵行为1。位在第一个分裂窗口的(0;1)窗口
m_wndSplitter2。CreateStatic(&m_wndSplitter1; 2; 1;
WS_CHILD | WS_VISIBLE; m_wndSplitter1。IdFromRowCol(0; 1));
// 产生第二个分裂窗口的第一个窗口(标号0;0)的view 窗口。
m_wndSplitter2。CreateView(0; 0; RUNTIME_CLASS(CBarView);
CSize(0; 150); pContext);
// 产生第二个分裂窗口的第二个窗口(标号1;0)的view 窗口。
711
…………………………………………………………Page 774……………………………………………………………
第篇 深入 MFC 程式設計
m_wndSplitter2。CreateView(1; 0; RUNTIME_CLASS(CCurveView);
CSize(0; 0); pContext);
return TRUE;
}
这会产生如下的分裂窗口:
1 m_wndSplitter1。CreateStatic(this; 1; 2)
产生静态分裂窗口,横列为1 纵行为2 。
m_wndSplitter1。CreateView(0; 0; ;CSize(300;0)。。。)
2 产生第一个窗口(标号0;0)
m_wndSplitter2。CreateStatic(&m_wndSplitter1; 2; 1; 3
m_wndSplitter1。IdFromRowCol(0; 1)。。。)
产生静态分裂窗口,横列为2 纵行为1。位在第一个分裂窗口的(0;1)窗口
m_wndSplitter2。CreateView(0; 0; ;CSize(0;150)。。。)
4
产生第二个分裂窗口的第一个窗口(标号0;0)
m_wndSplitter2。CreateView(1; 0; ;CSize(0;0)。。。)
5
产生第二个分裂窗口的第二个窗口(标号1;0)
窗口 (0;1)
Splitter 窗口 (0;0) 窗口 (0;0)
窗口
150
初 始 高度
剩余高度
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!