💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 4.5 容器窗口 容器窗口是用来装载别的可见元素的窗口,所谓可见元素指的是子窗口或者是画在这个窗口上的图案。 wxPanel wxPanel是一个在某些方面有点象dialog窗口的窗口。这个窗口通常被用来摆放那些除了对话框或者frame窗口以外的其它控件窗口。它也常被用来作为wxNoteBook控件的页面。它通常使用系统默认的颜色。 和对话框一样,可以使用它的InitDialog方法来产生一个wxInitDialogEvent事件。如果设置了wxTAB_TRAVERSAL类型,那么它通常可以通过使用类似TAB键的导航键遍历所有它上面的子控件。 除了默认的构造函数以外,wxPanel还拥有下面的构造函数: ``` wxPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL|wxNO_BORDER, const wxString& name = wxT("panel")); ``` 用法如下: ``` wxPanel* panel = new wxPanel(frame, wxID_ANY, wxDefaultPosition, (500, 300)); ``` wxPanel的窗口类型 wxPanel没有额外的窗口类型。 wxPanel的成员函数 wxPanel也没有额外的成员函数。 wxNotebook 这个类提供了一个有多个页面的窗口,页面之间可以通过边上的TAB按钮来切换。每个页面通常是一个普通的wxPanel窗口或者其派生类,当然你完全可以使用别的窗口。 NoteBook的TAB按钮可以包含一个图片,也可以包含一个文本标签。图片是由wxImageList(参考第10章)提供的,是通过在列表中的位置和页面对应的。 使用notebook的方法是,创建一个wxNotebook对象,然后调用其AddPage方法或者InserPage方法,传递一个用来作为页面的窗口指针。不要手动释放那些已经被wxNoteBook作为页面的窗口,你应该使用DeletePage来删除某个页面或者干脆等到notebook释放它自己的时候。notebook会一并释放那些页面. 下面举例说明怎样创建一个有三个页面,包含文本和图片的TAB标签的notebook: ``` #include "wx/notebook.h" #include "copy.xpm" #include "cut.xpm" #include "paste.xpm" //创建notebook wxNotebook* notebook = new wxNotebook(parent, wxID_ANY, wxDefaultPosition, wxSize(300, 200)); // 创建图片列表 wxImageList* imageList = new wxImageList(16, 16, true, 3); imageList->Add(wxIcon(copy_xpm)); imageList->Add(wxIcon(paste_xpm)); imageList->Add(wxIcon(cut_xpm)); // 创建页面 wxPanel1* window1 = new wxPanel(notebook, wxID_ANY); wxPanel2* window2 = new wxPanel(notebook, wxID_ANY); wxPanel3* window3 = new wxPanel(notebook, wxID_ANY); notebook->AddPage(window1, wxT("Tab one"), true, 0); notebook->AddPage(window2, wxT("Tab two"), false, 1); notebook->AddPage(window3, wxT("Tab three"), false 2); ``` 下图演示了上述代码在windows平台上的结果: ![](img/mht1CCA%281%29.tmp) 在大多数的平台上,当TAB页面数量太多不能被完全显示的时候,都会自动出现导航按钮。但是在Mac OS上,这个导航按钮是不会出现的,因此在这个系统上,可以使用的页面数目将受到窗口大小和TAB标签大小的限制。 如果你在每个页面上都使用布局控件,并且在创建notebook的时候使用默认的大小wxDefaultSize,那么wxNotebook将会自动调整大小以适合它的页面。 Notebook窗口主题管理 在Windows Xp系统中,默认的窗口主题会给notebook的页面添加过渡色。虽然这是预期的本地行为,但是它可能会降低性能。出于审美方面的原因,你可能想直接使用单一的色彩,尤其是当notebook不是位于一个对话框以内的时候。如果你想阻止这种默认的行为,可以采用以下三种办法:第一:你可以给你的 notebook指定wxNB_NOPAGETHEM类型来禁止某个特定的notebook的这种效果,或者你可以使用 wxSystemOptions::SetOption来在应用程序范围内禁止它,或者你可以使用SetBackgroundColour函数来给某个单独的页面禁止它。要在应用程序范围内禁止它,你可以使用下面的代码: wxSystemOptions::SetOption(wxT("msw.notebook.themed-background"), 0); 将它的值设置成1可以再次允许这种效果。要让某个单独的页面禁用这种效果可以使用下面的方法: ``` wxColour col = notebook->GetThemeBackgroundColour(); if (col.Ok()) { page->SetBackgroundColour(col); } ``` 在windows系统以外的平台,或者如果一个应用程序没有使用主题风格,GetThemeBackgroundColour都将返回一个未初始化的颜色,因此上面的代码在各个平台都是可以使用的。另外就是上述的这部分代码的语法和行为是有可能在将来的wxWidgets版本中发生变化,请参考你本地wxWidgets发行版中的wxNotebook类的文档来获取最新的信息。 wxNotebook的窗口类型 wxNotebook可以拥有下面的额外窗口类型: | wxNB_TOP | 标签放在顶部. | |:--- |:--- | | wxNB_LEFT | 标签放在左面. 不是所有的WindowsXp的主题都支持这个选项. | | wxNB_RIGHT | 标签在右面. 不是所有的WindowsXp的主题都支持这个选项. | | wxNB_BOTTOM | 标签在底部. 不是所有的WindowsXp的主题都支持这个选项. | | wxNB_FIXEDWIDTH | 所有标签宽度相同.仅适用于windows. | | wxNB_MULTILINE | 可以有多行的标签. 仅适用于windows | | wxNB_NOPAGETHEME | 在windos上禁用主题风格.以提高性能和提供另外一种审美选择. | wxNotebook的事件 wxNotebook可以产生wxNotebookEvent事件,这个事件可以被它和它的继承者处理. | EVT_NOTEBOOK_PAGE_CHANGED(id,func) | 当前页面已经改变. | |:--- |:--- | | EVT_NOTEBOOK_PAGE_CHANGING(id,func) | 当前页面即将改变。你可以使用Veto函数阻止这种改变. | wxNotebook的成员函数 AddPage增加一个页面,InsertPage在某个固定位置插入一个页面.你可以使用文本标签或者图片标签或者两者都有,用法如下: ``` //增加一个使用了文本和图片两种标签都有的页面,并且当前处于未选中状态。 // (其中图片使用的是图片列表中的索引为2的那个). notebook->AddPage(page, wxT("My tab"), false, 2); ``` DeletePage函数移除并且释放某个特定的页面,而RemovePage函数则仅仅是移除这个页面。DeleteAllPages函数用来删除所有的页面。当wxNoteBook被释放时,它也会自动删除所有的页面。 AdvanceSelection函数循环选择页面。 SetSelection函数以基于0的索引选择特定的页面. GetSelection取得当前选中页面的索引或者返回wxNOT_FOUND. SetImageList函数用来给Notebook设置一个图标列表,这个函数仅是设置而不绑定图片列表,这意味着在notebook 控件被删除的时候,这个图片列表控件并不会被删除,如果你希望使用绑定,则可以使用AssignImageList函数. GetImageList函数返回notebook相关的图片列表对象.图片列表对象用来提供每个页面标签中使用的图片,详情请参考第10章。 GetPage函数用来返回和某个索引对应的页面窗口指针, GetPageCount函数则返回页面总数. SetPageText和GetPageText用来操作页面标签上的文本. SetPageImage和GetPageImage用来操作页面标签上的图片在图片列表中的索引, wxNotebook的替代选择 wxNotebook是wxBookCtrlBase的派生类, 这个基类是用来提供用于管理一组页面的所有数据和方法的抽象类。和wxNotebook有着相似API的类还有两个,一个是wxListbook,一个是 wxChoicebook,你也可以实现你自己的类,比如你可以实现一个wxTreebook. wxListbook使用一个wxListCtrl变量来控制页面;ListCtrl控件是一种在内部显示一组带有标签的图片的控件. 在wxListbook中,相关的ListCtrl控件可以显示在上下左右四个方向,默认是在左边。这是wxNotebook的一个很有吸引力的替代者。因为即使在Mac Os X平台上,ListCtrl可以管理的项目数量也几乎没有限制,因此wxListbook可以管理的页面数也不受窗口大小和标签长度的限制。 wxChoicebook则使用一个选择控件(一个下拉列表)来管理页面。比较适用于窗口空间比较小的场合。这个控件不会在页面标签处显示图片,而且默认情况下,选择控件显示在整个控件的上方。 上述这两个控件的头文件分别为wx/listbook.h和wx/choicebk.h.它们的事件处理函数的参数类型分别为 wxListbookEvent和wxChoicebookEvent类型,事件影射宏则分别为EVT_XXX_PAGE_CHANGED(id, func)和EVT_XXX_PAGE_CHANGING(id,func),其中XXX代表LISTBOOK或者CHOICEBOOK. 你可以使用类似wxNotebook定义的那些窗口类型,也可以类似用wxCHB_TOP或者wxLB_TOP取代wxNB_TOP这样的窗口类型,它们的值都是一样的, wxScrolledWindow 尽管所有的窗口都可以拥有滚动条,但是为了让滚动条工作,还需要一些额外的代码。这个类则为让不同类型的窗口类中的滚动条正确工作提供了足够的灵活性。 wxScrolledWindow主要实现了那些让窗口可以以一定的单位连续的滚动(而不是不定大小的跳跃),也可以定义在使用翻页键进行翻页的时候的大小。这种实现通常仅适用于类似画图程序中的那种翻页功能,对于一些复杂功能的文本编辑程序则不一定适合。因为富文本编辑器中每一行的高度和宽度都有可能不同。wxGrid网格控件就是这样的一个例子(在网格控件中,每一行和每一列的宽度都有可能不同),在这种情况下,你应该自己直接从wxWindow类实现自己的派生类,从而实现自己的窗口滚动机制。 要适用滚动窗口,你需要提供每次逻辑移动的单位(也就是当处理上滚一行和下滚一行时窗口应该移动的大小)以及整个窗口的虚拟逻辑大小。然后wxScrollWindow类就会自己关注是否显示滚动条,以及滚动条上的滑钮应该用多大显示等等这些细节问题. 下面演示了怎样创建一个滚动窗口: ``` #include "wx/scrolwin.h" wxScrolledWindow* scrolledWindow = new wxScrolledWindow( this, wxID_ANY, wxPoint(0, 0), wxSize(400, 400), wxVSCROLL|wxHSCROLL); // 设置窗口的虚拟逻辑大小: 1000x1000 // 每次滚动10个象素 int pixelsPerUnixX = 10; int pixelsPerUnixY = 10; int noUnitsX = 1000; int noUnitsY = 1000; scrolledWindow->SetScrollbars(pixelsPerUnitX, pixelsPerUnitY, noUnitsX, noUnitsY); ``` 第二种设置虚拟大小的方法是使用SetVirtualSize函数,它的参数是以象素为单位的虚拟大小。然后再用SetScrollRate 函数来设置水平和垂直方向上的滚动增量。第三种方法是使用布局控件来布局窗口,滚动窗口会自动计算所有子窗口需要的窗口大小作为窗口的虚大小,你同样需要调用SetScrollRate函数来设置滚动增量。 你可以想普通窗口那样使用重画事件,但是在进行任何窗口重画动作之前你应该调用DoPrepareDC函数来保证重画动作以当前的窗口原点作为原点,就象下面演示的那样: ``` void MyScrolledWindow::OnPaint(wxPaintEvent& event) { wxPaintDC dc(this); DoPrepareDC(dc); dc.SetPen(*wxBLACK_PEN); dc.DrawLine(0, 0, 100, 100); } ``` 你也可以直接重载OnDraw虚函数,wxScrolledWindow在调用这个函数之前,会首先调用DoPrepareDC函数,因此你只需要象下面演示的那样作: ``` void MyScrolledWindow::OnDraw(wxDC& dc) { dc.SetPen(*wxBLACK_PEN); dc.DrawLine(0, 0, 100, 100); } ``` 需要注意的是,在别的任何事件处理函数中如果要重画窗口,你同样需要调用DoPrepareDC函数。 你也可以象下面这样提供你自己的DoPrepareDC函数,这个函数默认的行为只是把设备操作原点移动到当前滚动条开始的位置: ``` void wxScrolledWindow::DoPrepareDC(wxDC& dc) { int ppuX, ppuY, startX, startY; GetScrollPixelsPerUnit(& ppuX, & ppuY); GetViewStart(& startX, & startY); dc.SetDeviceOrigin( - startX * ppuX, - startY * ppuY ); } ``` 关于在wxScrollWindow上进行作图的详细情形,包括怎样使用双缓冲区,请参考第5章,�重画和打印�中的wxPaintDC小节。 wxScrolledWindow的窗口类型 wxScrolledWindow类并没有特别的窗口类型,但是通常需要设置wxVSCROLL|wxHSCROLL类型,这也是wxScrolledWindow的默认类型。在某些平台上因为效率的原因可能不支持这两个类型。 wxScrolledWindow的事件 wxScrolledWindow会产生wxScrollWinEvent事件(参见下表).这些事件不会在父子窗口关系中传播,因此要处理这种事件,你必须定义自己的滚动窗口派生类或者挂载你自己的事件表。不过在通常情况下,你并不需要覆盖默认的处理函数来自己处理这些事件。 | EVT_SCROLLWIN(func) | 处理所有滚动事件. | |:--- |:--- | | EVT_SCROLLWIN_TOP(func) | 处理事件wxEVT_SCROLLWIN_TOP,滚动到最顶端. | | EVT_SCROLLWIN_BOTTOM(func) | 处理事件wxEVT_SCROLLWIN_BOTTOM 滚动到最底端事件. | | EVT_SCROLLWIN_LINEUP(func) | 处理事件wxEVT_SCROLLWIN_LINEUP上滚一行. | | EVT_SCROLLWIN_LINEDOWN(func) | 处理事件wxEVT_SCROLLWIN_LINEDOWN 下滚一行. | | EVT_SCROLLWIN_PAGEUP(func) | 处理事件wxEVT_SCROLLWIN_PAGEUP 上滚一页. | | EVT_SCROLLWIN_PAGEDOWN(func) | 处理事件 wxEVT_SCROLLWIN_PAGEDOWN 下滚一页. | wxScrolledWindow的成员函数介绍 CalcScrolledPosition和CalcUnscrolledPosition函数都需要四个参数,前两个整数参数是输入需要计算的点,后两个则是指向整数的指针用来放置计算结果。第一个函数用来计算实际位置到逻辑位置的映射。如果当前的滚动条下滚了10个象素,则0这个数字作为输入将得到对应输出-10,第二个函数则实现相反的功能。 EnableScrolling函数用来允许或者禁止垂直或者水平方向的物理滚动。物理滚动的含义是说在收到滚动事件的时候对窗口进行物理上的平移。但是如果应用程序需要不等量的移动(比如,由于字体的不同为了避免滚动的时候显示半行字的情况出现),则需要禁止物理移动,在这种情况下,应用程序需要自己移动对应的子窗口。物理移动在所有支持物理移动的平台上都是默认打开的。当然不是所有的平台都支持物理移动。 GetScrollPixelsPerUnit函数在两个指向整数的指针中返回水平和垂直方向上的移动单位。返回0表示在那个方向上不能滚动。 GetViewStart函数返回窗口可视部分左上角的座标,单位是逻辑单位,你需要乘以GetScrollPixelsPerUnit的返回值以便将结果转换成象素单位。 GetVirtualSize返回当前设定的以象素为单位的虚拟窗口大小。 DoPrepareDC将画画设备的原点设置到当前的可见原点。 Scroll函数将窗口滚动到一个特定的逻辑单位位置(注意这里的单位不是象素). SetScrollbars用来设置移动单位的象素值,各个方向的移动单位总数,水平或者垂直方向的当前滚动位置(可选)以及是否立即刷新窗口(默认否)等。 SetScrollRate用来设置滚动单位,相当于单独设置SetScrollbars中的移动单位参数. SetTargetWindow用来滚动非wxScrolledWindow类型的其它窗口. 滚动非wxScrolledWindow类型的窗口 如果你想自己实现窗口的滚动行为,你可以直接从wxWindow派生你的窗口类,然后使用SetScrollbar函数来设置这个窗口的滚动条。 SetScrollbar函数的参数如下表的说明: | int orientation | 滚动条的类型: wxVERTICAL or wxHORIZONTAL. | |:--- |:--- | | int position | 滚动条滑块的位置,逻辑滚动单位. | | int visible | 可见部分大小,逻辑滚动单位. 通常会决定滑块的长度. | | int range | 滚动条的最大长度,逻辑滚动单位. | | bool refresh | 是否立即刷新窗口. | 举例来说,如果你想显示一个50行文本的文本窗口,使用同样的字体,而窗口的大小只够显示16行,你可以使用下面的代码: ``` SetScrollbar(wxVERTICAL, 0, 16, 50) ``` 注意在上面的例子中,滑块的位置永远不可能大于50-16=34. 你可以通过用当前窗口除以当前字体下文本的高度来得到当前窗口可以显示多少行这个值。 如果你是自己实现滚动行为,你总是需要在窗口大小发生改变的时候更改滚动条的设置。因此你可以在首次计算滚动条参数的代码中使用AdjustScrollbars函数,然后在wxSizeEvent的处理事件中使用AdjustScrollbars函数。 你可以参考wxGrid控件的代码来获得实现自定义滚动窗口的更多灵感。 你也可以参考wxWidgets手册中的wxVScrolledWindow类,它可以用来建立一个可以在垂直方向进行不固定单位滚动的窗口类。 wxSplitterWindow 这个类用来管理最多两个窗口,如果你想在更多窗口中实现分割,你可以使用多个分割窗口。当前的窗口可以被应用程序分割成两个窗口,比如通过一个菜单命令,也可以通过应用程序命令或者通过分割窗口的用户操作界面(双击分割条或者拖拽分割条使得其中一个窗口的大小变为0)重新变为一个窗口.其中拖拽分割条的方法将会受到后面会提到的SetMinimumPaneSize方法的限制。 在大多数平台上,当分割条被拖拽时,会有一个和背景颜色相反的竖条随之移动以显示分割条的最终位置,你可以通过使用 wxSP_LIVE_UPDATE窗口类型来使得分割条以实时方式通过直接改变两个窗口的大小来代替那种默认方式。实时方式是Mac OS X上默认的也是唯一的方式。 下面的代码演示了怎样创建一个分割窗口来操作两个窗口并且隐藏其中的一个: ``` #include "wx/splitter.h" wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY, wxPoint(0, 0), wxSize(400, 400), wxSP_3D); leftWindow = new MyWindow(splitter); leftWindow->SetScrollbars(20, 20, 50, 50); rightWindow = new MyWindow(splitter); rightWindow->SetScrollbars(20, 20, 50, 50); rightWindow->Show(false); splitter->Initialize(leftWindow); //去掉下面的注释以便禁止窗口隐藏 // splitter->SetMinimumPaneSize(20); 下面的代码代码演示了创建分割窗口以后怎样使用它: void MyFrame::OnSplitVertical(wxCommandEvent& event) { if ( splitter->IsSplit() ) splitter->Unsplit(); leftWindow->Show(true); rightWindow->Show(true); splitter->SplitVertically( leftWindow, rightWindow ); } void MyFrame::OnSplitHorizontal(wxCommandEvent& event) { if ( splitter->IsSplit() ) splitter->Unsplit(); leftWindow->Show(true); rightWindow->Show(true); splitter->SplitHorizontally( leftWindow, rightWindow ); } void MyFrame::OnUnsplit(wxCommandEvent& event) { if ( splitter->IsSplit() ) splitter->Unsplit(); } ``` 下图演示了分割窗口在windows平台上的例子,在这个例子中,分割窗口没有使用wxSP_NO_XP_THEME类型。如果使用了这个类型,分割窗口将会拥有更传统的下沉边框和3维外观。 ![](img/mht1CCD%281%29.tmp) wxSplitterWindow的窗口类型 | wxSP_3D | 使用三维效果的边框和分割条 . | |:--- |:--- | | wxSP_3DSASH | 使用三维效果分割条 . | | wxSP_3DBORDER | 和xSP_BORDER效果相同 | | wxSP_BORDER | 使用标准边框 . | | wxSP_NOBORDER | 无边框(默认值). | | wxSP_NO_XP_THEME | 在Xp操作系统上,如果你不喜欢默认的效果,使用三维边框和分割条效果。 | | wxSP_PERMIT_UNSPLIT | 即使设置了最小值也允许窗口被隐藏. | | wxSP_LIVE_UPDATE | 在分割条移动的时候实时更新窗口. | wxSplitterWindow事件 wxSplitterWindow使用wxSplitterEvent类型的事件处理函数 | EVT_SPLITTER_SASH_POS_CHANGING(id,func) | 用于处理wxEVT_COMMAND_SPLITTER_SASH_ POS_CHANGING事件,在分割条位置即将改变的时候产生。调用Veto函数阻止分割条移动,或者调用事件的SetSashPosition函数来更改分割条的位置. | |:--- |:--- | | EVT_SPLITTER_SASH(id,func) | 用于处理wxEVT_COMMAND_SPLITTER_ SASH_POS_CHANGED事件,分割条的位置已经改变你可以通过事件的SetSashPosition函数阻止这种改变或者更改变化的幅度. | | EVT_SPLITTER_UNSPLIT(id,func) | 用于处理wxEVT_COMMAND_SPLITTER_UNSPLIT事件,在有某个窗口被隐藏的时候产生. | EVT_SPLITTER_DCLICK(id,func) | 用于处理wxEVT_COMMAND_SPLITTER_DOUBLECLICKED事件,在分割条被双击的时候产生. | wxSplitterWindow的成员函数 GetMinimumPaneSize和SetMinimumPaneSize函数用于操作分割窗口的最小窗格大小。默认为0,意味着分割窗口的每一侧的大小都可以被缩减至0。相当于移除某一部分分割窗口.要阻止这种情形,也为了阻止拖拽分割条的时候超出边界,可以将其设置成一个大于0的值比如20个象素。虽然这样,如果设置了wxSP_PERMIT_UNSPLIT窗口类型,即使最小值设置为大于0的数,也还是可以将某个分割窗口隐藏。 GetSashPosition和SetSashPosition用来操作分割条的位置,传递true参数给SetSashPosition函数导致分割条被立刻刷新。 GetSplitMode和SetSplitMode函数用来设置分割的方向wxSPLIT_VERTICAL或者wxSPLIT_HORIZONTAL. GetWindow1和GetWindow2用来获取两个分割窗口的指针。 Initialize函数使用一个窗口指针参数调用,用来显示两个分割窗口中的某一个窗口。 IsSplit函数用来判断窗口是否处于分割状态. ReplaceWindow用来替换被分割窗口控制的两个窗口中的一个。使用这个函数要好过先使用Unsplit函数然后再增加另外一个窗口. SetSashGravity用一个浮点小数来设置分割比例。0.0表示只显示右边或者下边的窗口,1.0表示只显示左边或者上边的窗口。中间的值则表示按照某种比例分配两个窗口的大小。使用GetSashGravity函数来获取当前的分割比例。 SplitHorizontally函数SplitVertically使用一个可选的分割尺寸来初始化分割窗口。 Unsplit去掉指定的那个分割窗口. UpdateSize用来使得分割窗口立即刷新(通常情况下,这是在系统空闲的时候完成的). 布局控件中使用wxSplitterWindow的说明 在布局控件中使用分割窗口有一点细微之处需要说明一下。如果你不需要这个分割窗口的分割条是可移动的,你可以在创建两个子窗口的时候指定绝对大小。这将固定这两个子窗口的最小大小,从而使得分割条不能自由移动。如果你希望分割条能正常移动,在创建两个子窗口的时候你就需要使用默认的大小,然后在分割窗口的构造函数中指定其最小大小。然后在将这个分割窗口增加到布局控件的时候,在Add函数中使用wxFIXED_MINSIZE标记来告诉wxWidgets 将分割窗口控件当前的大小作为其最小大小。 另外一种情况是,分割窗口没有设定分割条的位置,也没有设定它的子窗口的大小,当布局控件完成布局时,分割窗口不愿意过早的设置分割条的位置,而要等到系统空闲的时候(这是它的默认行为)。在这种情况下,我们可能会看到当窗口刚刚可见的时候分割条复位自己的位置。为了避免出现这种情景,我们应该在对布局控件调用Fit之后,马上调用分割窗口的UpdateSize函数让其作立即更新。 默认情况下,当用户或者应用程序改变分割窗口的大小时,只有底端(或者右端)的子窗口改变自己的大小以便获取或减小额外的空间,要改变这种默认的行为,你可以使用前面说过的SetSashGravity函数指定一个固定的分割比例。 wxSplitterWindow的替代者 如果在应用程序中你需要使用很多的分割窗口,不妨考虑使用wxSashWindow.这个窗口允许它的任何边成为一个分割条,以便将其分割成多个窗口。而新分的这些窗口通常是用户创建的wxSashWindow的子窗口。 当wxSashWindow的分割条被拖动时,会向应用程序发送wxSashEvent事件以便事件处理函数可以相应的进行窗口布局。布局是通过一个称为wxLayoutAlgorithm的类来完成的,这个类可以根据父窗口的不同提供LayoutWindow,LayoutFrame, LayoutMDIFrame等多种不同的排列方法。 你还可以使用wxSashLayoutWindow类,这个类通过wxQueryLayoutInfoEvent事件来给wxLayoutAlgorithm提供布局方向和尺寸方面的信息。 关于wxSashWindow,wxLayoutAlgorithm和wxSashLayoutWindow更多的信息请参考手册中的相关内容。wxSashWindow不允许子窗口被移动或者分离,因此在不久的将来,这个类可能被一个通用的支持合并和分离的布局框架体系所代替。 下图演示了samples/sashtest目录中的例子在windows上执行的效果: ![](img/mht1CE0%281%29.tmp)