fix wxWindow::PushEventHandler and related wxWindow functions for the stack management; currently they don't work well when passing event handlers which are part of an event handler chain (see wx-dev thread 'wxWindow event handler stack'); implement wxEvtHandler Unlink() and IsUnlinked() functions and document them; revise docs of all involved functions of both wxEvtHandler and wxWindow, adding images for better explanations
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58291 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
47009083ce
commit
7f853dd046
BIN
docs/doxygen/images/evthandler_unlink_after.dia
Normal file
BIN
docs/doxygen/images/evthandler_unlink_after.dia
Normal file
Binary file not shown.
BIN
docs/doxygen/images/evthandler_unlink_after.png
Normal file
BIN
docs/doxygen/images/evthandler_unlink_after.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
docs/doxygen/images/evthandler_unlink_before.dia
Normal file
BIN
docs/doxygen/images/evthandler_unlink_before.dia
Normal file
Binary file not shown.
BIN
docs/doxygen/images/evthandler_unlink_before.png
Normal file
BIN
docs/doxygen/images/evthandler_unlink_before.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
docs/doxygen/images/overview_eventhandling_chain.dia
Normal file
BIN
docs/doxygen/images/overview_eventhandling_chain.dia
Normal file
Binary file not shown.
BIN
docs/doxygen/images/overview_eventhandling_chain.png
Normal file
BIN
docs/doxygen/images/overview_eventhandling_chain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
docs/doxygen/images/overview_eventhandling_winstack.dia
Normal file
BIN
docs/doxygen/images/overview_eventhandling_winstack.dia
Normal file
Binary file not shown.
BIN
docs/doxygen/images/overview_eventhandling_winstack.png
Normal file
BIN
docs/doxygen/images/overview_eventhandling_winstack.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
@ -184,7 +184,7 @@ in the previous section. However the similarities end here and both the syntax
|
||||
and the possibilities of handling events in this way are rather different.
|
||||
|
||||
Let us start by looking at the syntax: the first obvious difference is that you
|
||||
need not use @c DECLARE_EVENT_TABLE() nor @c BEGIN_EVENT_TABLE and the
|
||||
need not use DECLARE_EVENT_TABLE() nor BEGIN_EVENT_TABLE() and the
|
||||
associated macros. Instead, in any place in your code, but usually in
|
||||
the code of the class defining the handler itself (and definitely not in the
|
||||
global scope as with the event tables), call its Connect() method like this:
|
||||
@ -331,10 +331,20 @@ doesn't count as having handled the event and the search continues):
|
||||
<li value="5">
|
||||
The event is passed to the next event handler, if any, in the event handler
|
||||
chain, i.e., the steps (1) to (4) are done for it. This chain can be formed
|
||||
using wxEvtHandler::SetNextHandler() or wxWindow::PushEventHandler() but
|
||||
usually there is no next event handler and chaining event handlers using
|
||||
these functions is much less useful now that Connect() exists so this step
|
||||
will almost never do anything.
|
||||
using wxEvtHandler::SetNextHandler():
|
||||
@image html overview_eventhandling_chain.png
|
||||
(referring to the image, if @c A->ProcessEvent is called and it doesn't handle
|
||||
the event, @c B->ProcessEvent will be called and so on...).
|
||||
In the case of wxWindow you can build a stack (implemented using wxEvtHandler
|
||||
double-linked list) using wxWindow::PushEventHandler():
|
||||
@image html overview_eventhandling_winstack.png
|
||||
(referring to the image, if @c W->ProcessEvent is called, it immediately calls
|
||||
@c A->ProcessEvent; if nor @c A nor @c B handle the event, then the wxWindow
|
||||
itself is used - i.e. the dynamically connected event handlers and static
|
||||
event table entries of wxWindow are looked as the last possibility, after
|
||||
all pushed event handlers were tested).
|
||||
Note however that usually there are no wxEvtHandler chains nor wxWindows stacks
|
||||
so this step will usually do anything.
|
||||
</li>
|
||||
|
||||
<li value="6">
|
||||
@ -349,7 +359,7 @@ doesn't count as having handled the event and the search continues):
|
||||
|
||||
<li value="7">
|
||||
Finally, i.e., if the event is still not processed, the wxApp object itself
|
||||
gets a last chance to process it.
|
||||
(which derives from wxEvtHandler) gets a last chance to process it.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
|
@ -283,7 +283,7 @@ HR {
|
||||
}
|
||||
|
||||
.memproto, .memdoc {
|
||||
border: 1px solid #84b0c7;
|
||||
border: 1px solid #84b0c7;
|
||||
}
|
||||
|
||||
.memproto {
|
||||
@ -400,6 +400,10 @@ H2 > A.anchor {
|
||||
color: black;
|
||||
}
|
||||
|
||||
IMG {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
IMG.logo {
|
||||
float: right;
|
||||
margin: 20px;
|
||||
|
@ -2668,14 +2668,27 @@ public:
|
||||
wxEvtHandler();
|
||||
virtual ~wxEvtHandler();
|
||||
|
||||
|
||||
// Event handler chain
|
||||
// -------------------
|
||||
|
||||
wxEvtHandler *GetNextHandler() const { return m_nextHandler; }
|
||||
wxEvtHandler *GetPreviousHandler() const { return m_previousHandler; }
|
||||
void SetNextHandler(wxEvtHandler *handler) { m_nextHandler = handler; }
|
||||
void SetPreviousHandler(wxEvtHandler *handler) { m_previousHandler = handler; }
|
||||
virtual void SetNextHandler(wxEvtHandler *handler) { m_nextHandler = handler; }
|
||||
virtual void SetPreviousHandler(wxEvtHandler *handler) { m_previousHandler = handler; }
|
||||
|
||||
void SetEvtHandlerEnabled(bool enabled) { m_enabled = enabled; }
|
||||
bool GetEvtHandlerEnabled() const { return m_enabled; }
|
||||
|
||||
void Unlink();
|
||||
bool IsUnlinked() const;
|
||||
|
||||
|
||||
|
||||
// Event queuing and processing
|
||||
// ----------------------------
|
||||
|
||||
|
||||
// Process an event right now: this can only be called from the main
|
||||
// thread, use QueueEvent() for scheduling the events for
|
||||
// processing from other threads.
|
||||
@ -2686,6 +2699,7 @@ public:
|
||||
// when called from C code (e.g. in GTK+ callback) when the exception
|
||||
// wouldn't correctly propagate to wxEventLoop.
|
||||
bool SafelyProcessEvent(wxEvent& event);
|
||||
// NOTE: uses ProcessEvent()
|
||||
|
||||
// Schedule the given event to be processed later. It takes ownership of
|
||||
// the event pointer, i.e. it will be deleted later. This is safe to call
|
||||
@ -2708,11 +2722,17 @@ public:
|
||||
}
|
||||
|
||||
void ProcessPendingEvents();
|
||||
// NOTE: uses ProcessEvent()
|
||||
|
||||
#if wxUSE_THREADS
|
||||
bool ProcessThreadEvent(const wxEvent& event);
|
||||
// NOTE: uses AddPendingEvent()
|
||||
#endif
|
||||
|
||||
|
||||
// Connecting and disconnecting
|
||||
// ----------------------------
|
||||
|
||||
// Dynamic association of a member function handler with the event handler,
|
||||
// winid and event type
|
||||
void Connect(int winid,
|
||||
|
@ -792,7 +792,7 @@ public:
|
||||
|
||||
// replace the event handler (allows to completely subclass the
|
||||
// window)
|
||||
void SetEventHandler( wxEvtHandler *handler ) { m_eventHandler = handler; }
|
||||
void SetEventHandler( wxEvtHandler *handler );
|
||||
|
||||
// push/pop event handler: allows to chain a custom event handler to
|
||||
// alreasy existing ones
|
||||
@ -806,13 +806,17 @@ public:
|
||||
// be there)
|
||||
bool RemoveEventHandler(wxEvtHandler *handler);
|
||||
|
||||
// Process an event by calling GetEventHandler()->ProcessEvent() and
|
||||
// handling any exceptions thrown by event handlers. It's mostly useful
|
||||
// when processing wx events when called from C code (e.g. in GTK+
|
||||
// callback) when the exception wouldn't correctly propagate to
|
||||
// wxEventLoop.
|
||||
// Process an event by calling GetEventHandler()->ProcessEvent() and
|
||||
// handling any exceptions thrown by event handlers. It's mostly useful
|
||||
// when processing wx events when called from C code (e.g. in GTK+
|
||||
// callback) when the exception wouldn't correctly propagate to
|
||||
// wxEventLoop.
|
||||
bool HandleWindowEvent(wxEvent& event) const;
|
||||
|
||||
// disable wxEvtHandler double-linked list mechanism:
|
||||
virtual void SetNextHandler(wxEvtHandler *handler);
|
||||
virtual void SetPreviousHandler(wxEvtHandler *handler);
|
||||
|
||||
// validators
|
||||
// ----------
|
||||
|
||||
|
@ -258,7 +258,7 @@ public:
|
||||
wxWindow is (and therefore all window classes are) derived from this class.
|
||||
|
||||
When events are received, wxEvtHandler invokes the method listed in the
|
||||
event table using itself as the object. When using multiple inheritance
|
||||
event table using itself as the object. When using multiple inheritance
|
||||
<b>it is imperative that the wxEvtHandler(-derived) class is the first
|
||||
class inherited</b> such that the @c this pointer for the overall object
|
||||
will be identical to the @c this pointer of the wxEvtHandler portion.
|
||||
@ -279,8 +279,8 @@ public:
|
||||
/**
|
||||
Destructor.
|
||||
|
||||
If the handler is part of a chain, the destructor will unlink itself and
|
||||
restore the previous and next handlers so that they point to each other.
|
||||
If the handler is part of a chain, the destructor will unlink itself
|
||||
(see Unlink()).
|
||||
*/
|
||||
virtual ~wxEvtHandler();
|
||||
|
||||
@ -382,17 +382,23 @@ public:
|
||||
|
||||
The normal order of event table searching is as follows:
|
||||
-# If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled)
|
||||
the function skips to step (6).
|
||||
the function skips to step (6).
|
||||
-# If the object is a wxWindow, ProcessEvent() is recursively called on the
|
||||
window's wxValidator. If this returns @true, the function exits.
|
||||
window's wxValidator. If this returns @true, the function exits.
|
||||
-# SearchEventTable() is called for this event handler. If this fails, the base
|
||||
class table is tried, and so on until no more tables exist or an appropriate
|
||||
function was found, in which case the function exits.
|
||||
class table is tried, and so on until no more tables exist or an appropriate
|
||||
function was found, in which case the function exits.
|
||||
-# The search is applied down the entire chain of event handlers (usually the
|
||||
chain has a length of one). If this succeeds, the function exits.
|
||||
chain has a length of one). This chain can be formed using wxEvtHandler::SetNextHandler():
|
||||
@image html overview_eventhandling_chain.png
|
||||
(referring to the image, if @c A->ProcessEvent is called and it doesn't handle
|
||||
the event, @c B->ProcessEvent will be called and so on...).
|
||||
Note that in the case of wxWindow you can build a stack of event handlers
|
||||
(see wxWindow::PushEventHandler() for more info).
|
||||
If any of the handlers of the chain return @true, the function exits.
|
||||
-# If the object is a wxWindow and the event is a wxCommandEvent, ProcessEvent()
|
||||
is recursively applied to the parent window's event handler.
|
||||
If this returns true, the function exits.
|
||||
is recursively applied to the parent window's event handler.
|
||||
If this returns @true, the function exits.
|
||||
-# Finally, ProcessEvent() is called on the wxApp object.
|
||||
|
||||
@param event
|
||||
@ -620,7 +626,10 @@ public:
|
||||
|
||||
|
||||
/**
|
||||
@name Event handler chain
|
||||
@name Event handler chaining
|
||||
|
||||
wxEvtHandler can be arranged in a double-linked list of handlers
|
||||
which is automatically iterated by ProcessEvent() if needed.
|
||||
*/
|
||||
//@{
|
||||
|
||||
@ -664,21 +673,60 @@ public:
|
||||
/**
|
||||
Sets the pointer to the next handler.
|
||||
|
||||
@param handler
|
||||
Event handler to be set as the next handler.
|
||||
@remarks
|
||||
See ProcessEvent() for more info about how the chains of event handlers
|
||||
are internally used.
|
||||
Also remember that wxEvtHandler uses double-linked lists and thus if you
|
||||
use this function, you should also call SetPreviousHandler() on the
|
||||
argument passed to this function:
|
||||
@code
|
||||
handlerA->SetNextHandler(handlerB);
|
||||
handlerB->SetPreviousHandler(handlerA);
|
||||
@endcode
|
||||
|
||||
@see GetNextHandler(), SetPreviousHandler(), GetPreviousHandler(),
|
||||
wxWindow::PushEventHandler, wxWindow::PopEventHandler
|
||||
@param handler
|
||||
The event handler to be set as the next handler.
|
||||
Cannot be @NULL.
|
||||
|
||||
@see @ref overview_eventhandling_processing
|
||||
*/
|
||||
void SetNextHandler(wxEvtHandler* handler);
|
||||
virtual void SetNextHandler(wxEvtHandler* handler);
|
||||
|
||||
/**
|
||||
Sets the pointer to the previous handler.
|
||||
All remarks about SetNextHandler() apply to this function as well.
|
||||
|
||||
@param handler
|
||||
Event handler to be set as the previous handler.
|
||||
The event handler to be set as the previous handler.
|
||||
Cannot be @NULL.
|
||||
|
||||
@see @ref overview_eventhandling_processing
|
||||
*/
|
||||
void SetPreviousHandler(wxEvtHandler* handler);
|
||||
virtual void SetPreviousHandler(wxEvtHandler* handler);
|
||||
|
||||
/**
|
||||
Unlinks this event handler from the chain it's part of (if any);
|
||||
then links the "previous" event handler to the "next" one
|
||||
(so that the chain won't be interrupted).
|
||||
|
||||
E.g. if before calling Unlink() you have the following chain:
|
||||
@image html evthandler_unlink_before.png
|
||||
then after calling @c B->Unlink() you'll have:
|
||||
@image html evthandler_unlink_after.png
|
||||
|
||||
@since 2.9.0
|
||||
*/
|
||||
void Unlink();
|
||||
|
||||
/**
|
||||
Returns @true if the next and the previous handler pointers of this
|
||||
event handler instance are @NULL.
|
||||
|
||||
@since 2.9.0
|
||||
|
||||
@see SetPreviousHandler(), SetNextHandler()
|
||||
*/
|
||||
bool IsUnlinked() const;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
@ -1656,6 +1656,9 @@ public:
|
||||
|
||||
/**
|
||||
@name Event-handling functions
|
||||
|
||||
wxWindow allows you to build a (sort of) stack of event handlers which
|
||||
can be used to override the window's own event handling.
|
||||
*/
|
||||
//@{
|
||||
|
||||
@ -1669,9 +1672,8 @@ public:
|
||||
wxEvtHandler* GetEventHandler() const;
|
||||
|
||||
/**
|
||||
This function will generate the appropriate call to
|
||||
Navigate() if the key event is one normally used for
|
||||
keyboard navigation and return @true in this case.
|
||||
This function will generate the appropriate call to Navigate() if the key
|
||||
event is one normally used for keyboard navigation and return @true in this case.
|
||||
|
||||
@return Returns @true if the key pressed was for navigation and was
|
||||
handled, @false otherwise.
|
||||
@ -1691,44 +1693,62 @@ public:
|
||||
/**
|
||||
Removes and returns the top-most event handler on the event handler stack.
|
||||
|
||||
@param deleteHandler
|
||||
If this is @true, the handler will be deleted after it is removed.
|
||||
The default value is @false.
|
||||
E.g. in the case of:
|
||||
@image html overview_eventhandling_winstack.png
|
||||
when calling @c W->PopEventHandler(), the event handler @c A will be
|
||||
removed and @c B will be the first handler of the stack.
|
||||
|
||||
@see SetEventHandler(), GetEventHandler(),
|
||||
PushEventHandler(), wxEvtHandler::ProcessEvent, wxEvtHandler
|
||||
Note that it's an error to call this function when no event handlers
|
||||
were pushed on this window (i.e. when the window itself is its only
|
||||
event handler).
|
||||
|
||||
@param deleteHandler
|
||||
If this is @true, the handler will be deleted after it is removed
|
||||
(and the returned value will be @NULL).
|
||||
|
||||
@see @ref overview_eventhandling_processing
|
||||
*/
|
||||
wxEvtHandler* PopEventHandler(bool deleteHandler = false);
|
||||
|
||||
/**
|
||||
Pushes this event handler onto the event stack for the window.
|
||||
|
||||
An event handler is an object that is capable of processing the events sent
|
||||
to a window. By default, the window is its own event handler, but an application
|
||||
may wish to substitute another, for example to allow central implementation
|
||||
of event-handling for a variety of different window classes.
|
||||
|
||||
wxWindow::PushEventHandler allows an application to set up a @e stack
|
||||
of event handlers, where an event not handled by one event handler is
|
||||
handed to the next one in the chain.
|
||||
|
||||
E.g. if you have two event handlers @c A and @c B and a wxWindow instance
|
||||
@c W and you call:
|
||||
@code
|
||||
W->PushEventHandler(A);
|
||||
W->PushEventHandler(B);
|
||||
@endcode
|
||||
you will end up with the following situation:
|
||||
@image html overview_eventhandling_winstack.png
|
||||
|
||||
Note that you can use wxWindow::PopEventHandler to remove the event handler.
|
||||
|
||||
@param handler
|
||||
Specifies the handler to be pushed.
|
||||
It must not be part of a wxEvtHandler chain; an assert will fail
|
||||
if it's not unlinked (see wxEvtHandler::IsUnlinked).
|
||||
|
||||
@remarks An event handler is an object that is capable of processing the
|
||||
events sent to a window. By default, the window is its
|
||||
own event handler, but an application may wish to
|
||||
substitute another, for example to allow central
|
||||
implementation of event-handling for a variety of
|
||||
different window classes.
|
||||
wxWindow::PushEventHandler allows an application to set up a
|
||||
chain of event handlers, where an event not handled by one event
|
||||
handler is handed to the next one in the chain.
|
||||
Use wxWindow::PopEventHandler to remove the event handler.
|
||||
|
||||
@see SetEventHandler(), GetEventHandler(),
|
||||
PopEventHandler(), wxEvtHandler::ProcessEvent, wxEvtHandler
|
||||
@see @ref overview_eventhandling_processing
|
||||
*/
|
||||
void PushEventHandler(wxEvtHandler* handler);
|
||||
|
||||
/**
|
||||
Find the given @a handler in the windows event handler chain and remove
|
||||
(but not delete) it from it.
|
||||
Find the given @a handler in the windows event handler stack and unlinks
|
||||
(but not delete) it. See wxEvtHandler::Unlink() for more info.
|
||||
|
||||
@param handler
|
||||
The event handler to remove, must be non-@NULL and
|
||||
must be present in this windows event handlers chain
|
||||
must be present in this windows event handlers stack.
|
||||
|
||||
@return Returns @true if it was found and @false otherwise (this also
|
||||
results in an assert failure so this function should
|
||||
@ -1741,27 +1761,41 @@ public:
|
||||
/**
|
||||
Sets the event handler for this window.
|
||||
|
||||
Note that if you use this function you may want to use as the "next" handler
|
||||
of @a handler the window itself; in this way when @a handler doesn't process
|
||||
an event, the window itself will have a chance to do it.
|
||||
|
||||
@param handler
|
||||
Specifies the handler to be set.
|
||||
Specifies the handler to be set. Cannot be @NULL.
|
||||
|
||||
@remarks An event handler is an object that is capable of processing the
|
||||
events sent to a window. By default, the window is its
|
||||
own event handler, but an application may wish to
|
||||
substitute another, for example to allow central
|
||||
implementation of event-handling for a variety of
|
||||
different window classes.
|
||||
It is usually better to use wxWindow::PushEventHandler since
|
||||
this sets up a chain of event handlers, where an event not
|
||||
handled by one event handler is handed to the next one in the chain.
|
||||
|
||||
@see GetEventHandler(), PushEventHandler(),
|
||||
PopEventHandler(), wxEvtHandler::ProcessEvent, wxEvtHandler
|
||||
@see @ref overview_eventhandling_processing
|
||||
*/
|
||||
void SetEventHandler(wxEvtHandler* handler);
|
||||
|
||||
/**
|
||||
wxWindows cannot be used to form event handler chains; this function
|
||||
thus will assert when called.
|
||||
|
||||
Note that instead you can use PushEventHandler() or SetEventHandler() to
|
||||
implement a stack of event handlers to override wxWindow's own
|
||||
event handling mechanism.
|
||||
*/
|
||||
virtual void SetNextHandler(wxEvtHandler* handler);
|
||||
|
||||
/**
|
||||
wxWindows cannot be used to form event handler chains; this function
|
||||
thus will assert when called.
|
||||
|
||||
Note that instead you can use PushEventHandler() or SetEventHandler() to
|
||||
implement a stack of event handlers to override wxWindow's own
|
||||
event handling mechanism.
|
||||
*/
|
||||
virtual void SetPreviousHandler(wxEvtHandler* handler);
|
||||
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@name Window styles functions
|
||||
*/
|
||||
|
@ -1036,12 +1036,7 @@ wxEvtHandler::wxEvtHandler()
|
||||
|
||||
wxEvtHandler::~wxEvtHandler()
|
||||
{
|
||||
// Takes itself out of the list of handlers
|
||||
if (m_previousHandler)
|
||||
m_previousHandler->m_nextHandler = m_nextHandler;
|
||||
|
||||
if (m_nextHandler)
|
||||
m_nextHandler->m_previousHandler = m_previousHandler;
|
||||
Unlink();
|
||||
|
||||
if (m_dynamicEvents)
|
||||
{
|
||||
@ -1103,6 +1098,26 @@ wxEvtHandler::~wxEvtHandler()
|
||||
delete m_clientObject;
|
||||
}
|
||||
|
||||
void wxEvtHandler::Unlink()
|
||||
{
|
||||
// this event handler must take itself out of the chain of handlers:
|
||||
|
||||
if (m_previousHandler)
|
||||
m_previousHandler->SetNextHandler(m_nextHandler);
|
||||
|
||||
if (m_nextHandler)
|
||||
m_nextHandler->SetPreviousHandler(m_previousHandler);
|
||||
|
||||
m_nextHandler = NULL;
|
||||
m_previousHandler = NULL;
|
||||
}
|
||||
|
||||
bool wxEvtHandler::IsUnlinked() const
|
||||
{
|
||||
return m_previousHandler == NULL &&
|
||||
m_nextHandler == NULL;
|
||||
}
|
||||
|
||||
#if wxUSE_THREADS
|
||||
|
||||
bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)
|
||||
|
@ -1096,73 +1096,121 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
|
||||
// event handler stuff
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
|
||||
void wxWindowBase::SetEventHandler(wxEvtHandler *handler)
|
||||
{
|
||||
wxCHECK_RET(handler != NULL, "SetEventHandler(NULL) called");
|
||||
|
||||
m_eventHandler = handler;
|
||||
}
|
||||
|
||||
void wxWindowBase::SetNextHandler(wxEvtHandler *WXUNUSED(handler))
|
||||
{
|
||||
// disable wxEvtHandler chain mechanism for wxWindows:
|
||||
// wxWindow uses its own stack mechanism which doesn't mix well with wxEvtHandler's one
|
||||
|
||||
wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
|
||||
}
|
||||
void wxWindowBase::SetPreviousHandler(wxEvtHandler *WXUNUSED(handler))
|
||||
{
|
||||
// we can't simply wxFAIL here as in SetNextHandler: in fact the last
|
||||
// handler of our stack when is destroyed will be Unlink()ed and thus
|
||||
// will call this function to update the pointer of this window...
|
||||
|
||||
//wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
|
||||
}
|
||||
|
||||
void wxWindowBase::PushEventHandler(wxEvtHandler *handlerToPush)
|
||||
{
|
||||
wxCHECK_RET( handlerToPush != NULL, "PushEventHandler(NULL) called" );
|
||||
|
||||
// the new handler is going to be part of the wxWindow stack of event handlers:
|
||||
// it can't be part also of an event handler double-linked chain:
|
||||
wxASSERT_MSG(handlerToPush->IsUnlinked(),
|
||||
"The handler being pushed in the wxWindow stack shouldn't be part of "
|
||||
"a wxEvtHandler chain; call Unlink() on it first");
|
||||
|
||||
wxEvtHandler *handlerOld = GetEventHandler();
|
||||
wxCHECK_RET( handlerOld, "an old event handler is NULL?" );
|
||||
|
||||
handler->SetNextHandler(handlerOld);
|
||||
// now use wxEvtHandler double-linked list to implement a stack:
|
||||
handlerToPush->SetNextHandler(handlerOld);
|
||||
|
||||
if ( handlerOld )
|
||||
GetEventHandler()->SetPreviousHandler(handler);
|
||||
if (handlerOld != this)
|
||||
handlerOld->SetPreviousHandler(handlerToPush);
|
||||
|
||||
SetEventHandler(handler);
|
||||
SetEventHandler(handlerToPush);
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
// final checks of the operations done above:
|
||||
wxASSERT_MSG( handlerToPush->GetPreviousHandler() == NULL,
|
||||
"the first handler of the wxWindow stack should have no previous handlers set" );
|
||||
wxASSERT_MSG( handlerToPush->GetNextHandler() != NULL,
|
||||
"the first handler of the wxWindow stack should have non-NULL next handler" );
|
||||
|
||||
wxEvtHandler* pLast = handlerToPush;
|
||||
while (pLast && pLast != this)
|
||||
pLast = pLast->GetNextHandler();
|
||||
wxASSERT_MSG( pLast->GetNextHandler() == NULL,
|
||||
"the last handler of the wxWindow stack should have this window as next handler" );
|
||||
#endif
|
||||
}
|
||||
|
||||
wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler)
|
||||
{
|
||||
wxEvtHandler *handlerA = GetEventHandler();
|
||||
if ( handlerA )
|
||||
// we need to pop the wxWindow stack, i.e. we need to remove the first handler
|
||||
|
||||
wxEvtHandler *firstHandler = GetEventHandler();
|
||||
wxCHECK_MSG( firstHandler != NULL, NULL, "wxWindow cannot have a NULL event handler" );
|
||||
wxCHECK_MSG( firstHandler != this, NULL, "cannot pop the wxWindow itself" );
|
||||
wxCHECK_MSG( firstHandler->GetPreviousHandler() == NULL, NULL,
|
||||
"the first handler of the wxWindow stack should have no previous handlers set" );
|
||||
|
||||
wxEvtHandler *secondHandler = firstHandler->GetNextHandler();
|
||||
wxCHECK_MSG( secondHandler != NULL, NULL,
|
||||
"the first handler of the wxWindow stack should have non-NULL next handler" );
|
||||
|
||||
firstHandler->SetNextHandler(NULL);
|
||||
secondHandler->SetPreviousHandler(NULL);
|
||||
|
||||
// now firstHandler is completely unlinked; set secondHandler as the new window event handler
|
||||
SetEventHandler(secondHandler);
|
||||
|
||||
if ( deleteHandler )
|
||||
{
|
||||
wxEvtHandler *handlerB = handlerA->GetNextHandler();
|
||||
handlerA->SetNextHandler(NULL);
|
||||
|
||||
if ( handlerB )
|
||||
handlerB->SetPreviousHandler(NULL);
|
||||
SetEventHandler(handlerB);
|
||||
|
||||
if ( deleteHandler )
|
||||
{
|
||||
delete handlerA;
|
||||
handlerA = NULL;
|
||||
}
|
||||
delete firstHandler;
|
||||
firstHandler = NULL;
|
||||
}
|
||||
|
||||
return handlerA;
|
||||
return firstHandler;
|
||||
}
|
||||
|
||||
bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
|
||||
bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handlerToRemove)
|
||||
{
|
||||
wxCHECK_MSG( handler, false, _T("RemoveEventHandler(NULL) called") );
|
||||
wxCHECK_MSG( handlerToRemove != NULL, false, "RemoveEventHandler(NULL) called" );
|
||||
wxCHECK_MSG( handlerToRemove != this, false, "Cannot remove the window itself" );
|
||||
|
||||
wxEvtHandler *handlerPrev = NULL,
|
||||
*handlerCur = GetEventHandler();
|
||||
while ( handlerCur )
|
||||
if (handlerToRemove == GetEventHandler())
|
||||
{
|
||||
// removing the first event handler is equivalent to "popping" the stack
|
||||
PopEventHandler(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: the wxWindow event handler list is always terminated with "this" handler
|
||||
wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
|
||||
while ( handlerCur != this )
|
||||
{
|
||||
wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
|
||||
|
||||
if ( handlerCur == handler )
|
||||
if ( handlerCur == handlerToRemove )
|
||||
{
|
||||
if ( handlerPrev )
|
||||
{
|
||||
handlerPrev->SetNextHandler(handlerNext);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEventHandler(handlerNext);
|
||||
}
|
||||
|
||||
if ( handlerNext )
|
||||
{
|
||||
handlerNext->SetPreviousHandler ( handlerPrev );
|
||||
}
|
||||
|
||||
handler->SetNextHandler(NULL);
|
||||
handler->SetPreviousHandler(NULL);
|
||||
handlerCur->Unlink();
|
||||
|
||||
wxASSERT_MSG( handlerCur != GetEventHandler(),
|
||||
"the case Remove == Pop should was already handled" );
|
||||
return true;
|
||||
}
|
||||
|
||||
handlerPrev = handlerCur;
|
||||
handlerCur = handlerNext;
|
||||
}
|
||||
|
||||
@ -1173,6 +1221,7 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
|
||||
|
||||
bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
|
||||
{
|
||||
// SafelyProcessEvent() will handle exceptions nicely
|
||||
return GetEventHandler()->SafelyProcessEvent(event);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user