Tag: is the Connect widget Comm cal specified static public hash
Directory
- Message map Table
- Static message map table
- Static message mapping Table processing procedure
- Dynamic Message map Table
- Process of dynamic message map table processing
Message map Table
The message is the core of the GUI program, and all the operational behavior is communicated through the message.
Static message map table
Use static eventtable to bind the event number to the processing code, using the example:
// 声明class debugWXFrame: public wxFrame{ DECLARE_EVENT_TABLE()};// 实现BEGIN_EVENT_TABLE(debugWXFrame,wxFrame) EVT_MENU(ID_MenuUser, debugWXFrame::OnCheckMenu)END_EVENT_TABLE()
Look at the definition first wxDECLARE_EVENT_TABLE
to declare some data in the current class, mostly static data, and provide GetEventTable
access to the table;
#define DECLARE_EVENT_TABLE() wxDECLARE_EVENT_TABLE();#define wxDECLARE_EVENT_TABLE() private: static const wxEventTableEntry sm_eventTableEntries[]; protected: static const wxEventTable sm_eventTable; virtual const wxEventTable* GetEventTable() const; static wxEventHashTable sm_eventHashTable; virtual wxEventHashTable& GetEventHashTable() const
The following is an implementation that initializes these static variables, and all message definitions are located wxBEGIN_EVENT_TABLE
and END_EVENT_TABLE
between:
sm_eventTableEntries
Save the message map table, which is the message ID and message processing function relationship;
- The implementation method is used by the
GetEventTable
caller;
sm_eventHashTable
For saving Hashtable, the lookup rate will increase;
#define BEGIN_EVENT_TABLE(a,b) wxBEGIN_EVENT_TABLE(a,b)#define END_EVENT_TABLE() wxEND_EVENT_TABLE()#define wxBEGIN_EVENT_TABLE(theClass, baseClass) const wxEventTable theClass::sm_eventTable = { &baseClass::sm_eventTable, &theClass::sm_eventTableEntries[0] }; const wxEventTable *theClass::GetEventTable() const { return &theClass::sm_eventTable; } wxEventHashTable theClass::sm_eventHashTable(theClass::sm_eventTable); wxEventHashTable &theClass::GetEventHashTable() const { return theClass::sm_eventHashTable; } const wxEventTableEntry theClass::sm_eventTableEntries[] = { #define wxEND_EVENT_TABLE() wxDECLARE_EVENT_TABLE_TERMINATOR() };
In wxBEGIN_EVENT_TABLE
and END_EVENT_TABLE
between is the message processing item, for example EVT_MENU(ID_MenuUser, debugWXFrame::OnCheckMenu)
, above is an item, we can expand this:
// 用户使用这个宏来定义事件映射#define EVT_MENU(winid, func) wx__DECLARE_EVT1(wxEVT_MENU, winid, wxCommandEventHandler(func))// 事件映射内部宏#define wx__DECLARE_EVT2(evt, id1, id2, fn) wxDECLARE_EVENT_TABLE_ENTRY(evt, id1, id2, fn, NULL),#define wx__DECLARE_EVT1(evt, id, fn) wx__DECLARE_EVT2(evt, id, wxID_ANY, fn)// 根据传递进来的参数创建一个wxEventTableEntry对象#define wxDECLARE_EVENT_TABLE_ENTRY(type, winid, idLast, fn, obj) wxEventTableEntry(type, winid, idLast, wxNewEventTableFunctor(type, fn), obj)
Then the EVT_MENU(ID_MenuUser, debugWXFrame::OnCheckMenu)
expansion is followed by:
wxEventTableEntry(wxEVT_MENU, winid, wxID_ANY, wxNewEventTableFunctor(wxEVT_MENU, wxCommandEventHandler(fn)), NULL)
wxNewEventTableFunctor
Used to instantiate an wxObjectEventFunctor
object wxCommandEventHandler
for use in a strongly-forwarded message processing function wxNewEventTableFunctor
.
#define wxCommandEventHandler(func) wxEVENT_HANDLER_CAST(wxCommandEventFunction, func)#define wxEVENT_HANDLER_CAST( functype, func ) ( wxObjectEventFunction )( wxEventFunction )wxStaticCastEvent( functype, &func )inline wxObjectEventFunctor *wxNewEventTableFunctor(const wxEventType& WXUNUSED(evtType), wxObjectEventFunction method){ return new wxObjectEventFunctor(method, NULL);}
This allows you to statically create multiple wxEventTableEntry
objects and add them to the sm_eventTableEntries
.
Static message mapping Table processing procedure
The message processing process wxEvtHandler::TryHereOnly
calls the static table query processing:
bool wxEvtHandler::TryHereOnly(wxEvent& event){ // Then static per-class event tables if ( GetEventHashTable().HandleEvent(event, this) ) return true;}
The GetEventHashTable
method above returns an wxEventHashTable
object and then invokes the object's HandleEvent
method:
wxEventHashTable
The table is segmented according to the message type, so that you can quickly find the table of the specified type;
- Iterates over a table of the specified type, for each
wxEventTableEntry
callProcessEventIfMatchesId
bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self){ // Find all entries for the given event type. wxEventType eventType = event.GetEventType(); const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size]; if (eTTnode && eTTnode->eventType == eventType) { const wxEventTableEntryPointerArray& eventEntryTable = eTTnode->eventEntryTable; const size_t count = eventEntryTable.GetCount(); for (size_t n = 0; n < count; n++) { const wxEventTableEntry& entry = *eventEntryTable[n]; if ( wxEvtHandler::ProcessEventIfMatchesId(entry, self, event) ) return true; } } return false;}
wxEvtHandler::ProcessEventIfMatchesId
The processing flow is as follows:
- Checks whether the currently received message matches this item
wxEventTableEntryBase
- Call the user's handler function
m_fn
execution, here m_fn
is also after several layers of encapsulation, interested in continuing to follow.
bool wxEvtHandler::ProcessEventIfMatchesId(const wxEventTableEntryBase& entry, wxEvtHandler *handler, wxEvent& event){ int tableId1 = entry.m_id, tableId2 = entry.m_lastId; // match only if the event type is the same and the id is either -1 in // the event table (meaning "any") or the event id matches the id // specified in the event table either exactly or by falling into // range between first and last if ((tableId1 == wxID_ANY) || (tableId2 == wxID_ANY && tableId1 == event.GetId()) || (tableId2 != wxID_ANY && (event.GetId() >= tableId1 && event.GetId() <= tableId2))) { event.Skip(false); event.m_callbackUserData = entry.m_callbackUserData; (*entry.m_fn)(handler, event); if (!event.GetSkipped()) return true; } return false;}
Dynamic Message map Table
The addition and deletion of dynamic mapping table entries is carried out wxEvtHandler::DoBind
and wxEvtHandler::DoUnbind
executed, and Wxwidgets provides a variety of interfaces to perform this operation.
It is important to note that if the object is passed in wxEvtHandler
, it is processed by invoking the user-specified wxEvtHandler
object for processing, and if not specified, it is processed directly using the current wxEvtHandler
object.
There are interfaces that provide similar functionality, but they are Connect
Connect
more complex to use, and it is recommended that all subsequent code be used Bind接口
, not to repeat them here.
Bind
An interface is a template function that provides three types of interfaces:
- Directly bind the global function, at this time only the event type and function parameters must be, recommended to use ;
- Binding Funtor function, users need to use their own
wxNewEventFunctor
encapsulation, not recommended ;
- The use of Class intrinsics, as well as the need to specify a class pointer, is recommended .
Three types of interfaces are declared as follows:
template <typename EventTag, typename EventArg>void Bind(const EventTag& eventType, void (*function)(EventArg &), int winid = wxID_ANY, int lastId = wxID_ANY, wxObject *userData = NULL) template <typename EventTag, typename Functor>void Bind(const EventTag& eventType, const Functor &functor, int winid = wxID_ANY, int lastId = wxID_ANY, wxObject *userData = NULL) template <typename EventTag, typename Class, typename EventArg, typename EventHandler>void Bind(const EventTag &eventType, void (Class::*method)(EventArg &), EventHandler *handler, int winid = wxID_ANY, int lastId = wxID_ANY, wxObject *userData = NULL)
Process of dynamic message map table processing
Same as static message entry, when wxEvtHandler::TryHereOnly
getting called:
bool wxEvtHandler::TryHereOnly(wxEvent& event){ // Handle per-instance dynamic event tables first if ( m_dynamicEvents && SearchDynamicEventTable(event) ) return true;}
Dynamic table lookup is relatively simple, the dynamic message table exists in the list m_dynamicEvents
, as long as the list of every item out of the chain ProcessEventIfMatchesId
to call on it.
bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event ){ wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); while (node) { wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); node = node->GetNext(); if ( event.GetEventType() == entry->m_eventType ) { wxEvtHandler *handler = entry->m_fn->GetEvtHandler(); if ( !handler ) handler = this; if ( ProcessEventIfMatchesId(*entry, handler, event) ) return true; } } return false;}
Wxwidgets Source Analysis (3)-Message mapping table