C++GUI之wxWidgets(11)-编写应用涉及的类和方法(6)-事件处理(5)

文章介绍了wxWidgets框架中用于事件处理的关键函数,如wxPostEvent、wxQueueEvent、PopEventHandler、Bind、GetEventUserData、Connect和Unbind,以及如何自定义事件类。这些函数用于在GUI应用中发布、处理和管理事件,同时提到了动态事件绑定和解绑的方法。文章还强调了事件处理程序与虚拟方法之间的区别,并给出了使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义事件

wxPostEvent()

void wxPostEvent 	( 	wxEvtHandler *  	dest,
		const wxEvent &  	event 
	) 	

在GUI应用程序中,此函数使用wxEvtHandler::AddPendingEvent()将事件发布到指定的dest对象。

否则,它将使用wxEvtHandler::ProcessEvent()立即分派事件。有关详细信息(和注意事项),请参阅相应的文档。由于wxEvtHandler::AddPendingEvent()的限制,此函数对于具有wxString字段的事件对象不是线程安全的,请改用wxQueueEvent()。

#include <wx/event.h> 

wxQueueEvent()

void wxQueueEvent 	( 	wxEvtHandler *  	dest,
		wxEvent *  	event 
	) 	

将事件排入队列,以便对给定对象进行处理。

这是wxEvtHandler::QueueEvent()的包装器,有关详细信息,请参阅其文档。

包含文件:

#include <wx/event.h>

参数

dest要对事件进行排队的对象不能为NULL。

event分配给队列的堆和非NULL事件,函数将拥有它的所有权。

PopEventHandler()


wxEvtHandler* wxWindow::PopEventHandler 	( 	bool  	deleteHandler = false	) 	

删除并返回事件处理程序堆栈上最顶部的事件处理程序。

在以下情况下:

在这里插入图片描述

当调用W->PopEventHandler()时,事件处理程序A将被删除,而B将是堆栈的第一个处理程序。

请注意,当此窗口上没有推送事件处理程序时(即当窗口本身是其唯一的事件处理程序),调用此函数是错误的。

参数

deleteHandler如果这是真的,那么在移除处理程序之后,它将被删除(返回的值将为NULL)。

Bind()

 template<typename EventTag , typename Functor >
void wxEvtHandler::Bind 	( 	const EventTag &  	eventType,
		Functor  	functor,
		int  	id = wxID_ANY,
		int  	lastId = wxID_ANY,
		wxObject *  	userData = NULL 
	) 		

将给定函数、函子或方法与事件动态绑定。

这提供了与Connect()基本相同的功能,但它更灵活,因为它还允许您使用普通函数和任意函子作为事件处理程序。它也比Connect()限制更少,因为可以使用任意方法作为事件处理程序,而Connect()需要wxEvtHandler派生的处理程序。

有关此函数的详细说明,请参阅动态事件处理,有关用法示例,请参阅事件示例示例。

参数

eventType要与此事件处理程序关联的事件类型。

functor事件处理程序函子。这可以是一个普通函数,也可以是任意函子,如boost::function<>。

id要与事件处理程序关联的标识符范围的第一个id。

lastId要与事件处理程序关联的标识符范围的最后一个ID。

userData与事件表条目关联的可选数据。wxWidgets将拥有该指针的所有权,即当事件处理程序断开连接或程序终止时,该指针将被销毁。稍后可以使用wxEvent::GetEventUserData()检索此指针。

GetEventUserData()

wxObject* wxEvent::GetEventUserData 	( 		) 	const

返回与动态连接的事件处理程序关联的用户数据。

wxEvtHandler::Connect()和wxEvt handler::Bind()允许将可选的userData指针与处理程序关联,此方法返回此指针的值。

返回的指针由wxWidgets拥有,不能删除。

Connect()

void wxEvtHandler::Connect 	( 	int  	id,
		int  	lastId,
		wxEventType  	eventType,
		wxObjectEventFunction  	function,
		wxObject *  	userData = NULL,
		wxEvtHandler *  	eventSink = NULL 
	) 	

将给定函数、函子或方法与事件动态绑定。

这提供了与Connect()基本相同的功能,但它更灵活,因为它还允许您使用普通函数和任意函子作为事件处理程序。它也比Connect()限制更少,因为可以使用任意方法作为事件处理程序,而Connect()需要wxEvtHandler派生的处理程序。

有关此函数的详细说明,请参阅动态事件处理,有关用法示例,请参阅事件示例示例。

参数

eventType要与此事件处理程序关联的事件类型。

functor事件处理程序函子。这可以是一个普通函数,也可以是任意函子,如boost::function<>。

id要与事件处理程序关联的标识符范围的第一个id。

lastId要与事件处理程序关联的标识符范围的最后一个ID。

userData与事件表条目关联的可选数据。wxWidgets将拥有该指针的所有权,即当事件处理程序断开连接或程序终止时,该指针将被销毁。稍后可以使用wxEvent::GetEventUserData()检索此指针。

Unbind()

 template<typename EventTag , typename Functor >
bool wxEvtHandler::Unbind 	( 	const EventTag &  	eventType,
		Functor  	functor,
		int  	id = wxID_ANY,
		int  	lastId = wxID_ANY,
		wxObject *  	userData = NULL 
	) 	

使用指定的参数作为搜索条件,从事件处理程序中动态取消绑定给定的函数、函子或方法,如果找到并删除了匹配的函数,则返回true。

此方法只能解除绑定使用Bind<>()方法添加的函数、函子或方法。无法解除绑定使用(静态)事件表绑定的函数。

目前,函子是通过它们的地址进行比较的,不幸的是,如果相同的地址被重复用于两个不同的函子对象,则无法正常工作。因此,如果有多个函子使用相同的eventType和id以及lastId,则不建议使用Unbind()。

参数

eventType与此事件处理程序关联的事件类型。

functor事件处理程序函子。这可以是一个普通函数,也可以是任意函子,如boost::function<>。

id与事件处理程序关联的标识符范围的第一个id。

lastId与事件处理程序关联的标识符范围的最后一个ID。

userData与事件表条目关联的数据。

定义自己的事件类

在某些情况下,您必须定义自己的事件类,例如,将更复杂的数据从一个地方发送到另一个地方。除了定义事件类之外,如果仍然需要使用事件表(现在被认为是遗留的)来处理此类事件,还需要定义自己的事件表宏。有关新wxEvent派生类的完整工作实现,请参阅事件示例中的ChessBoardEvent。

下面是一个简单的例子:

// create a new event class derived from wxEvent
class MyPlotEvent: public wxEvent
{
public:
    MyPlotEvent(wxEventType eventType, int winid, const wxPoint& pos)
        : wxEvent(winid, eventType),
          m_pos(pos)
    {
    }
 
    // accessors
    wxPoint GetPoint() const { return m_pos; }
 
    // implement the base class pure virtual
    virtual wxEvent *Clone() const { return new MyPlotEvent(*this); }
 
private:
    const wxPoint m_pos;
};
 
// We use a single myEVT_PLOT_CLICKED event type associated with the class
// above but often you are going to have more than one event type, e.g. you
// could also have myEVT_PLOT_ZOOMED or myEVT_PLOT_PANNED etc. -- in which case
// you would just add more similar lines here.
//
// Note that this macro, as all declarations, should be in the header, and
// there should be a matching definition macro in some source file (see
// wxDEFINE_EVENT below).
wxDECLARE_EVENT(myEVT_PLOT_CLICKED, MyPlotEvent);
 
 
// --- Skip this part if you're only going to use Bind() (as recommended) ---
 
// The following typedef and macro are needed only when the new event class
// still needs to be used with the legacy approach to handling events - event
// table macros or Connect() - to cast the type of a function handling it to
// the type expected by the legacy event handling machinery.
typedef void (wxEvtHandler::*MyPlotEventFunction)(MyPlotEvent&);
#define MyPlotEventHandler(func) wxEVENT_HANDLER_CAST(MyPlotEventFunction, func)
 
// If the new event is to be used with event tables, a macro for creating
// event table entries for the new event type must be defined.
#define EVT_PLOT_CLICKED(id, func) \
    wx__DECLARE_EVT1(myEVT_PLOT_CLICKED, id, MyPlotEventHandler(func))
 
// --- End of the part which is only relevant when using event tables ---
 
 
// Up until now, we only had declarations that would typically appear in a
// header file. Starting from now we have the definitions, which must occur
// only once in the program and so need to be in a source file.
 
// This defines the event type declared above. If you use multiple event types,
// you need to do it for each of them.
wxDEFINE_EVENT(myEVT_PLOT_CLICKED, MyPlotEvent);
 
// example of code handling the event (you will use one of these methods,
// not both, of course):
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_PLOT_CLICKED(ID_MY_WINDOW, MyFrame::OnPlot)
wxEND_EVENT_TABLE()
 
MyFrame::MyFrame()
{
    Bind(myEVT_PLOT_CLICKED, &MyFrame::OnPlot, this, ID_MY_WINDOW);
}
 
void MyFrame::OnPlot(MyPlotEvent& event)
{
    ... do something with event.GetPoint() ...
}
 
 
// example of code generating the event:
void MyWindow::SendEvent()
{
    MyPlotEvent event(myEVT_PLOT_CLICKED, GetId(), wxPoint(...));
    event.SetEventObject(this);
    ProcessWindowEvent(event);
}

事件处理程序与虚拟方法

可能需要注意的是,wxWidgets的事件处理系统在精神上实现了类似于普通C++中的虚拟方法:这两种机制都允许您通过在派生类中定义事件处理函数来改变基类的行为。

然而,当您想要从派生类处理程序调用基类实现的默认行为时,这两种机制之间有一个重要的区别。对于虚拟函数,您需要直接调用基类函数,您可以在派生类处理程序函数的开头(后处理事件)或结尾(预处理事件)执行该操作。使用事件处理程序,您只能选择预处理事件,为了仍然让默认行为发生,您必须调用wxEvent::Skip(),而不是直接调用基类事件处理程序。事实上,事件处理程序可能甚至不存在于基类中,因为默认行为通常由底层工具包或操作系统本身在特定于平台的代码中实现。但即使它确实存在于wxWidgets级别,也不应该直接调用它,因为事件处理程序不是wxWidget API的一部分,也不应直接调用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值