MFC支持兩種類型的拆分窗口:靜態的和動態的。
靜態拆分窗口的行列數在拆分窗口被創建時就設置好了,用戶不能更改。但是用戶可以縮放各行各列。一個靜態拆分窗口最多可以包含16行16列。
要找一個使用了靜態拆分窗口的應用程序,只要看一下windows管理器即可。
動態拆分窗口最多可以有兩行兩列,但它們可以相互拆分和合並。Vc就使用了動態拆分窗口使得可以同時編輯源程序文件的兩個以上不同的部分。
選擇靜態或動態拆分的一個準則是是否希望用戶能夠交互地修改拆分窗口的行列配置。另一個決定因素是計劃在拆分窗口中使用的視圖種類。
在靜態拆分窗口中很容易使用兩個以上不同種類的視圖,因爲您可以在每個窗格中指定所用的視圖類型。但是在動態拆分窗口中,MFC管理着視圖,
除非從 CsplitterWnd派生一個新類並修改拆分窗口的默認操作性能,否則拆分窗口中的所有視圖使用的都是相同的視圖類。
靜態拆分窗口是用CsplitterWnd::CreateStatic而不是CsplitterWnd::Create創建,並且由於MFC不會自動創建靜態拆分窗口中顯示的視圖,
所以您要親自在CreateStatic返回之後創建視圖。CsplitterWnd爲此提供了名爲 CreateView的函數。
你應按如下步驟創建一個CSplitterWnd對象:
1. 在父框架中嵌入一個CSplitterWnd成員變量。
2. 重載父框架的CFrameWnd::OnCreateClient成員函數。
3. 從重載的OnCreateClient函數中調用類CSplitterWnd的Create或CreateStatic成員函數,並調用CreateView來創建視圖。
使用靜態拆分窗口的一個優點是由於您自己給窗格添加視圖,所以可以控制放入視圖的種類。
關鍵函數
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_wndSplitter.CreateStatic(this, 2,1); // 切分爲2行1列
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)。
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CTest),CSize(190,100),pContext)
實現的關鍵代碼
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { // TODO: Add your specialized code here and/or call the base class if(!m_wndSplitter.CreateStatic(this,1,2)) { return FALSE; } CRect rect; GetClientRect(&rect); if(!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CTest),
CSize(rect.Width()/4,rect.Height()),pContext)|| !m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CSplitterSDIView),
CSize(rect.Width()/4*3,rect.Height()),pContext)) { return FALSE; } return TRUE; }
重載該函數之前需要做的步驟:
1. 在CMainFrame類中添加protected成員CSplitterWnd m_wndSplitter;
2. 建立對話框資源(IDD_FORMVIEW),並以CFormView類爲基類建立相應的視類;
3. 重載OnCreateClient函數(如上述代碼)。
4. 如果需要更多的劃分,則再添加其他的CSplitterWnd成員變量,但在m_wndSplitter2.CreateStatic()
函數裏的第一個參數則採用需要劃分的那個子視圖,如m_wndSplitter2.CreateStatic(&m_wndSplitter1,
1, 2, WS_CHILD|WS_VISIBLE, m_wndSplitter1.IdFromRowCol(0,0)) ),當然也需要自己創建需要的所
有視圖。
多視類之間的交互
在MFC程序中,各個視類之間進行數據交互是通過Doc類來完成的,由CDocument類來處理文檔,
而由CView類來顯示。即將數據存儲到CDocument類中,而用到數據的時候再從該類中讀取。
處理按鈕事件:
void CTest::OnShowInt() { // TODO: Add your control notification handler code here CSplitterSDIDoc* pDoc =(CSplitterSDIDoc*) GetDocument(); UpdateData(TRUE); pDoc->x=m_int; pDoc->UpdateAllViews(NULL); }
在CSplitterSDIView中顯示:
void CSplitterSDIView::OnDraw(CDC* pDC) { CSplitterSDIDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here CString str; str.Format("%d", pDoc->x); pDC->TextOut(0,0,str); }
CSplitterWnd類的其他成員信息
有關該類的其他成員函數,可以參考MSDN。
其他信息
當用戶創建好分割窗口後,有時並不希望通過拖動切分條來調節窗口的大小。這時就必須鎖定切分條。鎖定切分條的最簡單的
void CXXSplitterWnd::OnLButtonDown(UINT nFlags,CPoint point) { CWnd::OnLButtonDown(nFlags,point);}
切分條的定製
由Window自己生成的切分條總是固定的,沒有任何的變化,我們在使用一些軟件比如ACDSee的時候卻能發現它們的切分條
void CSplitterWndEx::OnDrawSplitter(CDC *pDC, ESplitType nType, const CRect &rectArg){
if(pDC==NULL)
{
RedrawWindow(rectArg,NULL,RDW_INVALIDATE|RDW_NOCHILDREN);
return;
}
ASSERT_VALID(pDC);
CRect rc=rectArg;
switch(nType)
{
case splitBorder:
//重畫分割窗口邊界,使之爲紅色
pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0));
rc.InflateRect(-CX_BORDER,-CY_BORDER);
pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0));
return;
case splitBox:
pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
rc.InflateRect(-CX_BORDER,-CY_BORDER);
pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
rc.InflateRect(-CX_BORDER,-CY_BORDER);
pDC->FillSolidRect(rc,RGB(0,0,0));
pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
return;
case splitBar:
//重畫分割條,使之爲綠色
pDC->FillSolidRect(rc,RGB(255,255,255));
rc.InflateRect(-5,-5);
pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0));
return;
default:
ASSERT(FALSE);
}
pDC->FillSolidRect(rc,RGB(0,0,255));
}
void CSplitterWndEx::OnInvertTracker(CRect &rect)
{ ASSERT_VALID(this);
ASSERT(!rect.IsRectEmpty());
ASSERT((GetStyle()&WS_CLIPCHILDREN)==0);
CRect rc=rect;
rc.InflateRect(2,2);
CDC* pDC=GetDC();
CBrush* pBrush=CDC::GetHalftoneBrush();
HBRUSH hOldBrush=NULL;
if(pBrush!=NULL) hOldBrush=(HBRUSH)SelectObject(pDC->m_hDC,pBrush->m_hObject);
pDC->PatBlt(rc.left,rc.top,rc.Width(),rc.Height(),BLACKNESS);
if(hOldBrush!=NULL)
SelectObject(pDC->m_hDC,hOldBrush);
ReleaseDC(pDC);
}