}
SetScrollSizes(MM_TEXT, CSize(100, 100));
else { }
m_iWidth = pDoc->img.GetWidth(); m_iHeight = pDoc->img.GetHeight(); RECT crect; GetClientRect(&crect);
SetScrollSizes(MM_TEXT, CSize(m_iWidth, m_iHeight),
CSize(crect.right, crect.bottom), CSize(10, 10));
//GetParentFrame()->RecalcLayout(); // 对SDI ResizeParentToFit( ); m_bInit = true;
还可以在用户改变窗口大小时,调整滚动的页面和行的大小。例如:
void CImageView::OnSize(UINT nType, int cx, int cy) { }
在OnDraw函数中,可以对整个滚动范围绘图;例如:
void CImageView::OnDraw(CDC* pDC) {
CScrollView::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 CImageDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);
if (!pDoc->img.IsNull()) { }
if (m_bInit) // 因为创建视图类时会在先调用OnSize后,再调用
// OnInitialUpdate。所以,m_iWidth和m_iHeight的值, // 只能在初始化完成后才能使用。
SetScrollSizes(MM_TEXT, CSize(m_iWidth, m_iHeight),
CSize(cx, cy), CSize(10, 10));
CImageDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);
21
}
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
if(m_bInit) pDoc->img.BitBlt(pDC->m_hDC, 0, 0);
还可以调用CDC类的成员函数GetClipBox,来确定当前客户区中需要更新的矩形区域及需要绘制的文档范围,该函数的原型为:
virtual int GetClipBox( LPRECT lpRect ) const;
2.CEditView类
CEditView类是另一个常用的CView的派生类,它可以使你的应用程序成为一个简单的文本编辑器,支持文本文件的读写和各种编辑操作(包括基于剪接板的复制),参见图12-19。具体做法与CScrollView类似,只需在创建项目时,将C*View的基类从默认的CView改成CEditView即可。另外,还需要将项目的字符集属性,设置或修改为“使用多字节字符集”,不然在打开ASCII码文件时会出现乱码。
图12-19 编辑视图程序
MFC会在文档类的序列化函数中自动加上如下语句:
void CEditDoc::Serialize(CArchive& ar) {
// CEditView 包含一个处理所有序列化的编辑控件
reinterpret_cast
SerializeRaw(ar);
}
22
对已经存在的项目,可在*View.h和*View.cpp文件中,将所有的CView替换成CEditView,并将文档类序列化函数中内容替换成如上语句。以CView为基类的默认Serialize函数体为:
void CTestDoc::Serialize(CArchive& ar) { }
if (ar.IsStoring()) { } else { }
// TODO: 在此添加加载代码 // TODO: 在此添加存储代码
12.3 文档窗口
在MFC的文档-视图结构中,一般一个文档对应一个视图窗口。不过我们可以将一个视图窗口拆分成多个窗格(Pane),在不同的窗格中显示文档的不同部分或不同表示。
MDI应用程序在启动运行时,默认会自动创建一个空白的子框架窗口,可以通过在适当的位置添加语句予以屏蔽。
MDI应用程序,一般会在用户选中了“文件”菜单中的“新建”和“打开”菜单项后,自动创建新的文档子窗口或新的选项卡窗口。我们也可以编写代码,在需要时候由自己来创建文档子窗口。我们还可以设置文件过滤器,只打开具有指定扩展名的文件。另外,我们也能根据需要,改变文档窗口的位置和大小。
12.3.1 拆分窗口*
可以将一个视图窗口拆分成多个窗格(参见图12-20),每个窗格显示文档的一个视图,这样一个文档窗口就可以显示多个视图。
23
图12-20 窗口拆分成多个窗格
1.CSplitterWnd类
拆分窗口需要用到MFC的CSplitterWnd类,它是CWnd的派生类:
CObject → CCmdTarget → CWnd → CSplitterWnd
CSplitterWnd类的常用成员函数有: ? 默认构造函数:CSplitterWnd( );
? 创建含有指定行列数窗格的动态拆分窗口:
virtual BOOL Create( CWnd* pParentWnd, int nMaxRows, int nMaxCols, SIZE
sizeMin, CCreateContext* pContext, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | SPLS_DYNAMIC_SPLIT, UINT nID = AFX_IDW_PANE_FIRST );
? 创建含有指定行列数窗格的静态拆分窗口:
virtual BOOL CreateStatic( CWnd* pParentWnd, int nRows, int nCols, DWORD
dwStyle = WS_CHILD | WS_VISIBLE, UINT nID = AFX_IDW_PANE_FIRST );
? 创建一个窗格,指定初始大小:
virtual BOOL CreateView( int row, int col, CRuntimeClass* pViewClass, SIZE sizeInit,
CCreateContext* pContext );
? 返回当前窗格的行号(从0开始计数):int GetRowCount( ) const; ? 返回当前窗格的列号(从0开始计数):int GetColumnCount( ) const; ? 获取指定列的当前与最小宽度:
void GetColumnInfo( int col, int& cxCur, int& cxMin ) const; ? 获取指定行的当前与最小高度:
void GetRowInfo( int row, int& cyCur, int& cyMin ) const;
? 设置指定行的当前与最小高度:void SetRowInfo( int row, int cyIdeal, int cyMin );
24
? 设置指定列的当前与最小宽度:void SetColumnInfo( int col, int cxIdeal, int cxMin ); ? 在调整窗格大小后重新显示:virtual void RecalcLayout( );
? 获取指定(行/列)窗格的窗口对象:CWnd* GetPane( int row, int col ) const; ? 删除指定行的窗格:virtual void DeleteRow( int rowDelete ); ? 删除指定列的窗格:virtual void DeleteColumn( int colDelete );
2.动态拆分
动态拆分指拆分窗格的数量可以由用户动态改变。在动态拆分的情形下,MFC规定各个窗格所对应的必须是同一个视图类。因此,这种拆分主要用于,在同一个大文档(如大图片、大文本文件)的同一种显示方式中,对文档不同部分的多视,便于对文档进行查看、比较和编辑。
动态拆分的典型例子,是Word窗口的垂直拆分:可以在同一Word窗口的上下窗格中,同时显示文档的不同部分。例如,在上部窗格中显示文档的开始部分,而在下部窗格中显示文档的末尾部分。而Word文档结构图,则是典型的窗口左右水平拆分。
1)使用方法
创建动态拆分应用程序的最简单方法,就是在创建项目时,设置拆分窗口选项。具体做法是,在“MFC应用程序向导”的“用户界面功能”页中,选中“拆分窗口”多选框,参见图12-21。
图12-21 选中“拆分窗口”多选框
25