http://blog.csdn.net/csdnmicrosoftcsdn/article/details/47952895
鉴于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 ");
- 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 ");
- }
- 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
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对象 |
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.为分隔器窗口的共享滚动条指定新的滚动条风格 |
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.表明一个框架窗口是否是水平分隔的 |