1. 程式人生 > >CSplitterWnd視窗分割之——動態靜態巢狀分割(二)

CSplitterWnd視窗分割之——動態靜態巢狀分割(二)

       鑑於CSplitterWnd資料很少(MSDN上也說的很簡單,Sample我也就不想吐槽了),同時網上部落格又幾乎是千篇一律的轉載。現將個人的一點經驗拿出來和大家分享,希望對他人有所幫助。不足之處還望批評指正。

       最終效果如下:

      分割窗體就是把一個窗體分割成多個面板,面板就是放各種控制元件或檢視的容器。分割窗體有兩種形式,靜態和動態。兩種形式的區別在於動態的可以收攏和展開,靜態的則不能。動態分割只能建立2*2的分割視窗,而靜態分割可以建立16*16的分割視窗。

       好了,進入正題。在VS或VC++6.0中建立一個多文件或者單文件,按照嚮導一直下一步即可。本文建立的是多文件,單文件相對簡單一些。

       建立好之後,在ChildFrm.h中新增兩個視窗分割變數:

// Attributes
protected:
	CSplitterWnd m_wndSplitter1;
	CSplitterWnd m_wndSplitter;

然後選擇工程的類檢視,右鍵ChildFrm屬性,新增Overrides中的OnCreateClient方法。如果是單文件的話在MainFrm中新增!

修改OnCreateClient方法如下:

BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
{
	////// Create 2*2 nested dynamic splitter
	//// 	// TODO: Add your specialized code here and/or call the base class
	//// 	return m_wndSplitter.Create(this,
	//// 		2, 2,			// TODO: adjust the number of rows, columns
	//// 		CSize(10, 10),	// TODO: adjust the minimum pane size
	//// 		pContext);
	//// 	//return CMDIChildWnd::OnCreateClient(lpcs, pContext);

	//// Create a  static splitter with 1 rows, 3 columns
	//m_wndSplitter.CreateStatic(this, 1, 3);	// create a splitter with 1 rows, 3 columns
	//m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CViewLeft), CSize(0, 0), pContext);	// create view with 0 rows, 0 columns
	//m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CViewMiddle), CSize(0, 0), pContext);	// create view with 0 rows, 1 columns
	//m_wndSplitter.CreateView(0, 2, RUNTIME_CLASS(CViewRight), CSize(0, 0), pContext);	// create view with 0 rows, 2 columns

	//m_wndSplitter.SetColumnInfo(0, 400, 10);	// set the width of column, 0 column, ideal width is 200dip,min width is 10dip
	//m_wndSplitter.SetColumnInfo(1, 400, 10);	// set the width of column, 0 column, ideal width is 200dip,min width is 10dip
	//m_wndSplitter.SetColumnInfo(2, 400, 10);	// set the width of column, 0 column, ideal width is 200dip,min width is 10dip
	//// m_wndSplitter.SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

	//Create a static splitter with 2 rows,1 columns
	if (!m_wndSplitter.CreateStatic(this, 2, 1, WS_CHILD|WS_VISIBLE))
	{
		TRACE("Failed to Create StaticSplitter\n");
		return NULL;
	}
	//set view
	pContext->m_pNewViewClass = RUNTIME_CLASS(CViewRight);
	
	CRect rect;     
	this->GetClientRect(&rect);
	SIZE size;
	size.cx = rect.Width();
	size.cy = rect.Height()/3;

	m_wndSplitter.CreateView(0, 0, pContext->m_pNewViewClass, size, pContext);
	//m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CViewLeft), CSize(0, 0), pContext);	// create view with 0 rows, 0 columns
	//m_wndSplitter.SetRowInfo(0, 200, 10);	// set the width of column, 0 column, ideal width is 250dip,min width is 10dip


	pContext->m_pNewViewClass = RUNTIME_CLASS(CViewMiddle);
	if (!m_wndSplitter1.Create(
		&m_wndSplitter,     // our parent window is the first splitter
		2, 2,          // TODO: adjust the number of rows, columns
		CSize(10, 10), // TODO: adjust the minimum pane size
		pContext,
		WS_CHILD|WS_VISIBLE|SPLS_DYNAMIC_SPLIT|WS_HSCROLL|WS_VSCROLL,
		m_wndSplitter.IdFromRowCol(1, 0)))
	{
		TRACE("Failed to create the nested dynamic splitter\n");
	}

	return TRUE;
}

RUNTIME_CLASS是MFC中的一個巨集,用來動態建立一個類。
這裡是我做了三種分割方式的測試,第一種是直接建立了一個2*2的動態分割視窗,沒有修改檢視;第二種是建立的一個一行三列的靜態分割視窗,並且分別為之建立了三個檢視,然後設定的了每一列的寬度;最後一種是靜態分割和動態分割巢狀使用,先使用靜態分割,將整個視窗分割成為兩行一列,分割完成後為第一行建立檢視,設定檢視高度為整個視窗的1/3,然後更改檢視,使得隨後動態分割的視窗繫結不同的檢視,再對第二行使用動態分割,將第二行分割成2*2的動態分割視窗。

       CViewLeft、CViewRight、CViewMiddle這三個類均繼承自CView,只需重寫下每個類的OnDraw方法即可

void CViewLeft::OnDraw(CDC* pDC)
{
	CDocument* pDoc = GetDocument();
	// TODO: add draw code here
	CPaintDC* dc = (CPaintDC*)pDC;
	CRect rect,fillrect;
	CBrush brush;
	brush.CreateSolidBrush(RGB(255, 0, 0));
	this->GetClientRect(&rect);
	dc->FillRect(&rect,&brush);
	brush.DeleteObject();
}

void CViewMiddle::OnDraw(CDC* pDC)
{
	CDocument* pDoc = GetDocument();
	// TODO: add draw code here
	CPaintDC* dc = (CPaintDC*)pDC;
	CRect rect,fillrect;
	CBrush brush;
	brush.CreateSolidBrush(RGB(0, 255, 0));
	this->GetClientRect(&rect);
	dc->FillRect(&rect,&brush);
	brush.DeleteObject();
}
void CViewRight::OnDraw(CDC* pDC)
{
 CDocument* pDoc = GetDocument();
 // TODO: add draw code here
 CPaintDC* dc = (CPaintDC*)pDC;
 CRect rect,fillrect;
 CBrush brush;
 brush.CreateSolidBrush(RGB(0, 0, 255));
 this->GetClientRect(&rect);
 dc->FillRect(&rect,&brush);
 brush.DeleteObject();
}

       一個CSplitterWnd物件通常被嵌入CFrameWnd或CMDIChildWnd父物件。一般使用Create或者CreateStatic分割視窗完畢,可使用SetColumnInfo和SetRowInfo來調整這些最小值,為使用其設定過的行或列則會自動分配大小。

定製屬於自己的SplitterWnd:拖動滾動條時只顯示一行或者一列

/*****************************************************************

Filename:			Splitter.h
Contents:			Implemetation of CSplitter class

Authors:	
Created date: 	  	
Last Modified date:	
Revision History: 

Used by:			
Uses:				
Build Notes:		

See Also:			

Copyright: 		(c) 2015 by All rights reserved.                           

*****************************************************************/

#pragma once

// CSplitter

class CSplitter : public CSplitterWnd
{
	DECLARE_DYNCREATE(CSplitter)

	// Attributes
public:
	// this var saves the size of the pane before floating
	int m_iSize;
	// this var saves the pane orientation before floating
	BOOL m_bHorizontal;

	SIZE m_szMinimumSize;
public:
	CSplitter();
	// added funciton for customize the splitter
public:

	/****************************************
	Function name:	void CSplitter::SetMinimumSize(const int cx = -1, const int cy = -1)
	Purpose:		Replaces a view with another in a given pane.
	Only for static splitters.
	Arguments:		row, col: pane coords
	pViewClass: a runtime class of the view
	size: min size
	Return value:	TRUE if successful, FALSE otherwise.
	**************************************/
	void SetMinimumSize(const int cx = -1, const int cy = -1);

	// Operations
public:
	/****************************************
	Function name:	void CSplitter::ReplaceView()
	Purpose:		Replaces a view with another in a given pane.
	Only for static splitters.
	Arguments:		row, col: pane coords
	pViewClass: a runtime class of the view
	size: min size
	Return value:	TRUE if successful, FALSE otherwise.
	**************************************/
	BOOL ReplaceView(int row, int col, CRuntimeClass* pViewClass, SIZE size);

	/****************************************
	Function name:	BOOL CSplitter::EmbedView()
	Purpose:		Resurrects the former column or row
	after the floating dlg is closed
	Arguments:		none
	Return value:	none
	**************************************/
	void EmbedView();

	// overridables
public:

	/****************************************
	Function name:	BOOL CSplitter::SplitRow()
	Purpose:		Overrides the default function.
	Arguments:		cyBefore - pos of the split
	Return value:	TRUE if successful, FALSE otherwise.
	**************************************/
	virtual BOOL SplitRow(int cyBefore);

	/****************************************
	Function name:	BOOL CSplitter::SplitColumn()
	Purpose:		Overrides the default function.
	Arguments:		cxBefore - pos of the split
	Return value:	TRUE if successful, FALSE otherwise.
	**************************************/
	virtual BOOL SplitColumn(int cxBefore);

	/****************************************
	Function name:	BOOL CSplitter::DeleteRow()
	Purpose:		Overrides the default function.
	Arguments:		rowDelete - row to delete
	Return value:	none
	**************************************/
	virtual void DeleteRow(int rowDelete);

	/****************************************
	Function name:	BOOL CSplitter::DeleteColumn()
	Purpose:		Overrides the default function.
	Arguments:		colDelete - row to delete
	Return value:	none
	**************************************/
	virtual void DeleteColumn(int colDelete);

	/****************************************
	Function name:	BOOL CSplitter::GetActivePane()
	Purpose:		Overrides the default function.
	Arguments:		pRow and pCol - coords of the active pane
	Return value:	the active pane

	Comments:		This function may return active pane
	that is not in this splitter at all,
	as opposed to the base class' implementation,
	which always check for it. In this case, the
	pRow and pCol will be -1
	**************************************/
	virtual CWnd* GetActivePane(int* pRow = NULL, int* pCol = NULL);

	// Implementation
public:
	virtual ~CSplitter();

	// Generated message map functions
	//{{AFX_MSG(CSplitter)
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};


/////////////////////////////////////////////////////////////////////////////

// Splitter.cpp : implementation file
//

#include "stdafx.h"
#include "sample.h"
#include "Splitter.h"


/*****************************************************************

Filename:			Splitter.cpp
Contents:			Implemetation of CSplitter class

Authors:		
Created date: 	  	
Last Modified date:	
Revision History:

Used by:			
Uses:				
Build Notes:

See Also:			

Copyright: 		(c) 2015 by All rights reserved.                           

*****************************************************************/

// Embedded Version Control String:  
static char *versionstring =	"@(#) Splitter.cpp 8/25/15";

#include "stdafx.h"
#include "splitter.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSplitter

IMPLEMENT_DYNCREATE(CSplitter, CSplitterWnd)

CSplitter::CSplitter()
{ 
	m_iSize = 0;
	// by default, we split vertically
	m_bHorizontal = FALSE;
	m_szMinimumSize.cx = -1;// not set
	m_szMinimumSize.cy = -1;// not set
}

CSplitter::~CSplitter()
{                 
}


/****************************************
Function name:	void CSplitter::ReplaceView()
Purpose:		Replaces a view with another in a given pane.
Only for static splitters.
Arguments:		row, col: pane coords
pViewClass: a runtime class of the view
size: min size
Return value:	TRUE if successful, FALSE otherwise.
**************************************/
BOOL CSplitter::ReplaceView(int row, int col, CRuntimeClass* pViewClass, SIZE size)
{
	CCreateContext context;
	BOOL bSetActive;

	if ((GetPane(row,col)->IsKindOf(pViewClass))==TRUE)
		return FALSE;


	// Get pointer to CDocument object so that it can be used in the creation 
	// process of the new view
	CDocument * pDoc= ((CView *)GetPane(row,col))->GetDocument();
	CView * pActiveView=GetParentFrame()->GetActiveView();
	if (pActiveView==NULL || pActiveView==GetPane(row,col))
		bSetActive=TRUE;
	else
		bSetActive=FALSE;

	// set flag so that document will not be deleted when view is destroyed
	pDoc->m_bAutoDelete=FALSE;    
	// Delete existing view 
	((CView *) GetPane(row,col))->DestroyWindow();
	// set flag back to default 
	pDoc->m_bAutoDelete=TRUE;

	// Create new view                      

	context.m_pNewViewClass=pViewClass;
	context.m_pCurrentDoc=pDoc;
	context.m_pNewDocTemplate=NULL;
	context.m_pLastView=NULL;
	context.m_pCurrentFrame=NULL;

	CreateView(row,col,pViewClass,size, &context);

	CView* pNewView = (CView*)GetPane(row, col);

	if (bSetActive==TRUE)
		GetParentFrame()->SetActiveView(pNewView);

	RecalcLayout(); 
	GetPane(row,col)->SendMessage(WM_PAINT);

	return TRUE;
}

/****************************************
Function name:	BOOL CSplitter::SplitRow()
Purpose:		Overrides the default function.
Arguments:		cyBefore - pos of the split
Return value:	TRUE if successful, FALSE otherwise.
**************************************/
BOOL CSplitter::SplitRow(int cyBefore)
{
	// first, leave only one column
	while (m_nCols > 1)
		DeleteColumn(m_nCols - 1);

	BOOL bRet = CSplitterWnd::SplitRow(cyBefore);

	// Show horizontal scroll bar of the upper view window,
	//	hide all the others.
	CWnd	*pUpperWnd = GetPane(0, 0);
	pUpperWnd->ShowScrollBar(SB_VERT, 0);
	pUpperWnd->ShowScrollBar(SB_HORZ, 1);

	if (m_nRows > 1) {
		CWnd	*pLowerWnd = GetPane(1, 0);
		pLowerWnd->ShowScrollBar(SB_VERT, 0);
		pLowerWnd->ShowScrollBar(SB_HORZ, 0);
	}

	return bRet;
}

/****************************************
Function name:	BOOL CSplitter::SplitColumn()
Purpose:		Overrides the default function.
Arguments:		cxBefore - pos of the split
Return value:	TRUE if successful, FALSE otherwise.
**************************************/
BOOL CSplitter::SplitColumn(int cxBefore)
{
	// first, leave only one row
	while (m_nRows > 1)
		DeleteRow(m_nRows - 1);

	BOOL bRet = CSplitterWnd::SplitColumn(cxBefore);

	// Show vertical scroll bar of the left view window,
	//	hide all the others.
	CWnd	*pLeftWnd = GetPane(0, 0);
	pLeftWnd->ShowScrollBar(SB_VERT, 1);
	pLeftWnd->ShowScrollBar(SB_HORZ, 0);

	if (m_nCols > 1) {
		CWnd	*pRightWnd = GetPane(0, 1);
		pRightWnd->ShowScrollBar(SB_VERT, 0);
		pRightWnd->ShowScrollBar(SB_HORZ, 0);
	}
	return bRet;
}

/****************************************
Function name:	BOOL CSplitter::DeleteRow()
Purpose:		Overrides the default function.
Arguments:		rowDelete - row to delete
Return value:	none
**************************************/
void CSplitter::DeleteRow(int rowDelete)
{
	// save the state of the pane before deleting
	// note: since we always insert it later as a pane #0,
	// save the size of the pane #0. Later we can save the pane id too.
	m_bHorizontal = TRUE;
	int iDummy;
	GetRowInfo(0, m_iSize, iDummy);
	CSplitterWnd::DeleteRow(rowDelete);
}

/****************************************
Function name:	BOOL CSplitter::DeleteColumn()
Purpose:		Overrides the default function.
Arguments:		colDelete - row to delete
Return value:	none
**************************************/
void CSplitter::DeleteColumn(int colDelete)
{
	// save the state of the pane before deleting
	// note: since we always insert it later as a pane #0,
	// save the size of the pane #0. Later we can save the pane id too.
	m_bHorizontal = FALSE;
	int iDummy;
	GetColumnInfo(0, m_iSize, iDummy);

	CSplitterWnd::DeleteColumn(colDelete);
}

/****************************************
Function name:	BOOL CSplitter::EmbedView()
Purpose:		Resurrects the former column or row
after the floating dlg is closed
Arguments:		none
Return value:	none
**************************************/
void CSplitter::EmbedView()
{
	if (m_bHorizontal && (m_nRows < m_nMaxRows))
		SplitRow(m_iSize + m_cyBorder);
	else if (m_nCols < m_nMaxCols)
		SplitColumn(m_iSize + m_cxBorder);
}

BEGIN_MESSAGE_MAP(CSplitter, CSplitterWnd)
	//{{AFX_MSG_MAP(CSplitter)
	ON_WM_CREATE()
	ON_WM_MOUSEMOVE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


int CSplitter::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CSplitterWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	RECT ClientRect;
	if (::GetClientRect(lpCreateStruct->hwndParent, &ClientRect))
	{
		m_iSize = (ClientRect.left - ClientRect.right) / 2;
	}

	return 0;
}

/****************************************
Function name:	BOOL CSplitter::GetActivePane()
Purpose:		Overrides the default function.
Arguments:		pRow and pCol - coords of the active pane
Return value:	the active pane

Comments:		This function may return active pane
that is not in this splitter at all,
as opposed to the base class' implementation,
which always check for it. In this case, the
pRow and pCol will be -1
**************************************/
CWnd* CSplitter::GetActivePane(int* pRow, int* pCol)
{
	ASSERT_VALID(this);

	// attempt to use active view of frame window
	CWnd* pView = NULL;
	CFrameWnd* pFrameWnd = GetParentFrame();
	ASSERT_VALID(pFrameWnd);
	pView = pFrameWnd->GetActiveView();

	// failing that, use the current focus
	if (pView == NULL)
		pView = GetFocus();

	// check if the view is in this splitter (it may not),
	// but don't return NULL if it is not, like the base class does.
	// instead, just 
	if (pView != NULL && !IsChildPane(pView, pRow, pCol))
	{
		if (pRow)
			*pRow = -1;
		if (pCol)
			*pCol = -1;
	}

	return pView;
}

void CSplitter::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if(point.y < m_szMinimumSize.cy)
	{
		point.y = m_szMinimumSize.cy;
	}
	if(point.x < m_szMinimumSize.cx)
	{
		point.x = m_szMinimumSize.cx;
	}

	CSplitterWnd::OnMouseMove(nFlags, point);
}

/****************************************
Function name:	void CSplitter::SetMinimumSize(const int cx = -1, const int cy = -1)
Purpose:		Replaces a view with another in a given pane.
Only for static splitters.
Arguments:		row, col: pane coords
pViewClass: a runtime class of the view
size: min size
Return value:	TRUE if successful, FALSE otherwise.
**************************************/
void CSplitter::SetMinimumSize(const int cx, const int cy)
{ 
	m_szMinimumSize.cx = cx;
	m_szMinimumSize.cy = cy;
}

另外還給我們的View類(我們以CViewLeft為例,其他同理)新增右鍵選單,新增步驟為:

1.點選資源檢視的Menu右鍵Insert Menu,自動生成IDR_MENU1的選單(可右鍵屬性修改IDR),點選選單雙擊Type Here新增第一個選單View,然後同樣的方法在其下面新增子選單Horizonal,Vertical,Float,Swap等等,單擊選單即可在VS中看到相應選單的屬性,可以做相應修改;

2.新增選單完畢,需要顯示選單,在檢視類中新增右鍵響應函式OnRButtonDown,如下:

// CViewLeft message handlers

void CViewLeft::OnRButtonDown(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default

	CPoint ptScreen = point;//Current Mouse position int view
	ClientToScreen(&ptScreen);//to Screen
	CMenu Menu;//define menu
	if (Menu.LoadMenu(IDR_VIEW_MENU))
	{
		CMenu *pSubMenu = Menu.GetSubMenu(0);
		pSubMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, ptScreen.x, ptScreen.y, this);//shown menu at point
	}
	

	CView::OnRButtonDown(nFlags, point);
}

3.完成2之後右鍵就可以看到我們新增的右鍵選單了,最後一步就是響應選單了,資源檢視中單擊相應選單,右鍵Add Event Handler,如下所示:

然後完成相應的處理函式即可:

void CViewLeft::OnViewHorz()
{
	// TODO: Add your command handler code here
	MessageBox(L"Horz command", L"Horz", 0);
}

void CViewLeft::OnViewVert()
{
	// TODO: Add your command handler code here
	MessageBox(L"Vert command", L"Vert", 0);
}

void CViewLeft::OnViewFloat()
{
	// TODO: Add your command handler code here
	MessageBox(L"Float command", L"Float", 0);
}

void CViewLeft::OnViewSwap()
{
	// TODO: Add your command handler code here
	MessageBox(L"Swap command!", L"Swap", 0);
}

新增Splitter.h到ChildFrm.h,修改CSplitterWnd為CSplitter,執行即可看到效果如下




Base Class Members

Construction

Call to create a dynamic splitter window and attach it to the CSplitterWnd object.建立一個動態的分隔器視窗並將它與一個CSplitterWnd物件連線

Call to create a static splitter window and attach it to the CSplitterWnd object.建立一個靜態的分隔器視窗並將它與一個CSplitterWnd物件連線

Call to create a pane in a splitter window.在一個分隔器視窗中建立一個窗格

Call to construct a CSplitterWnd object.構造一個CSplitterWnd物件

Operations

Returns the current pane column count.返回當前窗格列的計數值

Returns information on the specified column.返回指定列的資訊

Returns the pane at the specified row and column.返回位於指定行和列處的窗格

Returns the current pane row count.返回當前窗格行的計數值

Returns information on the specified row.返回指定行的資訊

Returns the shared scroll-bar style.返回共享滾動條的風格

Returns the child window ID of the pane at the specified row and column.返回位於指定行和列處的窗格的子視窗ID

Determines if splitter bar is currently being moved.判定分隔條是否正在移動

Call to determine whether the window is currently a child pane of this splitter window.確定視窗是否是此分隔器視窗的當前子窗格

Call to redisplay the splitter window after adjusting row or column size.在調整行或列尺寸後呼叫此函式來重新顯示該分隔器視窗

Call to set the specified column information.設定指定列的資訊

Call to set the specified row information.設定指定行的資訊

Specifies the new scroll-bar style for the splitter window's shared scroll-bar support.為分隔器視窗的共享滾動條指定新的滾動條風格

Overridables

Performs the Next Pane or Previous Pane command.執行Next Pane或Previous Pane命令

Checks to see if the Next Pane or Previous Pane command is currently possible.檢查Next Pane或Previous Pane命令當前是否有效

Creates a shared scroll bar control.建立一個共享的滾動條控制元件

Deletes a column from the splitter window.從分隔器視窗中刪除一列

Deletes a row from the splitter window.從分隔器視窗中刪除一行

Deletes a view from the splitter window.從分隔器視窗中刪除一個檢視

Performs the keyboard split command, usually "Window Split."執行鍵盤分隔命令,通常是“Window Split”

Performs synchronized scrolling of split windows.執行分隔視窗的同步滾動

Scrolls split windows by a given number of pixels.將分隔視窗滾動給定的畫素數

Determines the active pane from the focus or active view in the frame.根據焦點或框架中的活動檢視來判定活動窗格

Renders an image of a split window.繪製一個分隔器視窗的影象

Renders the image of a split window to be the same size and shape as the frame window.繪製一個分隔器視窗的影象,使它具有與框架視窗相同的大小和形狀

Sets a pane to be the active one in the frame.在框架中設定一個活動窗格

Indicates where a frame window splits vertically.表明一個框架視窗是否是垂直分隔的

Indicates where a frame window splits horizontally.表明一個框架視窗是否是水平分隔的

需要定製屬於自己的分割視窗可以根據情況重寫Overridables相應方法。 下一篇將繼續介紹靜態動態巢狀分割以及動態分割後的視窗如何繫結不同的檢視,我們目前看到的是動態分割之後的視窗共用一個檢視,如何讓(0, 0),(0, 1),(1, 0), (1, 1)分別顯示不同的檢視呢?預知後事如何且聽下回分解。。。