wxWidgets事件表是什么样的C++语句

What kind of C++ statement(s) is the wxWidgets event table?

本文关键字:C++ 语句 什么样 事件表 wxWidgets      更新时间:2023-10-16

我刚开始学习wxWidgets,我遇到了一组代码行,看起来像这样:

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
EVT_MENU(Minimal_About, MyFrame::OnAbout)
wxEND_EVENT_TABLE()

wxWidgets称之为"事件表"。我想知道这是什么样的语句,因为我已经学习了一些C++教程,但我还没有见过这样的东西。它们看起来像函数调用,但没有分号。我知道这与MACROS有关,但我真的不明白这是怎么回事。这种说法是MACROS的一种说法,还是我在C++中还没有遇到的一种通用说法?

  1. 你是对的。wxBEGIN_EVENT_TABLE是"宏"的一个例子:

  2. 那么什么是"宏"呢?这里有一个合理的定义:

https://gcc.gnu.org/onlinedocs/cpp/Macros.html

宏是被赋予名称的代码片段。无论何时使用名称时,它将被宏的内容所替换。那里是两种宏。他们的不同之处主要在于长相当它们被使用时。当使用时,类似函数的宏类似于函数调用。

  1. 在这种情况下,wxBEGIN_EVENT_TABLE与wxEND_EVENT_ABLE一起"扩展"到wx"事件处理程序"列表:

https://docs.wxwidgets.org/3.0/group__group__funcmacro__events.html#

#define wxBEGIN_EVENT_TABLE   (       theClass,
baseClass 
)       

在源文件中使用此宏可以开始列出静态事件处理程序针对特定类别。

使用wxEND_EVENT_ABLE()终止事件声明块。

  1. "宏"是在最早的汇编语言中引入的。他们只是做"文本替换"——修改实际编译器看到的源代码。

    宏(和宏预处理器)是原始"C"语言的一个组成部分,并被移植到C++(和许多其他高级语言)中。

    你可以在这里阅读更多关于C/C++宏的信息:

    https://www.programiz.com/c-programming/c-preprocessor-macros

'希望这能帮助

事件表通常是某种类型的struct,它包含事件消息标识符以及指向处理事件消息的函数的指针。

这种类型的数据结构在许多GUI框架中非常常用。例如,Microsoft MFC框架使用它。

事件表是实际的数据结构,不是C++编程语言的一部分。您可以使用C++来定义事件表。

使这种方法发挥作用所需的一些部分是:

  • 允许搜索消息标识符以找到其关联处理程序的表结构

  • 框架找到事件表的一种方法,以便使用它进行消息标识符查找,并使用正确的接口调用正确的函数

  • 一种知道事件表中第一个和最后一个条目的方法

手工编码的框架表元素的简单版本可能如下所示。这将是一个用于创建事件表元素数组的元素,每个事件消息标识符一个。

typedef struct {
int  msgId;   // the identifier for the message type
void (*handler)(int msgId, void *msgData);   // function pointer to handler
} SimpleEventTable;

在没有宏的源代码中使用这一点的一个不完整的例子如下。在本例中,MSG_ID_ONE和MSG_ID_TWO由int值定义,而handler1handler2是处理这些消息的函数:

void handler1 (int msgId, void *msgData)
{
// do things with the data associated with message identifier MSG_ID_ONE
}
void handler2 (int msgId, void *msgData)
{
// do things with the data associated with message identifier MSG_ID_TWO
}
SimpleEventTable myTable[] = {
{MSG_ID_ONE, handler1},
{MSG_ID_TWO, handler2},
{0, NULL}
};

然后,框架使用事件表来确定代码是否正在处理特定的消息标识符,以及应用程序是否正在处理消息标识符,调用什么函数来处理它。框架将提供一个默认的处理程序,在许多情况下,它只会指示消息已被处理。

大多数框架都希望更容易地完成相当于样板源代码的工作,因此会提供一组预处理器宏,使事件表更容易创建。

MFC的示例宏

我无法访问wxWidgets,但是Microsoft MFC框架提供了类似于wxWidget框架的东西,尽管MFC中填充的内容比窗口管理多得多。

使用MFC的事件表如下所示,它实际上与您正在使用的框架非常相似。此消息映射是MFC窗口类的实现文件的一部分。在这种情况下,应用程序类CFrameworkWndDoc是从MFC类CWindowDocument派生的,该MFC类是MFC框架的一部分。

BEGIN_MESSAGE_MAP(CFrameworkWndDoc, CWindowDocument)
ON_WM_CHAR()
ON_WM_TIMER()
ON_MESSAGE(WU_EVS_DFLT_LOAD, OnDefaultWinLoad)
ON_MESSAGE(WM_APP_SHOW_HIDE_GROUP, OnShowHideGroupMsgRcvd)
END_MESSAGE_MAP()

除了实现源文件.c文件中的上述消息映射外,类定义中还使用了DECLARE_MESSAGE_MAP()定义,通常位于头文件中,因此类和消息映射之间存在链接。

DECLARE_MESSAGE_MAP()宏只是将必要的声明放入类定义中,这些声明将实现文件中的实际消息映射与类联系起来。

#define DECLARE_MESSAGE_MAP() 
protected: 
static const AFX_MSGMAP* PASCAL GetThisMessageMap(); 
virtual const AFX_MSGMAP* GetMessageMap() const; 

MFC包含文件具有如下定义。首先是事件表的开始和结束的两个定义,或者MFC所称的消息映射。正如您所看到的,这将创建MFC类的一个新成员,该成员由MFC框架调用,以便在MFC框架处理消息时访问消息映射。class定义中的DECLARE_MESSAGE_MAP()宏声明由以下宏生成的函数。

#define BEGIN_MESSAGE_MAP(theClass, baseClass) 
PTM_WARNING_DISABLE 
const AFX_MSGMAP* theClass::GetMessageMap() const 
{ return GetThisMessageMap(); } 
const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() 
{ 
typedef theClass ThisClass;                        
typedef baseClass TheBaseClass;                    
static const AFX_MSGMAP_ENTRY _messageEntries[] =  
{
#define END_MESSAGE_MAP() 
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } 
}; 
static const AFX_MSGMAP messageMap = 
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; 
return &messageMap; 
}                                 
PTM_WARNING_RESTORE

还有许多宏用于简化事件表的构建。MFC使用的这些比上面的简单示例复杂得多,因为它们被设计为与MFC窗口类一起使用,并被插入到源代码文件中,并由Visual Studio开发环境管理。

还要注意,MFC消息映射技术使用一组特殊标识符AfxSig_vwwwAfxSig_lwl,它们分别"告诉"MFC框架处理程序函数的接口应该是什么,(UINT, UINT, UINT)(WPARAM, LPARAM)

#define ON_WM_CHAR() 
{ WM_CHAR, 0, 0, 0, AfxSig_vwww, 
(AFX_PMSG)(AFX_PMSGW) 
(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, UINT, UINT) > ( &ThisClass :: OnChar)) },
#define ON_MESSAGE(message, memberFxn) 
{ message, 0, 0, 0, AfxSig_lwl, 
(AFX_PMSG)(AFX_PMSGW) 
(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > 
(memberFxn)) },