# 12.7 編寫自定義的控件
這一小節,我們來介紹一下怎樣創建自定義的控件.實際上,wxWidgets并不具有象別的應用程序開發平臺上的二進制的,支持鼠標拖入應用程序窗口的這種控件.第三方控件通常都和wxWidgets自帶的控件比如wxCalendarCtrl和wxGrid一樣,是通過源代碼的方式提供的.我們這里用的 "控件"一詞,含義是比較松散的,你不一定非要從"wxControl"進行派生,比如有時候,你可能更愿意從wxScrolledWindow產生派生類.
制作一個自定義的控件通常需要經過下面10個步驟:
1. 編寫類聲明,它應該擁有一個默認構造函數,一個完整構造函數,一個Create函數用于兩步創建, 最好還有一個Init函數用于初始化內部數據.
2. 增加一個函數DoGetBestSize,這個函數應該根據內部控件的情況(比如標簽尺寸)返回該控件最合適的大小.
3. 如果已有的事件類不能滿足需要,為你的控件增加新的事件類. 比如對于內部的一個按鈕被按下的事件,可能使用已有的wxCommandEvent就可以了,但是更復雜的控件需要更復雜的事件類.并且如果你增加了新的事件類,也應改增加相應的事件映射宏.
4. 編寫代碼在你的新控件上顯示信息.
5. 編寫底層鼠標和鍵盤控制代碼,并在其處理函數中產生你自定義的新的事件,以便應用程序可以作出相應處理.
6. 編寫默認事件處理函數,以便控件可以處理那些標準事件(比如處理wxID_COPY或wxID_UNDO等標準命令的事件)或者默認的用戶界面更新事件.
7. 可選的增加一個驗證器類,以便應用程序可以用它使得數據和控件之間的傳輸變得容易,并且增加數據校驗功能.
8. 可選的增加一個資源處理類,以便可以在XRC文件中使用你自定義的控件.
9. 在你準備使用的所有平臺上測試你的自定義控件.
10. 編寫文檔
我們來舉一個簡單的例子,這個例子我們在第三章"事件處理"中曾經使用過,當時我們用來討論自定義的事件: wxFontSelectorCtrl,你可以在隨書光盤的examples/chap03中找到這個例子.這個類提供了一個字體預覽窗口,當用戶在這個窗口上點擊鼠標的時候會彈出一個標準的字體選擇窗口用于更改當前字體.這將導致一個新的事件wxFontSelectorCtrlEvent,應用程序可以使用EVT_FONT_SELECTION_CHANGED(id, func)宏來攔截這個事件.
這個控件的運行效果如下圖所示,下圖中靜態文本下方即為我們自定義的控件.

自定義控件的類聲明
下面的代碼展示了自定義控件wxFontSelectorCtrl的類聲明.其中DoGetBestSize只簡單的返回固定值200x40象素,如果構造函數中沒有指定大小,我們會默認使用這個大小.
```
/*!
* 一個顯示顯示字體預覽的自定義控件.
*/
class wxFontSelectorCtrl: public wxControl
{
DECLARE_DYNAMIC_CLASS(wxFontSelectorCtrl)
DECLARE_EVENT_TABLE()
public:
// 默認構造函數
wxFontSelectorCtrl() { Init(); }
wxFontSelectorCtrl(wxWindow* parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxSUNKEN_BORDER,
const wxValidator& validator = wxDefaultValidator)
{
Init();
Create(parent, id, pos, size, style, validator);
}
// Create函數
bool Create(wxWindow* parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxSUNKEN_BORDER,
const wxValidator& validator = wxDefaultValidator);
// 通用初始化函數
void Init() { m_sampleText = wxT("abcdeABCDE"); }
// 重載函數
wxSize DoGetBestSize() const { return wxSize(200, 40); }
// 事件處理函數
void OnPaint(wxPaintEvent& event);
void OnMouseEvent(wxMouseEvent& event);
// 操作函數
void SetFontData(const wxFontData& fontData) { m_fontData = fontData; };
const wxFontData& GetFontData() const { return m_fontData; };
wxFontData& GetFontData() { return m_fontData; };
void SetSampleText(const wxString& sample);
const wxString& GetSampleText() const { return m_sampleText; };
protected:
wxFontData m_fontData;
wxString m_sampleText;
};
```
象wxFontDialog中的那樣,我們使用wxFontData類型來保存字體數據,這個類型可以額外的保存字體顏色信息.
這個控件的RTTI(運行期類型標識)事件表和創建函數的代碼列舉如下:
```
BEGIN_EVENT_TABLE(wxFontSelectorCtrl, wxControl)
EVT_PAINT(wxFontSelectorCtrl::OnPaint)
EVT_MOUSE_EVENTS(wxFontSelectorCtrl::OnMouseEvent)
END_EVENT_TABLE()
IMPLEMENT_DYNAMIC_CLASS(wxFontSelectorCtrl, wxControl)
bool wxFontSelectorCtrl::Create(wxWindow* parent, wxWindowID id,
const wxPoint& pos, const wxSize& size, long style,
const wxValidator& validator)
{
if (!wxControl::Create(parent, id, pos, size, style, validator))
return false;
SetBackgroundColour(wxSystemSettings::GetColour(
wxSYS_COLOUR_WINDOW));
m_fontData.SetInitialFont(GetFont());
m_fontData.SetChosenFont(GetFont());
m_fontData.SetColour(GetForegroundColour());
// 這個函數告訴相應的布局控件使用指定的最佳大小.
SetBestFittingSize(size);
return true;
}
```
對于函數SetBestFittingSize的調用告訴布局控件或者使用構造函數中指定的大小,或者使用DoGetBestSize函數返回的大小作為這個控件的最小尺寸.當控件被增加到一個布局控件中時,根據增加函數的參數不同,這個控件的尺寸有可能被放大.
增加DoGetBestSize函數
實現DoGetBestSize函數的目的是為了讓wxWidgets可以以此作為控件的最小尺寸以便更好的布局.如果你提供了這個函數,用戶就可以在創建控件的時候使用默認的大小(wxDefaultSize)以便控件自己決定自己的大小.在這里我們只是選擇一個固定值200x40象素,雖然是固定的,但是是合理的.當然,應用程序可以通過在構造函數中傳遞不同的大小來覆蓋它.類似按鈕或者標簽這樣的控件,我們可以提供一個合理的大小,當然,你的控件也可能不能夠決定自己的大小,比如一個沒有子窗口的滾動窗口通常無法知道自己最合適的大小,在這種情況下,你可以不理會 wxWindow::DoGetBestSize.在這種情況下,你的控件大小將取決于用戶在構造函數中指定的非默認大小或者應用程序需要通過一個布局控件來自動覺得你的控件的大小.
如果你的控件包含擁有可感知大小的子窗口,你可以通過所有子窗口的大小來決定你自己控件的大小,子窗口的合適大小可以通過 GetAdjustedBestSize函數獲得.比如如果你的控件包含水平平鋪的兩個子窗口,你可以用下面的代碼來實現DoGetBestSize函數:
```
wxSize ContainerCtrl::DoGetBestSize() const
{
// 獲取子窗口的最佳大小
wxSize size1, size2;
if ( m_windowOne )
size1 = m_windowOne->GetAdjustedBestSize();
if ( m_windowTwo )
size2 = m_windowTwo->GetAdjustedBestSize();
// 因為子窗口是水平平鋪的,因此
// 通過下面的方法計算控件的最佳大小.
wxSize bestSize;
bestSize.x = size1.x + size2.x;
bestSize.y = wxMax(size1.y, size2.y);
return bestSize;
}
```
定義一個新的事件類
我們在第三章中詳細介紹了怎樣創建一個新的事件類(wxFontSelectorCtrlEvent)及其事件映射宏 (EVT_FONT_SELECTION_CHANGED).使用這個控件的應用程序可能并不需要攔截這個事件,因為可以直接使用數據傳送機制會更方便. 不過在一個更復雜的例子中,事件類可以提供特別的函數,以便應用程序的事件處理函數可以從事件中獲取更有用的信息,比如在這個例子中,我們可以增加 wxFontSelectorCtrlEvent::GetFont函數以返回用戶當前選擇的字體.
顯示控件信息
我們的自定義控件使用一個簡單的重繪函數顯示控件信息(一個居中放置的使用指定字體的文本),如下所示:
```
void wxFontSelectorCtrl::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
wxRect rect = GetClientRect();
int topMargin = 2;
int leftMargin = 2;
dc.SetFont(m_fontData.GetChosenFont());
wxCoord width, height;
dc.GetTextExtent(m_sampleText, & width, & height);
int x = wxMax(leftMargin, ((rect.GetWidth() - width) / 2)) ;
int y = wxMax(topMargin, ((rect.GetHeight() - height) / 2)) ;
dc.SetBackgroundMode(wxTRANSPARENT);
dc.SetTextForeground(m_fontData.GetColour());
dc.DrawText(m_sampleText, x, y);
dc.SetFont(wxNullFont);
}
```
如果你需要繪制標準元素,比如分割窗口的分割條或者一個邊框,你可以考慮使用wxNativeRenderer類(更多信息請參考使用手冊).
處理輸入
我們的控件會攔截左鍵單擊事件來顯示一個字體對話框,如果用戶選擇了新的字體,則一個新的事件會使用ProcessEvent函數發送給這個控件.這個事件可以被wxFontSelectorCtrl的派生類處理,也可以被包含我們自定義控件的對話框或者窗口處理.
```
void wxFontSelectorCtrl::OnMouseEvent(wxMouseEvent& event)
{
if (event.LeftDown())
{
// 獲取父窗口
wxWindow* parent = GetParent();
while (parent != NULL &&
!parent->IsKindOf(CLASSINFO(wxDialog)) &&
!parent->IsKindOf(CLASSINFO(wxFrame)))
parent = parent->GetParent();
wxFontDialog dialog(parent, m_fontData);
dialog.SetTitle(_("Please choose a font"));
if (dialog.ShowModal() == wxID_OK)
{
m_fontData = dialog.GetFontData();
m_fontData.SetInitialFont(
dialog.GetFontData().GetChosenFont());
Refresh();
wxFontSelectorCtrlEvent event(
wxEVT_COMMAND_FONT_SELECTION_CHANGED, GetId());
event.SetEventObject(this);
GetEventHandler()->ProcessEvent(event);
}
}
}
```
這個控件沒有攔截鍵盤事件,不過你還是可以通過攔截它們來實現和左鍵單擊相同的動作.你也可以在你的控件上繪制一個虛線框來表明是否其當前擁有焦點,這可以通過wxWindow::FindFocus函數判斷,如果你決定這樣作,你就需要攔截EVT_SET_FOCUS和 EVT_KILL_FOCUS事件來在合式的時候進行窗口刷新.
定義默認事件處理函數
如果你看過了wxTextCtrl的實現代碼,比如src/msw/textctrl.cpp中的代碼,你就會發現一些標準的標識符比如 wxID_COPY,wxID_PASTE, wxID_UNDO和wxID_REDO以及用戶界面更新事件都有默認的處理函數.這意味著如果你的應用程序設置了將事件首先交給活動控件處理(參考第 20章:"優化你的程序"),這些標準菜單項事件或者工具按鈕事件將會擁有自動處理這些事件的能力.當然我們自定義的控件還沒有復雜到這種程度,不過你還是可以通過這種機制實現撤消/重做操作以及剪貼板相關操作.我們來看看wxTextCtrl的例子:
```
BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
...
EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
EVT_MENU(wxID_SELECTALL, wxTextCtrl::OnSelectAll)
EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
EVT_UPDATE_UI(wxID_SELECTALL, wxTextCtrl::OnUpdateSelectAll)
...
END_EVENT_TABLE()
void wxTextCtrl::OnCopy(wxCommandEvent& event)
{
Copy();
}
void wxTextCtrl::OnPaste(wxCommandEvent& event)
{
Paste();
}
void wxTextCtrl::OnSelectAll(wxCommandEvent& event)
{
SetSelection(-1, -1);
}
void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
{
event.Enable( CanCopy() );
}
void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
{
event.Enable( CanPaste() );
}
void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event)
{
event.Enable( GetLastPosition() > 0 );
}
```
實現驗證器
正如我們在第9章,"創建自定義的對話框"中看到的那樣,驗證器是數據在變量和控件之間傳輸的一種很方便地手段.當你創建自定義控件的時候,你可以考慮創建一個特殊的驗證器以便應用程序可以使用它來和你的控件進行數據傳輸.
wxFontSelectorValidator是我們為wxFontSelectorCtrl控件事件的驗證器,你可以將其和一個字體指針和顏色指針或者一個wxFontData對象綁定.這些變量通常是在對話框的成員變量中聲明的,以便對話框持續跟蹤控件改變并且在對話框被關閉以后可以通過其成員返回相應的值.注意驗證器的使用方式,不需要使用new函數創建驗證器,SetValidator函數將創建一份驗證器的拷貝并且在需要的時候自動釋放它.如下所示:
```
wxFontSelectorCtrl* fontCtrl =
new wxFontSelectorCtrl( this, ID_FONTCTRL,
wxDefaultPosition, wxSize(100, 40), wxSIMPLE_BORDER );
// 或者使用字體指針和顏色指針作為參數
fontCtrl->SetValidator( wxFontSelectorValidator(& m_font,
& m_fontColor) );
// ...或者使用wxFontData指針作為參數
fontCtrl->SetValidator( wxFontSelectorValidator(& m_fontData) );
```
m_font和m_fontColor變量(或者m_fontData變量)將反應用戶對字體預覽控件所做的任何改變.數據傳輸在控件所在的對話框的transferDataFromWindow函數被調用的時候發生(這個函數將被默認的wxID_OK處理函數調用).
實現驗證器必須的函數包括默認構造函數,帶參數的構造函數,一個Clone函數用于復制自己.Validate函數用于校驗數據并在數據非法的時候顯示相關信息.transferToWindow和transferFromWindow則實現具體的數據傳輸.
下面列出了wxFontSelectorValidator的聲明:
```
/*!
* wxFontSelectorCtrl驗證器
*/
class wxFontSelectorValidator: public wxValidator
{
DECLARE_DYNAMIC_CLASS(wxFontSelectorValidator)
public:
// 構造函數
wxFontSelectorValidator(wxFontData *val = NULL);
wxFontSelectorValidator(wxFont *fontVal,
wxColour* colourVal = NULL);
wxFontSelectorValidator(const wxFontSelectorValidator& val);
// 析構函數
~wxFontSelectorValidator();
// 復制自己
virtual wxObject *Clone() const
{ return new wxFontSelectorValidator(*this); }
// 拷貝數據到變量
bool Copy(const wxFontSelectorValidator& val);
// 在需要校驗的時候被調用
// 此函數應該彈出錯誤信息
virtual bool Validate(wxWindow *parent);
// 傳輸數據到窗口
virtual bool TransferToWindow();
// 傳輸數據到變量
virtual bool TransferFromWindow();
wxFontData* GetFontData() { return m_fontDataValue; }
DECLARE_EVENT_TABLE()
protected:
wxFontData* m_fontDataValue;
wxFont* m_fontValue;
wxColour* m_colourValue;
// 檢測是否驗證器已經被正確設置
bool CheckValidator() const;
};
```
建議閱讀fontctrl.cpp文件中相關的函數實現以便對齊有進一步的了解.
實現資源處理器
如果你希望你自定義的控件可以在XRC文件中使用,你可以提供一個對應的資源處理器.我們在這里不對此作過多的介紹,請參考第9章,介紹XRC體系時候的相關介紹.同時也可以參考wxWidgets發行目錄include/wx/xrc和src/xrc中已經的實現.
你的資源處理器在應用程序中登記以后,XRC文件可以包含你的自定義控件了,它們也可以被你的應用程序自動加載.不過如果制作這個XRC 文件也稱為一個麻煩事.因為通常對話框設計工具都不支持動態加載自定義控件.不過通過DialogBlocks的簡單的自定義控件定義機制,你可以指定你的自定義控件的名稱和屬性,以便生成正確的XRC文件,雖然,DialogBlocks只能作到在其設計界面上顯示一個近似的圖形以代替你的自定義控件.
檢測控件顯示效果
當創建自定義控件的時候,你需要給wxWidgets一些關于控件外觀的小提示.記住,wxWidgets總會盡可能的使用系統默認的顏色和字體,不過也允許應用程序或者自定義控件在平臺允許的時候自己決定這些屬性.wxWidgets也會讓應用程序或者控件自己決定是否這些屬性應該被其子對象繼承.控制這些屬性的體系確實有一些復雜,不過,除非要大量定制控件的顏色(這是不推薦的)或者實現完全屬于自己的控件,程序員很少需要關心這些細節.
除非顯式指明,應用程序通常會允許子窗口(其中可能包含你自定義的控件)繼承它們父窗口的前景顏色和字體.然后這種行為可以通過使用 SetOwnFont函數設置字體或者使用SetOwnForegroundColour函數設置前景顏色來改變.你的控件也可以通過調用 ShouldInheritColours函數來決定是否要繼承父窗口的顏色(wxControl默認需要,而wxWindow則默認不需要).背景顏色通常不需要顯式繼承,你的控件應該通過不繪制不需要的區域的方法來保持和它的父窗口一致的背景.
為了實現屬性繼承,你的控件應該在構造函數中調用InheritAttributes函數,依平臺的不同,這個函數通常可以在構造函數調用wxControl::Create函數的時候被調用.
某些類型實現了靜態函數GetClassDefaultAttributes,這個函數返回一個wxVisualAttributes對象,包含前景色,背景色以及字體設定.這個函數包含一個只有在Mac OS X平臺上才有意義的參數wxWindowVariant.這個函數指定的相關屬性被用在類似GetBackgroundColour這樣的函數中作為應用未指定值時候的返回值.如果你不希望默認的值被返回,你可以在你的控件中重新實現這個函數.同時你也需要重載GetDefaultAttributes虛函數,在其中調用GetClassDefaultAttributes函數以便允許針對某個特定的對象返回默認屬性.如果你的控件包含一個標準控件的類似屬性,你可以直接使用它,如下所示:
```
// 靜態函數,用于全局訪問
static wxVisualAttributes GetClassDefaultAttributes(
wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL)
{
return wxListBox::GetClassDefaultAttributes(variant);
}
// 虛函數,用戶對象返回訪問
virtual wxVisualAttributes GetDefaultAttributes() const
{
return GetClassDefaultAttributes(GetWindowVariant());
}
wxVisualAttributes的結構定義如下:
struct wxVisualAttributes
{
// 內部標簽或者文本使用的字體
wxFont font;
// 前景色
wxColour colFg;
// 背景色; 背景不為純色背景時可能為wxNullColour
wxColour colBg;
};
```
如果你的自定義控件使用了透明背景,比如說,它是一個類似靜態文本標簽的控件,你應該提供一個函數HasTransparentBackground以便wxWidgets了解這個情況(目前僅支持windows).
最后需要說明的是,如果某些操作需要在某些屬性已經確定或者需要在最后的步驟才可以運行.你可以使用空閑時間來作這種處理,在第17章,"多線程編程"的"多線程替代方案"中對此有進一步的描述.
一個更復雜一點的例子:wxThumbnailCtrl
前面我們演示的例子wxFontSelectorCtrl是一個非常簡單的例子,很方便我們逐一介紹自定義控件的一些基本原則,比如事件,驗證器等.然后,對于顯示以及處理輸入方面則顯得有些不足.在隨書光盤的examples/chap12/thumbnail目錄中演示了一個更復雜的例子wxThumbnailCtrl,這個控件用來顯示縮略圖.你可以在任何應用程序中使用它來顯示圖片的縮略圖.(事實上它也可以顯示一些別的縮略圖,你可以實現自己的wxThumbnailItem的派生類以便使其可以支持顯示某種文件類型的縮略圖,比如顯示那些包含圖片的文檔中的縮略圖).
下圖演示的wxThumbnailBrowserDialog對話框使用了wxGenericDirCtrl控件,這個控件使用了wxThumbnailCtrl控件.出于演示的目的,正在顯示的這個目錄放置了一些圖片.

這個控件演示了下面的一些主題,當然列出的并不是全部:
* 鼠標輸入: 縮略圖子項可以通過單擊鼠標左鍵進行選擇或者通過按著Ctrl鍵單擊鼠標左鍵進行多選.
* 鍵盤輸入: 縮略圖網格可以通過鍵盤導航,也可以通過方向鍵翻頁,子項可以通過按住Shift鍵進行選擇.
* 焦點處理: 設置和丟失焦點將導致當前的活動縮略圖的顯示被更新.
* 優化繪圖: 通過wxBufferedPaintDC以及僅更新需要更新的區域的方法實現無閃爍更新當前顯示.
* 滾動窗口: 這個控件繼承自wxScrolledWindow窗口,可以根據子項的數目自動調整滾動條.
* 自定義事件: 在選擇,去選擇以及右鍵單擊的時候產生wxThumbnailEvent類型的事件.
為了靈活處理,wxThumbnailCtrl并不會自動加載一個目錄中所有的圖片,而是需要通過下面的代碼顯式的增加wxThumbnailItem對象.如下所示:
```
// 創建一個多選的縮略圖控件
wxThumbnailCtrl* imageBrowser =
new wxThumbnailCtrl(parent, wxID_ANY,
wxDefaultPosition, wxSize(300, 400),
wxSUNKEN_BORDER|wxHSCROLL|wxVSCROLL|wxTH_TEXT_LABEL|
wxTH_IMAGE_LABEL|wxTH_EXTENSION_LABEL|wxTH_MULTIPLE_SELECT);
// 設置一個漂亮的大的縮略圖大小
imageBrowser->SetThumbnailImageSize(wxSize(200, 200));
// 在填充的時候不要顯示
imageBrowser->Freeze();
// 設置一些高對比的顏色
imageBrowser->SetUnselectedThumbnailBackgroundColour(*wxRED);
imageBrowser->SetSelectedThumbnailBackgroundColour(*wxGREEN);
// 從'path'路徑查找圖片并且增加
wxDir dir;
if (dir.Open(path))
{
wxString filename;
bool cont = dir.GetFirst(&filename, wxT("*.*"), wxDIR_FILES);
while ( cont )
{
wxString file = path + wxFILE_SEP_PATH + filename;
if (wxFileExists(file) && DetermineImageType(file) != -1)
{
imageBrowser->Append(new wxImageThumbnailItem(file));
}
cont = dir.GetNext(&filename);
}
}
// 按照名稱排序
imageBrowser->Sort(wxTHUMBNAIL_SORT_NAME_DOWN);
// 標記和選擇第一個縮略圖
imageBrowser->Tag(0);
imageBrowser->Select(0);
// 刪除第二個縮略圖
imageBrowser->Delete(1);
// 顯示圖片
imageBrowser->Thaw();
```
如果你完整的閱讀thumbnailctrl.h和thumbnail.cpp中的代碼,你一定會得到關于自定義控件的足夠的知識.另外,你也可以在你的應用程序中直接使用wxThumbnailCtrl控件,不要客氣.
- 第一章 介紹
- 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 全書小結