# 3.7 自定義事件
如果你要使用自定義的事件,你需要下面的幾個步驟:
1. 從一個合適的事件類派生一個你自己的事件類,聲明動態類型信息并且實現一個Clone函數,按照你自己的意愿增加新的數據成員和函數成員.如果你希望這個事件在窗口繼承關系之間傳遞,你應該使用的wxCommandEvent派生類,如果你希望這個事件的處理函數可以調用Veto(譯者注:某些事件可以調用這個函數來阻止后續可能對這個事件進行的任何操作(如果有的話),最典型的例子是關閉窗口事件wxEVT_CLOSE),你應該使用 wxNotifyEvent的派生類.
1. 為這個事件類的處理函數定義類型.
1. 定義一個你的事件類支持的事件類型的表。這個表應該定義在你的頭文件中。用BEGIN_DECLARE_EVENT_TYPES()宏和END_DECLARE_EVENT_TYPES()宏包含起來。其中的每一個支持的事件的聲明應該使用DECLARE_EVENT_TABLE (name, integer)格式的宏.然后在你的.cpp文件中使用DEFINE_EVENT_TYPE(name)來實現這個事件類.
1. 為每個你的事件類支持的事件定義一個事件映射宏。
我們還是通過例子來讓上面這段繞口的話顯的更生動一些。假如我們要實現一個新的控件wxFontSelectorCtrl,這個控件將可以顯示字體的預覽。用戶通過點擊字體的預覽來彈出一個對話框讓用戶可以更改字體。應用程序也許想攔截這個字體改變事件,因此我們在我們的底層鼠標消息處理過程中將會給應用程序發送一個自定義的字體改變事件。
因此我們需要定義一個新的事件wxFontSelectorCtrlEvent.應用程序可以通過事件映射宏 EVT_FONT_SELECTION_CHANGED(id, func)來增加對這個事件的處理。我們還需要給這個事件定義一個事件類型: wxEVT_COMMAND_FONT_SELECTION_CHANGED. 這樣,我們的頭文件看上去就象下面的樣子:
```
/*!
* Font selector event class
*/
class wxFontSelectorCtrlEvent : public wxNotifyEvent
{
public:
wxFontSelectorCtrlEvent(wxEventType commandType = wxEVT_NULL,
int id = 0): wxNotifyEvent(commandType, id)
{}
wxFontSelectorCtrlEvent(const wxFontSelectorCtrlEvent& event): wxNotifyEvent(event)
{}
virtual wxEvent *Clone() const
{ return new wxFontSelectorCtrlEvent(*this); }
DECLARE_DYNAMIC_CLASS(wxFontSelectorCtrlEvent);
};
typedef void (wxEvtHandler::*wxFontSelectorCtrlEventFunction)
(wxFontSelectorCtrlEvent&);
/*!
* Font selector control events and macros for handling them
*/
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE(wxEVT_COMMAND_FONT_SELECTION_CHANGED, 801)
END_DECLARE_EVENT_TYPES()
#define EVT_FONT_SELECTION_CHANGED(id, fn) DECLARE_EVENT_TABLE_ENTRY(
wxEVT_COMMAND_FONT_SELECTION_CHANGED, id, -1, (wxObjectEventFunction) (wxEventFunction)
(wxFontSelectorCtrlEventFunction) & fn,
(wxObject *) NULL ),
```
而在我們的.cpp文件中,看上去則象下面的樣子:
```
DEFINE_EVENT_TYPE(wxEVT_COMMAND_FONT_SELECTION_CHANGED)
IMPLEMENT_DYNAMIC_CLASS(wxFontSelectorCtrlEvent, wxNotifyEvent)
```
然后,在我們的新控件的鼠標處理函數中,可以通過下面的方法在檢測到用戶選擇了一個新的字體的時候,發送一個自定義的事件:
```
wxFontSelectorCtrlEvent event(
wxEVT_COMMAND_FONT_SELECTION_CHANGED, GetId());
event.SetEventObject(this);
GetEventHandler()->ProcessEvent(event);
```
現在,在使用我們的新控件的應用程序的代碼中就可以通過下面代碼來處理我們定義的這個新事件了:
```
BEGIN_EVENT_TABLE(MyDialog, wxDialog)
EVT_FONT_SELECTION_CHANGED(ID_FONTSEL, MyDialog::OnChangeFont)
END_EVENT_TABLE()
void MyDialog::OnChangeFont(wxFontSelectorCtrlEvent& event)
{
// 字體已經更改了,可以作一些必要的處理。
...
}
```
上面用到的事件標識符801在最新的版本中已經沒有用處了,之所以這樣寫只是為了兼容wxWidgets2.4的版本。
讓我們再來看一眼事件映射宏的定義:
```
#define EVT_FONT_SELECTION_CHANGED(id, fn) DECLARE_EVENT_TABLE_ENTRY(
wxEVT_COMMAND_FONT_SELECTION_CHANGED, id, -1, (wxObjectEventFunction) (wxEventFunction)
(wxFontSelectorCtrlEventFunction) & fn,
(wxObject *) NULL ),
```
這個宏的作用其實是把一個五元組放入到一個數組中,所以這段代碼的語法看上去是奇怪了一些,這個五元組的意義分別解釋如下:
+ 事件類型:一個事件類可以處理多種事件類型,但是在我們的例子中,只處理了一個事件類型,所以就只有一個事件映射宏的記錄。這個事件類型必須要和事件處理函數所有處理的事件的類型一致。
+ 傳遞給事件映射宏的標識符:只有當事件的標識符和事件表中的標識符一致的時候,相應的事件處理函數才會被調用。
+ 第二標識符。在這里-1表示沒有第二標識符。
+ 事件處理函數。如果沒有類型的強制轉換,一些編譯器會報錯,這也就是我們要定義事件處理函數類型的原因。
+ 用戶數據,通常都是NULL;
隨書附帶光盤中的examples/chap03目錄中有一個完整的自定義事件的例子,其中包括了一個字體選擇控件和一個簡單驗證類,你可以在你的應用程序中使用她們。你還可以閱讀你的wxWidgets發行版目錄中的include/wx/event.h來獲得更多的靈感。
- 第一章 介紹
- 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 全書小結