wxWidgets程序总结

wxWidgets程序一般执行过程如下:



1. wxWidgets初始化它自己的数据结构并且创建一个MyApp的实例



每一个wxWidgets程序都需要定义一个wxApp类的子类,并且需要创建并且只能创建一个这个类的实例,这个实例控制着整个程序的执行。这个继承自wxApp的子类至少需要定义一个OnInit函数,当wxWidgets准备好运行你写的代码的时候,它将会调用这个函数(这和一个典型的Win32程序中的main函数或者WinMain函数类似)。



定义这个子类及其OnInit函数的代码如下所示:


class MyApp:public wxApp

{

public:

virtual bool OnInit();	//有个对应的清理函数OnExit,也是系统自动调用的,只需在里面定义自己的函数就行!!!!!!

};




2.wxWidgets调用MyApp::OnInit函数,这个函数会创建一个MyFrame的实例



这个OnInit函数中,通常应该做的事情包括:创建至少一个窗口实例,对传入的命令行参数进行解析,为应用程序进行数据设置和其他的一些初始化的操作。如果这个函数返回真,wxWidgets将开始事件循环,用来接收用户输入并且在必要的情况下处理这些输入。如果OnInit函数返回假,wxWidgets将会释放它内部已经分配的资源,然后结束整个程序的运行。

OnInit定义如下:

bool MyApp::OnInit()

{

MyFrame *frame = new MyFrame(_T("Event wxWidgets Sample"),

wxPoint(50, 50), wxSize(600, 340));

frame->Show(true);

return true; //返回真,进入事件循环中;如果返回假,程序终止

}



另外,我们需要告诉wxWidgets需要创建一个App类的实例,通过增加如下宏即可:

IMPLEMENT_APP(MyApp);





3.MyFrame的构造函数通过它的基类wxFrame的构造函数创建一个窗口,然后给这个窗口添加图标,菜单栏和状态栏。



一个Frame窗口是一个可以容纳别的窗口的顶层窗口,通常拥有一个标题栏和一个菜单栏。定义如下:



class MyFrame:public wxFrame

{

public:

MyFrame(const wxString& title);

void OnQuit(wxCommandEvent& event);

void OnAbout(wxCommandEvent& event);

private:

DECLARE_EVENT_TABLE() //声明事件表

};



看看MyFrame类窗口的构造函数,正是它实现了frame窗口的图标,菜单条和状态条。该构造函数首先调用它的基类(wxFrame)的构造函数,这个基类的构造函数才真正创建了一个窗口的实例。除了这样的调用方法外,还有另外的一种方法是:直接在构造函数里面显示调用基类默认的构造函数,然后调用wxFrame::Create函数来创建一个frame窗口的实例。



4. 事件表,是组类的实现文件(.CPP文件)中的宏,用来告诉wxWidgets来自用户或者其他地方的事件应该怎样和类的成员函数对应起来 。 定义事件表如下:

BEGIN_EVENT_TABLE(MyFrame, wxFrame)

EVT_MENU(wxID_ABOUT,MyFrame::OnAbout)

EVT_MENU(wxID_EXIT,MyFrame::OnQuit)

END_EVENT_TABLE()


上面展示的事件表表明,要把标识符分别为wxID_EXIT和wxID_ABOUT的菜单事件和MyFrame的成员函数OnAbout和OnQuit关联起来。 EVT_MENT为一事件宏,作用是告诉wxWidgets哪种事件应该被关联到哪个成员函数。 wxID_EXIT和wxID_ABOUT两个标识是wxWidgets预定义的宏,通常应该通过枚举,常量或者宏定义的方式定义自己的标识符。



5. MyApp::OnInit函数显示主窗口并且返回真

6.wxWidgets开始事件循环,等待事件发生并且将事件分发给相应的处理过程。





事件驱动编程

所有的GUI程序都是事件驱动的。换句话说,应用程序一直停留在一个循环中,等待着来自用户或者其他什么地方的事件,一旦收到某种事件,应用程序就将其扔给处理这个事件的函数。

不同的GUI编程架构用不同的方法将它内部的事件处理机制展现给程序开发者。对于wxWidgets来说,事件表机制是最主要的方法。



一、静态事件表

创建一个静态事件表需要下面几个步骤:

(1)定义一个直接或者间接继承自wxEvtHandler的类。

(2)为每一个你想要处理的事件定义一个处理函数。

(3)在这个类中使用DECLARE_EVENT_TABLE声明事件表

(4)在.cpp文件中使用BEGIN_EVENT_TABLE和END_EVENT_TABLE实现一个事件表。

(5)在事件表的实现中增加事件宏,来实现从事件到事件处理过程的映射。



另外,所有的事件处理函数拥有相同的形式。他们的返回值都是void,他们都不是虚函数,他们都只有一个事件对象作为参数。



二、过滤某个事件

wxWidgets事件处理系统实现了一些和C++中的虚方法非常类似的机制,通过这种机制,你可以通过重载某种基类的事件表的方法来改变基类的默认的事件处理过程。

举例来说,你可以过滤某些按键事件以便本地原生的编辑框控件不处理这些按键。要达到这个人目的,你需要实现一个继承自wxTextCtrl的新的类,然后在其事件表中使用EVT_KEY_DOWN事件映射宏。过滤所有的你不想要的按键事件,wxEvent::Skip函数:This method can be used inside an event handler to control whether further event handlers bound to this event will be called after the current one returns. Without Skip() (or equivalently if Skip(false) is used), the event will not be processed any more. If Skip(true) is called, the event processing system continues searching for a further handler function for this event, even though it has been processed already in the current handler(不一定是父类的处理函数!!!).



一般说来,在wxWidgets中,应该通过调用事件Skip方法,而不 是通过显式直接调用其父类对应函数的方法来实现对特殊事件的过滤。



三、挂载事件表

其实并不一定非要实现继承自某个类的新类,才可以改变它的事件表。对于那些继承自wxWidgets的类来说,有另一种可取代的方法。

(1)实现一个新的直接继承自wxEvtHandler的新类,并定义这个新类的事件表

(2)使用wxWindow::PushEventHandler函数将这个事件表压入到某个窗口类的事件表栈中。 最后压入的事件表在事件匹配过程中将会被最先匹配。如果在其中没有匹配到对应的事件处理过程,那么栈中以前的事件表仍将被匹配,如此类推。

(3)你还可以用wxWindow::PopEventHandler函数来弹出最顶层的事件表,如果你给wxWindow::PopEventHandler函数传递的是true的参数,那么这个弹出的事件表将被删除。

这种方法可以避免大量的类重载,也使不同的类的实例共享同一个事件表成为可能。(具体例子,可查看event实例)

(4)有时候,你需要手动调用窗口类的事件表,这时候你应该使用wxWindow::GetEventHandler方法,而不是直接使用调用这个窗口类的成员函数。虽然wxWindow::GetEventHandler通常返回这个窗口类本身。但是如果你之前曾经使用wxWindow::GetEventHandler函数才可以保证事件被正确处理。

wxWindow::PushEventHandler的方法通常用来临时的或者永久的改变图形界面的行为。



四、动态事件处理方法

上面讨论的都是静态的事件表,这也是我们处理事件最常用的方式。接下来,讨论下事件表的动态处理,也就是说在运行期改变事件表的映射关系。动态映射的方法可以使你更精确的控制事件表的细节,你甚至可以单独的将事件表中的某一个条目在运行期打开或者关闭,而前面说的PushEventHandler和PopEventHandler的方法只能针对整个事件表进行处理。除此以外,动态事件处理还允许你在不同的类之间共享事件函数。

和动态事件处理相关的API有两个:wxEventHandler::Connect和wxEventHandler::Disconnect。大多数情况下不需要手动调用wxEventHandler::Disconnect函数,这个函数将在窗口类被释放的时候自动被调用。

void OnQuit(wxCommandEvent& event);

(方式2)frame->Connect(wxID_EXIT,wxEVT_COMMAND_MENU_SELECTED,wxCommandEventHandler(MyFrame::OnQuit));//一般来说,如果事件处理函数的参数类型是wxXYZEvent,那么其处理函数的类型就应该是用wxXYZEventHandler宏进行强制转换。

(方式3)win->Connect(wxEVT_DESTROY,wxObjectEventFunction(&QimWindowManager::OnDestroy),NULL,this);//win类使用QimWindowManager类事件函数OnDestroy,实现了共享事件函数。wxEVT_DESTROY 和wxObjectEventFunction系统定义(vc找)。

其中事件类型:可通过wx帮助文档查找wxCommandEvetnt的EVT_ MENU得到!!!

/****************************************************************/

以下为wx系统定义:

(方式1)
void Connect(int winid,

int lastId,

int eventType,

wxObjectEventFunction func,

wxObject *userData = (wxObject *)NULL,

wxEvtHandler *eventSink = (wxEvtHandler *) NULL);





// Convenience function: take just one id

(方式2)
void Connect(int winid,

int eventType,

wxObjectEventFunction func,

wxObject *userData = (wxObject *) NULL,

wxEvtHandler *eventSink = (wxEvtHandler *) NULL)

{ Connect(winid, wxID_ANY, eventType, func, userData, eventSink); }




// Even more convenient: without id (same as using id of wxID_ANY)

(方式3) 
void Connect(int eventType,

wxObjectEventFunction func,

wxObject *userData = (wxObject *) NULL,

wxEvtHandler *eventSink = (wxEvtHandler *) NULL)

{ Connect(wxID_ANY, wxID_ANY, eventType, func, userData, eventSink); }



/*********************************************************************/



五、自定义事件

如果要使用自定义事件,需要下面几个步骤:

(1)从一个合适的事件类派生一个你自己的事件类,声明动态类型信息并且实现一个Clone函数,按照你自己的意愿增加新的数据成员和函数成员,如果你希望这个事件在窗口继承关系直接传递,你应该使用wxCommandEvent派生类,如果你希望这个事件的处理函数可以调用Veto,你应该使用wxNotifyEvent的派生类。

(2)为这个事件类的处理函数定义类型

(3)定义一个自己的事件类支持的事件类型的表。这个表应该定义在你的头文件中。用BEGIN_DECLARE_EVENT_TYPES()宏和END_DECLARE_EVENT_TYPES()宏包含起来。其中每一个支持的事件的声明应该使用DECLARE_EVENT_TYPE(name, integer)格式的宏,然后在你的.cpp文件中使用DEFINE_EVENT_TYPE(name)来实现这个事件类。

(4)为每个事件类支持的事件定义一个事件映射宏



(1)一个合适的事件类派生一个你自己的事件类:

class WXDLLIMPEXP_QIMCTRLS wxHtmlExternalEvent : public wxCommandEvent

{

public:

wxHtmlExternalEvent(wxEventType commandType = wxEVT_NULL, int id = 0)

:wxCommandEvent(commandType, id)

{



}

wxHtmlExternalEvent(const wxHtmlExternalEvent& event)

: wxCommandEvent(event)

{

m_type = event.m_type;

m_wParam = event.m_wParam;

m_lParam = event.m_lParam;

}

virtual wxEvent *Clone() const { return new wxHtmlExternalEvent(*this); } //克隆函数,不可少



void SetHtmlEvtTyoe(const wxString& type){ m_type = type; }

void SetHtmlWParam(const wxString& wparam){ m_wParam = wparam; }

void SetHtmlLParam(const wxString& lparam ){ m_lParam = lparam; }



wxString GetHtmlEvtTyoe() const { return m_type; }

wxString GetHtmlWParam() const { return m_wParam; }

wxString GetHtmlLParam() const { return m_lParam; }

private:

wxString	m_type;

wxString	m_wParam;

wxString	m_lParam;

DECLARE_DYNAMIC_CLASS(wxHtmlExternalEvent);//声明动态类型

};



(2)为这个事件类的处理函数定义类型:

typedef void (wxEvtHandler::*wxHtmlExternalEventFunction)(wxHtmlExternalEvent&);





(3)

a.定义一个自己的事件类支持的事件类型的表:

BEGIN_DECLARE_EVENT_TYPES()

DECLARE_EVENT_TYPE(wxEVT_HTML_EXTERNAL, 2124) 

END_DECLARE_EVENT_TYPES()



以上三行语句等价:
extern WXDLLIMPEXP_QIMCTRLS const wxEventType wxEVT_HTML_EXTERNAL;





b. 在.CPP文件中:

<pre name="code" class="cpp"><pre name="code" class="cpp"><pre name="code" class="cpp">DEFINE_EVENT_TYPE(wxEVT_HTML_EXTERNAL);//等价于const wxEventType wxEVT_HTML_EXTERNAL = wxNewEventType();

IMPLEMENT_DYNAMIC_CLASS(wxHtmlExternalEvent, wxCommandEvent);//也可以不要该行,可查看wx帮助文档





//在新控件处理函数中,发送自定义事件:(注意系统也有SendMessage发送消息函数)

void FrameSite::SendMessage(const wxString& type,const wxString& wParam,const wxString& lParam)

{

if(m_window == NULL) return;

wxHtmlExternalEvent evt(wxEVT_HTML_EXTERNAL, m_window->GetId());

evt.SetHtmlEvtTyoe(type);

evt.SetHtmlLParam(lParam);

evt.SetHtmlWParam(wParam);

m_window->ProcessEvent(evt);//wxEvtHandler::ProcessEvent(也可以在响应函数中,当函数响应时,发送该消息)

};



/*********************也可以用wxPostEvent函数post消息*****************

wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, XRCID("ID_UNREADMSG"));

wxPostEvent(this, evt); //post evt消息 与发送(send)不同--可查看工作笔记





qim_menus.cpp文件中://发送客户登陆消息事件(自定义事件)

wxCommandEvent evt(ucEVT_CLIENT_LOGIN);

QimJabberJob::GetInstance()->SendEvent(evt);//其实里面也是用了ProcessEvent和wxPostEvent发送消息

*********************************************************************/
 



//在使用新控件的应用程序代码中,可以通过以下代码来处理我们自定义的事件了。

BEGIN_EVENT_TABLE(QimSendEmailFrame,wxFrame)

EVT_HTML_EXTERNAL(wxID_ANY,QimSendEmailFrame::OnHtmlExternal) //wxID_ANY为新控件ID

END_EVENT_TABLE()



void QimSendEmailFrame::OnHtmlExternal(wxHtmlExternalEvent& /*event*/)

{

...

}

/*******************************************************************

其中:(以下为wx系统定义)

a.

#ifdef WXMAKINGDLL_QIMRECORD

#define WXDLLIMPEXP_QIMRECORD WXEXPORT

#elif defined(WXUSINGDLL)

#define WXDLLIMPEXP_QIMRECORD WXIMPORT

#else // not making nor using DLL

#define WXDLLIMPEXP_QIMRECORD

#endif



#define WXEXPORT __declspec(dllexport)

#define WXIMPORT __declspec(dllimport)



b. #define DEFINE_EVENT_TYPE(name) const wxEventType name = wxNewEventType();

******************************************************************/
 
 

(4)为每个事件类支持的事件定义一个事件映射宏:

/***************************************************** ************

注意以下是在wx系统中定义好的:

#define wx__DECLARE_EVT2(evt, id1, id2, fn) \

DECLARE_EVENT_TABLE_ENTRY(evt, id1, id2, fn, NULL),

#define wx__DECLARE_EVT1(evt, id, fn) \

wx__DECLARE_EVT2(evt, id, wxID_ANY, fn)

#define wx__DECLARE_EVT0(evt, fn) \

wx__DECLARE_EVT1(evt, wxID_ANY, fn)



#define wxStaticCastEvent(type, val) wx_static_cast(type, val)

#define wx_static_cast(t, x) ((t)(x))

故:wxStaticCastEvent(wxHtmlExternalEventFunction, &func)等价((wxHtmlExternalEventFunction, )(&func)

*****************************************************************/

//声明自定义(wxHtmlExternalEvent)事件处理函数类型

typedef void (wxEvtHandler::*wxHtmlExternalEventFunction)(wxHtmlExternalEvent&);



#define wxHtmlExternalEventHandler(func) \

(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxHtmlExternalEventFunction, &func)



#define EVT_HTML_EXTERNAL(winid, func) wx__DECLARE_EVT1(wxEVT_HTML_EXTERNAL, winid, wxHtmlExternalEventHandler(func))



上面两条也可以合并为一条,类似如下:

#define EVT_HTML_EXTERNAL(winid, func) \

DECLARE_EVENT_TABLE_ENTRY( \

(wxEVT_HTML_EXTERNAL,winid, wxID_ANY, \

(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxHtmlExternalEventFunction, &func), \

(wxObject *) NULL ),

//wxStaticCastEvent为强制转换宏,当中wxStaticCastEvent(wxHtmlExternalEventFunction, &fn )进行静态类型强制转换,把指定的函数(fn)指针类型转换为事件处理函数类型,也可以(wxHtmlExternalEventFunction)(&fn)。

//如果DECLARE_EVENT_TABLE_ENTRY改为wx__DECLARE_EVT1,则可以省去wxID_ANY和(wxObject *) NULL两个参数;



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值