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:
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.
|
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
|
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
|
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
|
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:
|
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">
|
<li value="5">
|
||||||
The event is passed to the next event handler, if any, in the event handler
|
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
|
chain, i.e., the steps (1) to (4) are done for it. This chain can be formed
|
||||||
using wxEvtHandler::SetNextHandler() or wxWindow::PushEventHandler() but
|
using wxEvtHandler::SetNextHandler():
|
||||||
usually there is no next event handler and chaining event handlers using
|
@image html overview_eventhandling_chain.png
|
||||||
these functions is much less useful now that Connect() exists so this step
|
(referring to the image, if @c A->ProcessEvent is called and it doesn't handle
|
||||||
will almost never do anything.
|
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>
|
||||||
|
|
||||||
<li value="6">
|
<li value="6">
|
||||||
@@ -349,7 +359,7 @@ doesn't count as having handled the event and the search continues):
|
|||||||
|
|
||||||
<li value="7">
|
<li value="7">
|
||||||
Finally, i.e., if the event is still not processed, the wxApp object itself
|
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>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
@@ -283,7 +283,7 @@ HR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.memproto, .memdoc {
|
.memproto, .memdoc {
|
||||||
border: 1px solid #84b0c7;
|
border: 1px solid #84b0c7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.memproto {
|
.memproto {
|
||||||
@@ -400,6 +400,10 @@ H2 > A.anchor {
|
|||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IMG {
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
IMG.logo {
|
IMG.logo {
|
||||||
float: right;
|
float: right;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
|
@@ -2668,14 +2668,27 @@ public:
|
|||||||
wxEvtHandler();
|
wxEvtHandler();
|
||||||
virtual ~wxEvtHandler();
|
virtual ~wxEvtHandler();
|
||||||
|
|
||||||
|
|
||||||
|
// Event handler chain
|
||||||
|
// -------------------
|
||||||
|
|
||||||
wxEvtHandler *GetNextHandler() const { return m_nextHandler; }
|
wxEvtHandler *GetNextHandler() const { return m_nextHandler; }
|
||||||
wxEvtHandler *GetPreviousHandler() const { return m_previousHandler; }
|
wxEvtHandler *GetPreviousHandler() const { return m_previousHandler; }
|
||||||
void SetNextHandler(wxEvtHandler *handler) { m_nextHandler = handler; }
|
virtual void SetNextHandler(wxEvtHandler *handler) { m_nextHandler = handler; }
|
||||||
void SetPreviousHandler(wxEvtHandler *handler) { m_previousHandler = handler; }
|
virtual void SetPreviousHandler(wxEvtHandler *handler) { m_previousHandler = handler; }
|
||||||
|
|
||||||
void SetEvtHandlerEnabled(bool enabled) { m_enabled = enabled; }
|
void SetEvtHandlerEnabled(bool enabled) { m_enabled = enabled; }
|
||||||
bool GetEvtHandlerEnabled() const { return m_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
|
// Process an event right now: this can only be called from the main
|
||||||
// thread, use QueueEvent() for scheduling the events for
|
// thread, use QueueEvent() for scheduling the events for
|
||||||
// processing from other threads.
|
// processing from other threads.
|
||||||
@@ -2686,6 +2699,7 @@ public:
|
|||||||
// when called from C code (e.g. in GTK+ callback) when the exception
|
// when called from C code (e.g. in GTK+ callback) when the exception
|
||||||
// wouldn't correctly propagate to wxEventLoop.
|
// wouldn't correctly propagate to wxEventLoop.
|
||||||
bool SafelyProcessEvent(wxEvent& event);
|
bool SafelyProcessEvent(wxEvent& event);
|
||||||
|
// NOTE: uses ProcessEvent()
|
||||||
|
|
||||||
// Schedule the given event to be processed later. It takes ownership of
|
// 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
|
// the event pointer, i.e. it will be deleted later. This is safe to call
|
||||||
@@ -2708,11 +2722,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ProcessPendingEvents();
|
void ProcessPendingEvents();
|
||||||
|
// NOTE: uses ProcessEvent()
|
||||||
|
|
||||||
#if wxUSE_THREADS
|
#if wxUSE_THREADS
|
||||||
bool ProcessThreadEvent(const wxEvent& event);
|
bool ProcessThreadEvent(const wxEvent& event);
|
||||||
|
// NOTE: uses AddPendingEvent()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Connecting and disconnecting
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
// Dynamic association of a member function handler with the event handler,
|
// Dynamic association of a member function handler with the event handler,
|
||||||
// winid and event type
|
// winid and event type
|
||||||
void Connect(int winid,
|
void Connect(int winid,
|
||||||
|
@@ -792,7 +792,7 @@ public:
|
|||||||
|
|
||||||
// replace the event handler (allows to completely subclass the
|
// replace the event handler (allows to completely subclass the
|
||||||
// window)
|
// window)
|
||||||
void SetEventHandler( wxEvtHandler *handler ) { m_eventHandler = handler; }
|
void SetEventHandler( wxEvtHandler *handler );
|
||||||
|
|
||||||
// push/pop event handler: allows to chain a custom event handler to
|
// push/pop event handler: allows to chain a custom event handler to
|
||||||
// alreasy existing ones
|
// alreasy existing ones
|
||||||
@@ -806,13 +806,17 @@ public:
|
|||||||
// be there)
|
// be there)
|
||||||
bool RemoveEventHandler(wxEvtHandler *handler);
|
bool RemoveEventHandler(wxEvtHandler *handler);
|
||||||
|
|
||||||
// Process an event by calling GetEventHandler()->ProcessEvent() and
|
// Process an event by calling GetEventHandler()->ProcessEvent() and
|
||||||
// handling any exceptions thrown by event handlers. It's mostly useful
|
// handling any exceptions thrown by event handlers. It's mostly useful
|
||||||
// when processing wx events when called from C code (e.g. in GTK+
|
// when processing wx events when called from C code (e.g. in GTK+
|
||||||
// callback) when the exception wouldn't correctly propagate to
|
// callback) when the exception wouldn't correctly propagate to
|
||||||
// wxEventLoop.
|
// wxEventLoop.
|
||||||
bool HandleWindowEvent(wxEvent& event) const;
|
bool HandleWindowEvent(wxEvent& event) const;
|
||||||
|
|
||||||
|
// disable wxEvtHandler double-linked list mechanism:
|
||||||
|
virtual void SetNextHandler(wxEvtHandler *handler);
|
||||||
|
virtual void SetPreviousHandler(wxEvtHandler *handler);
|
||||||
|
|
||||||
// validators
|
// validators
|
||||||
// ----------
|
// ----------
|
||||||
|
|
||||||
|
@@ -258,7 +258,7 @@ public:
|
|||||||
wxWindow is (and therefore all window classes are) derived from this class.
|
wxWindow is (and therefore all window classes are) derived from this class.
|
||||||
|
|
||||||
When events are received, wxEvtHandler invokes the method listed in the
|
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
|
<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
|
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.
|
will be identical to the @c this pointer of the wxEvtHandler portion.
|
||||||
@@ -279,8 +279,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
Destructor.
|
Destructor.
|
||||||
|
|
||||||
If the handler is part of a chain, the destructor will unlink itself and
|
If the handler is part of a chain, the destructor will unlink itself
|
||||||
restore the previous and next handlers so that they point to each other.
|
(see Unlink()).
|
||||||
*/
|
*/
|
||||||
virtual ~wxEvtHandler();
|
virtual ~wxEvtHandler();
|
||||||
|
|
||||||
@@ -382,17 +382,23 @@ public:
|
|||||||
|
|
||||||
The normal order of event table searching is as follows:
|
The normal order of event table searching is as follows:
|
||||||
-# If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled)
|
-# 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
|
-# 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
|
-# 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
|
class table is tried, and so on until no more tables exist or an appropriate
|
||||||
function was found, in which case the function exits.
|
function was found, in which case the function exits.
|
||||||
-# The search is applied down the entire chain of event handlers (usually the
|
-# 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()
|
-# If the object is a wxWindow and the event is a wxCommandEvent, ProcessEvent()
|
||||||
is recursively applied to the parent window's event handler.
|
is recursively applied to the parent window's event handler.
|
||||||
If this returns true, the function exits.
|
If this returns @true, the function exits.
|
||||||
-# Finally, ProcessEvent() is called on the wxApp object.
|
-# Finally, ProcessEvent() is called on the wxApp object.
|
||||||
|
|
||||||
@param event
|
@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.
|
Sets the pointer to the next handler.
|
||||||
|
|
||||||
@param handler
|
@remarks
|
||||||
Event handler to be set as the next handler.
|
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(),
|
@param handler
|
||||||
wxWindow::PushEventHandler, wxWindow::PopEventHandler
|
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.
|
Sets the pointer to the previous handler.
|
||||||
|
All remarks about SetNextHandler() apply to this function as well.
|
||||||
|
|
||||||
@param handler
|
@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
|
@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;
|
wxEvtHandler* GetEventHandler() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This function will generate the appropriate call to
|
This function will generate the appropriate call to Navigate() if the key
|
||||||
Navigate() if the key event is one normally used for
|
event is one normally used for keyboard navigation and return @true in this case.
|
||||||
keyboard navigation and return @true in this case.
|
|
||||||
|
|
||||||
@return Returns @true if the key pressed was for navigation and was
|
@return Returns @true if the key pressed was for navigation and was
|
||||||
handled, @false otherwise.
|
handled, @false otherwise.
|
||||||
@@ -1691,44 +1693,62 @@ public:
|
|||||||
/**
|
/**
|
||||||
Removes and returns the top-most event handler on the event handler stack.
|
Removes and returns the top-most event handler on the event handler stack.
|
||||||
|
|
||||||
@param deleteHandler
|
E.g. in the case of:
|
||||||
If this is @true, the handler will be deleted after it is removed.
|
@image html overview_eventhandling_winstack.png
|
||||||
The default value is @false.
|
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(),
|
Note that it's an error to call this function when no event handlers
|
||||||
PushEventHandler(), wxEvtHandler::ProcessEvent, wxEvtHandler
|
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);
|
wxEvtHandler* PopEventHandler(bool deleteHandler = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Pushes this event handler onto the event stack for the window.
|
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
|
@param handler
|
||||||
Specifies the handler to be pushed.
|
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
|
@see @ref overview_eventhandling_processing
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
void PushEventHandler(wxEvtHandler* handler);
|
void PushEventHandler(wxEvtHandler* handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Find the given @a handler in the windows event handler chain and remove
|
Find the given @a handler in the windows event handler stack and unlinks
|
||||||
(but not delete) it from it.
|
(but not delete) it. See wxEvtHandler::Unlink() for more info.
|
||||||
|
|
||||||
@param handler
|
@param handler
|
||||||
The event handler to remove, must be non-@NULL and
|
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
|
@return Returns @true if it was found and @false otherwise (this also
|
||||||
results in an assert failure so this function should
|
results in an assert failure so this function should
|
||||||
@@ -1741,27 +1761,41 @@ public:
|
|||||||
/**
|
/**
|
||||||
Sets the event handler for this window.
|
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
|
@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
|
@see @ref overview_eventhandling_processing
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
void SetEventHandler(wxEvtHandler* handler);
|
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
|
@name Window styles functions
|
||||||
*/
|
*/
|
||||||
|
@@ -1036,12 +1036,7 @@ wxEvtHandler::wxEvtHandler()
|
|||||||
|
|
||||||
wxEvtHandler::~wxEvtHandler()
|
wxEvtHandler::~wxEvtHandler()
|
||||||
{
|
{
|
||||||
// Takes itself out of the list of handlers
|
Unlink();
|
||||||
if (m_previousHandler)
|
|
||||||
m_previousHandler->m_nextHandler = m_nextHandler;
|
|
||||||
|
|
||||||
if (m_nextHandler)
|
|
||||||
m_nextHandler->m_previousHandler = m_previousHandler;
|
|
||||||
|
|
||||||
if (m_dynamicEvents)
|
if (m_dynamicEvents)
|
||||||
{
|
{
|
||||||
@@ -1103,6 +1098,26 @@ wxEvtHandler::~wxEvtHandler()
|
|||||||
delete m_clientObject;
|
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
|
#if wxUSE_THREADS
|
||||||
|
|
||||||
bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)
|
bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)
|
||||||
|
@@ -1096,73 +1096,121 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
|
|||||||
// event handler stuff
|
// 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();
|
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 )
|
if (handlerOld != this)
|
||||||
GetEventHandler()->SetPreviousHandler(handler);
|
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 *wxWindowBase::PopEventHandler(bool deleteHandler)
|
||||||
{
|
{
|
||||||
wxEvtHandler *handlerA = GetEventHandler();
|
// we need to pop the wxWindow stack, i.e. we need to remove the first handler
|
||||||
if ( handlerA )
|
|
||||||
|
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();
|
delete firstHandler;
|
||||||
handlerA->SetNextHandler(NULL);
|
firstHandler = NULL;
|
||||||
|
|
||||||
if ( handlerB )
|
|
||||||
handlerB->SetPreviousHandler(NULL);
|
|
||||||
SetEventHandler(handlerB);
|
|
||||||
|
|
||||||
if ( deleteHandler )
|
|
||||||
{
|
|
||||||
delete handlerA;
|
|
||||||
handlerA = 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,
|
if (handlerToRemove == GetEventHandler())
|
||||||
*handlerCur = GetEventHandler();
|
{
|
||||||
while ( handlerCur )
|
// 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();
|
wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
|
||||||
|
|
||||||
if ( handlerCur == handler )
|
if ( handlerCur == handlerToRemove )
|
||||||
{
|
{
|
||||||
if ( handlerPrev )
|
handlerCur->Unlink();
|
||||||
{
|
|
||||||
handlerPrev->SetNextHandler(handlerNext);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetEventHandler(handlerNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( handlerNext )
|
|
||||||
{
|
|
||||||
handlerNext->SetPreviousHandler ( handlerPrev );
|
|
||||||
}
|
|
||||||
|
|
||||||
handler->SetNextHandler(NULL);
|
|
||||||
handler->SetPreviousHandler(NULL);
|
|
||||||
|
|
||||||
|
wxASSERT_MSG( handlerCur != GetEventHandler(),
|
||||||
|
"the case Remove == Pop should was already handled" );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerPrev = handlerCur;
|
|
||||||
handlerCur = handlerNext;
|
handlerCur = handlerNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1173,6 +1221,7 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
|
|||||||
|
|
||||||
bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
|
bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
|
||||||
{
|
{
|
||||||
|
// SafelyProcessEvent() will handle exceptions nicely
|
||||||
return GetEventHandler()->SafelyProcessEvent(event);
|
return GetEventHandler()->SafelyProcessEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user