# 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平臺上的結果:

在大多數的平臺上,當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維外觀。

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上執行的效果:

- 第一章 介紹
- 1.1 為什么要使用wxWidgets?
- 1.2 wxWidgets的歷史
- 1.3 wxWidgets社區
- 1.4 wxWidgets和面向對象編程
- 1.5 wxWidgets的體系結構
- 1.6 許可協議
- 第一章小結
- 第二章 開始使用
- 2.1 一個小例子
- 2.2 應用程序類
- 2.3 Frame窗口類
- 2.4 事件處理函數
- 2.5 Frame窗口的構造函數
- 2.6 完整的例子
- 2.7 wxWidgets程序一般執行過程
- 2.8 編譯和運行程序
- 第二章小結
- 第三章 事件處理
- 3.1 事件驅動編程
- 3.2 事件表和事件處理過程
- 3.3 過濾某個事件
- 3.4 掛載事件表
- 3.5 動態事件處理方法
- 3.6 窗口標識符
- 3.7 自定義事件
- 第三章小結
- 第四章 窗口的基礎知識
- 4.1 窗口解析
- 4.2 窗口類概覽
- 4.3 基礎窗口類
- 4.4 頂層窗口
- 4.5 容器窗口
- 4.6 非靜態控件
- 4.7 靜態控件
- 4.8 菜單
- 4.9 控制條
- 第四章小結
- 第五章繪畫和打印
- 5.1 理解設備上下文
- 5.2 繪畫工具
- 5.3 設備上下文中的繪畫函數
- 5.4 使用打印框架
- 5.5 使用wxGLCanvas繪制三維圖形
- 第五章小節
- 第六章處理用戶輸入
- 6.1 鼠標輸入
- 6.2 處理鍵盤事件
- 6.3 處理游戲手柄事件
- 第六章小結
- 第七章使用布局控件進行窗口布局
- 7.1 窗口布局基礎
- 7.2 窗口布局控件
- 7.3 使用布局控件進行編程
- 7.4 更多關于布局的話題
- 第七章小結
- 第八章使用標準對話框
- 8.1信息對話框
- 8.2 文件和目錄對話框
- 8.3 選擇和選項對話框
- 8.4 輸入對話框
- 8.5 打印對話框
- 第八章小結
- 第九章創建定制的對話框
- 9.1 創建定制對話框的步驟
- 9.2 一個例子:PersonalRecordDialog
- 9.3 在小型設備上調整你的對話框
- 9.4 一些更深入的話題
- 9.5 使用wxWidgets資源文件
- 第九章小結
- 第十章使用圖像編程
- 10.1 wxWidgets中圖片相關的類
- 10.2 使用wxBitmap編程
- 10.3 使用wxIcon編程
- 10.4 使用wxCursor編程
- 10.5 使用wxImage編程
- 10.6 圖片列表和圖標集
- 10.7 自定義wxWidgets提供的小圖片
- 第十章小結
- 第十一章剪貼板和拖放操作
- 11.1 數據對象
- 11.2 使用剪貼板
- 11.3 實現拖放操作
- 第十一章小結
- 第十二章高級窗口控件
- 12.1 wxTreeCtrl
- 12.2 wxListCtrl
- 12.3 wxWizard
- 12.4 wxHtmlWindow
- 12.5 wxGrid
- 12.6 wxTaskBarIcon
- 12.7 編寫自定義的控件
- 第十二章小結
- 第十三章數據結構類
- 13.1 為什么沒有使用STL?
- 13.2 字符串類型
- 13.3 wxArray
- 13.4 wxList和wxNode
- 13.5 wxHashMap
- 13.6 存儲和使用日期和時間
- 13.7 其它常用的數據類型
- 第十三章小結
- 第十四章文件和流操作
- 14.1 文件類和函數
- 14.2 流操作相關類
- 第十四章小結
- 第十五章內存管理,調試和錯誤處理
- 15.1 內存管理基礎
- 15.2 檢測內存泄漏和其它錯誤
- 15.3 構建自防御的程序
- 15.4 錯誤報告
- 15.5 提供運行期類型信息
- 15.6 使用wxModule
- 15.7 加載動態鏈接庫
- 15.8 異常處理
- 15.9 調試提示
- 第十五章小結
- 第十六章編寫國際化程序
- 16.1 國際化介紹
- 16.2 從翻譯說起
- 16.3 字符編碼和Unicode
- 16.4 數字和日期
- 16.5 其它媒介
- 16.6 一個小例子
- 第十六章小結
- 第十七章編寫多線程程序
- 17.1 什么時候使用多線程,什么時候不要使用
- 17.2 使用wxThread
- 17.3 用于線程同步的對象
- 17.4 多線程的替代方案
- 第十七章小結
- 第十八章使用wxSocket編程
- 18.1 Socket類和功能概覽
- 18.2 Socket及其基本處理介紹
- 18.3 Socket標記
- 18.4 使用Socket流
- 18.5 替代wxSocket
- 第十八章小結
- 第十九章使用文檔/視圖框架
- 19.1 文檔/視圖基礎
- 19.2 文檔/視圖框架的其它能力
- 19.3 實現Undo/Redo的策略
- 第十九章小結
- 第二十章完善你的應用程序
- 20.1 單個實例和多個實例
- 20.2 更改事件處理機制
- 20.3 降低閃爍
- 20.4 實現聯機幫助
- 20.5 解析命令行參數
- 20.6 存儲應用程序資源
- 20.7 調用別的應用程序
- 20.8 管理應用程序設置
- 20.9 應用程序安裝
- 20.10 遵循用戶界面設計規范
- 20.11 全書小結