]> git.saurik.com Git - wxWidgets.git/commitdiff
update documentation for Bind() (closes #10594)
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 29 Mar 2009 12:53:54 +0000 (12:53 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 29 Mar 2009 12:53:54 +0000 (12:53 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59911 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/doxygen/overviews/eventhandling.h
interface/wx/event.h

index 9bdbd8c1a9ff6dd81ffbc11057c7469583006703..39abbaa3d187f809935a57d275528f6599a637f3 100644 (file)
@@ -61,23 +61,27 @@ To be more precise, each event is described by:
 @section overview_events_eventhandling Event Handling
 
 There are two principal ways to handle events in wxWidgets. One of them uses
-<em>event table</em> macros and allows you to define the connection between events
+<em>event table</em> macros and allows you to define the binding between events
 and their handlers only statically, i.e., during program compilation. The other
-one uses wxEvtHandler::Connect() call and can be used to connect, and
-disconnect, the handlers dynamically, i.e., during run-time depending on some
-conditions. It also allows the direct connection of the events of one object to a
-handler method in another object. The static event tables can only handle
-events in the object where they are defined so using Connect() is more flexible
+one uses wxEvtHandler::Bind<>() call and can be used to bind and
+unbind, the handlers dynamically, i.e. during run-time depending on some
+conditions. It also allows the direct binding of events to:
+@li A handler method in another object.
+@li An ordinary function like a static method or a global function.
+@li An arbitrary functor like boost::function<>.
+
+The static event tables can only handle
+events in the object where they are defined so using Bind<>() is more flexible
 than using the event tables. On the other hand, event tables are more succinct
-and centralize all event handlers connection in one place. You can either
+and centralize all event handler bindings in one place. You can either
 choose a single approach that you find preferable or freely combine both
 methods in your program in different classes or even in one and the same class,
 although this is probably sufficiently confusing to be a bad idea.
 
 But before you make this choice, let us discuss these two ways in more
 detail. In the next section we provide a short introduction to handling the
-events using the event tables. Please see @ref overview_events_connect
-for the discussion of Connect().
+events using the event tables. Please see @ref overview_events_bind
+for the discussion of Bind<>().
 
 @subsection overview_events_eventtables Event Handling with Event Tables
 
@@ -90,7 +94,7 @@ containing the menu, so let's suppose that you need to handle some events in @c
 MyFrame class deriving from wxFrame.
 
 First define one or more <em>event handlers</em>. They
-are just simple (non-virtual) methods of the class that take as a parameter a
+are just simple methods of the class that take as a parameter a
 reference to an object of a wxEvent-derived class and have no return value (any
 return information is passed via the argument, which is why it is non-const).
 You also need to insert a macro
@@ -150,7 +154,7 @@ the event table definition; just defining it in MyFrame class is @e not enough.
 Let us now look at the details of this definition: the first line means that we
 are defining the event table for MyFrame class and that its base class is
 wxFrame, so events not processed by MyFrame will, by default, be handled by
-wxFrame. The next four lines define connections of individual events to their
+wxFrame. The next four lines define bindings of individual events to their
 handlers: the first two of them map menu commands from the items with the
 identifiers specified as the first macro parameter to two different member
 functions. In the next one, @c EVT_SIZE means that any changes in the size of
@@ -205,73 +209,59 @@ wxEvent-derived classes in the discussion of each control generating these
 events.
 
 
-@subsection overview_events_connect Dynamic Event Handling
-
-As with the event tables, decide in which class you intend to
-handle the events first and, as before, this class must derive from
-wxEvtHandler (usually indirectly via wxWindow). See the declaration of MyFrame
-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.
+@subsection overview_events_bind Dynamic Event Handling
 
+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 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:
+global scope as with the event tables), call its Bind<>() method like this:
 
 @code
 MyFrame::MyFrame(...)
 {
-      Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,
-                wxCommandEventHandler(MyFrame::OnExit));
+      Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExit, this, wxID_EXIT);
 }
 @endcode
 
-This class should be self-explanatory except for wxCommandEventHandler part:
-this is a macro that ensures that the method is of the correct type by using
-static_cast in the same way as the event table macros.
+Note that @c this pointer must be specified here.
 
 Now let us describe the semantic differences:
 <ul>
     <li>
-        Event handlers can be connected at any moment. For example, it's possible
-        to do some initialization first and only connect the handlers if and when
+        Event handlers can be bound at any moment. For example, it's possible
+        to do some initialization first and only bind the handlers if and when
         it succeeds. This can avoid the need to test that the object was properly
-        initialized in the event handlers themselves. With Connect() they
+        initialized in the event handlers themselves. With Bind<>() they
         simply won't be called if it wasn't correctly initialized.
     </li>
 
     <li>
-        As a slight extension of the above, the handlers can also be
-        Disconnect()-ed at any time and maybe later reconnected. Of course,
+        As a slight extension of the above, the handlers can also be unbound at
+        any time with Unbind<>() (and maybe rebound later). Of course,
         it's also possible to emulate this behaviour with the classic
-        static (i.e., connected via event tables) handlers by using an internal
+        static (i.e., bound via event tables) handlers by using an internal
         flag indicating whether the handler is currently enabled and returning
-        from it if it isn't, but using dynamically connected handlers requires
+        from it if it isn't, but using dynamically bind handlers requires
         less code and is also usually more clear.
     </li>
 
     <li>
-        Also notice that you must derive a class inherited from, say,
-        wxTextCtrl even if you don't want to modify the control behaviour at
-        all but just want to handle some of its events. This is especially
-        inconvenient when the control is loaded from the XRC. Connecting the
-        event handler dynamically bypasses the need for this unwanted
-        sub-classing.
-    </li>
-
-    <li>
-        Last but very, very far from least is the possibility to connect an
-        event of some object to a method of another object. This is impossible
-        to do with event tables because it is not possible to specify the
-        object to dispatch the event to so it necessarily needs to be sent to
-        the same object which generated the event. Not so with Connect() which
-        has an optional @c eventSink parameter that can be used to specify the
-        object which will handle the event. Of course, in this case the method
-        being connected must belong to the class that is the type of the
-        @c eventSink object! To give a quick example, people often want to catch
-        mouse movement events happening when the mouse is in one of the frame
-        children in the frame itself. Doing it in a naive way doesn't work:
+        Almost last but very, very far from least is the increased flexibility
+        which allows to bind an event to:
+        @li A method in another object.
+        @li An ordinary function like a static method or a global function.
+        @li An arbitrary functor like boost::function<>.
+
+        This is impossible to do with the event tables because it is not
+        possible to specify these handlers to dispatch the event to, so it
+        necessarily needs to be sent to the same object which generated the
+        event. Not so with Bind<>() which can be used to specify these handlers
+        which will handle the event. To give a quick example, a common question
+        is how to receive the mouse movement events happening when the mouse is
+        in one of the frame children in the frame itself. Doing it in a naive
+        way doesn't work:
         <ul>
             <li>
                 A @c EVT_LEAVE_WINDOW(MyFrame::OnMouseLeave) line in the frame
@@ -295,10 +285,7 @@ Now let us describe the semantic differences:
         @code
             MyFrame::MyFrame(...)
             {
-              m_child->Connect(wxID_ANY, wxEVT_LEAVE_WINDOW,
-                               wxMouseEventHandler(MyFrame::OnMouseLeave),
-                               NULL,  // unused extra data parameter
-                               this); // this indicates the object to connect to
+              m_child->Bind(wxEVT_LEAVE_WINDOW, &MyFrame::OnMouseLeave, this);
             }
         @endcode
         will work exactly as expected. Note that you can get the object that
@@ -306,9 +293,118 @@ Now let us describe the semantic differences:
         wxEvent::GetEventObject() method of @c event argument passed to the
         event handler.
     </li>
+
+    <li>
+        Really last point is the consequence of the previous one: because of
+        increased flexibility of Bind(), it is also safer as it is impossible
+        to accidentally use a method of another class. Instead of run-time
+        crashes you will get compilation errors in this case when using Bind().
+    </li>
 </ul>
 
-To summarize, using Connect() requires slightly more typing but is much more
+Here are some more examples of how to use different event handlers.
+
+You can use a method from a completely different object as an event handler:
+
+@code
+void MyFrameHandler::OnFrameExit( wxCommandEvent & )
+{
+    // Do something useful.
+}
+
+MyFrameHandler myFrameHandler;
+
+MyFrame::MyFrame()
+{
+      Bind( wxEVT_COMMAND_MENU_SELECTED, &MyFrameHandler::OnFrameExit,
+              &myFrameHandler, wxID_EXIT );
+}
+@endcode
+
+Note that @c MyFrameHandler doesn't need to derive from wxEvtHandler. But
+keep in mind that then the lifetime of @c myFrameHandler must be greater than
+that of @c MyFrame object -- or at least it needs to be unbound before being
+destroyed.
+
+To use an ordinary function or a static method as an event handler you would
+write something like this:
+
+@code
+void HandleExit( wxCommandEvent & )
+{
+    // Do something useful
+}
+
+MyFrame::MyFrame()
+{
+    Bind( wxEVT_COMMAND_MENU_SELECTED, &HandleExit, wxID_EXIT );
+}
+@endcode
+
+And finally you can bind to an arbitrary functor and use it as an event
+handler:
+
+@code
+
+struct MyFunctor
+{
+    void operator()( wxCommandEvent & )
+    {
+        // Do something useful
+    }
+};
+
+MyFunctor myFunctor;
+
+MyFrame::MyFrame()
+{
+    Bind( wxEVT_COMMAND_MENU_SELECTED, &myFunctor, wxID_EXIT );
+}
+@endcode
+
+A common example of a functor is boost::function<>:
+
+@code
+using namespace boost;
+
+void MyHandler::OnExit( wxCommandEvent & )
+{
+    // Do something useful
+}
+
+MyHandler myHandler;
+
+MyFrame::MyFrame()
+{
+    function< void ( wxCommandEvent & ) > exitHandler( bind( &MyHandler::OnExit, &myHandler, _1 ));
+
+    Bind( wxEVT_COMMAND_MENU_SELECTED, exitHandler, wxID_EXIT );
+}
+@endcode
+
+
+With the aid of boost::bind<>() you can even use methods or functions which
+don't quite have the correct signature:
+
+@code
+void MyHandler::OnExit( int exitCode, wxCommandEvent &, wxString goodByeMessage )
+{
+    // Do something useful
+}
+
+MyHandler myHandler;
+
+MyFrame::MyFrame()
+{
+    function< void ( wxCommandEvent & ) > exitHandler(
+            bind( &MyHandler::OnExit, &myHandler, EXIT_FAILURE, _1, "Bye" ));
+
+    Bind( wxEVT_COMMAND_MENU_SELECTED, exitHandler, wxID_EXIT );
+}
+@endcode
+
+
+To summarize, using Bind<>() requires slightly more typing but is much more
 flexible than using static event tables so don't hesitate to use it when you
 need this extra power. On the other hand, event tables are still perfectly fine
 in simple situations where this extra flexibility is not needed.
@@ -344,8 +440,8 @@ doesn't count as having handled the event and the search continues):
     </li>
 
     <li value="3">
-    The list of dynamically connected event handlers, i.e., those for which
-    Connect() was called, is consulted. Notice that this is done before
+    The list of dynamically bind event handlers, i.e., those for which
+    Bind<>() was called, is consulted. Notice that this is done before
     checking the static event table entries, so if both a dynamic and a static
     event handler match the same event, the static one is never going to be
     used.
@@ -370,7 +466,7 @@ doesn't count as having handled the event and the search continues):
         @image html overview_events_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
+     itself is used - i.e. the dynamically bind 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
@@ -499,10 +595,10 @@ void MyFrame::OnMyEvent(wxCommandEvent& event)
     wxString text = event.GetText();
 }
 
-// example of code handling the event with Connect():
+// example of code handling the event with Bind<>():
 MyFrame::MyFrame()
 {
-    Connect(ID_MY_WINDOW, MY_EVENT, &MyFrame::OnMyEvent);
+    Bind(MY_EVENT, &MyFrame::OnMyEvent, this, ID_MY_WINDOW);
 }
 
 // example of code generating the event
@@ -561,14 +657,14 @@ wxDEFINE_EVENT(MY_PLOT_CLICKED, MyPlotEvent);
 typedef void (wxEvtHandler::*MyPlotEventFunction)(MyPlotEvent&);
 #define MyPlotEventHandler(func) wxEVENT_HANDLER_CAST(MyPlotEventFunction, func)
 
-// if your code is only built sing reasonably modern compilers, you could just
+// if your code is only built using reasonably modern compilers, you could just
 // do this instead:
 #define MyPlotEventHandler(func) (&func)
 
 // finally define a macro for creating the event table entries for the new
 // event type
 //
-// remember that you don't need this at all if you only use Connect() and that
+// remember that you don't need this at all if you only use Bind<>() and that
 // you can replace MyPlotEventHandler(func) with just &func unless you use a
 // really old compiler
 #define MY_EVT_PLOT_CLICK(id, func) \
@@ -583,7 +679,7 @@ END_EVENT_TABLE()
 
 MyFrame::MyFrame()
 {
-    Connect(ID_MY_WINDOW, MY_PLOT_CLICKED, &MyFrame::OnPlot);
+    Bind(MY_PLOT_CLICKED, &MyFrame::OnPlot, this, ID_MY_WINDOW);
 }
 
 void MyFrame::OnPlot(MyPlotEvent& event)
@@ -626,9 +722,6 @@ code by the underlying toolkit or OS itself. But even if it does exist at
 wxWidgets level, it should never be called directly as the event handlers are
 not part of wxWidgets API and should never be called directly.
 
-Finally, please notice that the event handlers themselves shouldn't be virtual.
-They should always be non-virtual and usually private (as there is no need to
-make them public) methods of a wxEvtHandler-derived class.
 
 
 @subsection overview_events_prog User Generated Events vs Programmatically Generated Events
@@ -656,7 +749,7 @@ equivalents.
 
 @subsection overview_events_pluggable Pluggable Event Handlers
 
-<em>TODO: Probably deprecated, Connect() provides a better way to do this</em>
+<em>TODO: Probably deprecated, Bind() provides a better way to do this</em>
 
 In fact, you don't have to derive a new class from a window class
 if you don't want to. You can derive a new class from wxEvtHandler instead,
@@ -703,7 +796,7 @@ generated for you automatically by wxWidgets. This is useful when you don't
 care about the exact identifier either because you're not going to process the
 events from the control being created or because you process the events
 from all controls in one place (in which case you should specify @c wxID_ANY
-in the event table or wxEvtHandler::Connect call
+in the event table or wxEvtHandler::Bind call
 as well). The automatically generated identifiers are always negative and so
 will never conflict with the user-specified identifiers which must be always
 positive.
index c35a940299fed7ebf02daf37bc122ac4bd56d5ad..37732d5346c9709bcbdc05521c097d7b2c938330 100644 (file)
@@ -467,11 +467,11 @@ public:
            the function skips to step (7).
         -# TryBefore() is called (this is where wxValidator are taken into
            account for wxWindow objects). If this returns @true, the function exits.
-        -# Dynamic event table of the handlers connected using Connect() is
+        -# Dynamic event table of the handlers binded using Bind<>() is
            searched. If a handler is found, it is executed and the function
            returns @true unless the handler used wxEvent::Skip() to indicate
            that it didn't handle the event in which case the search continues.
-        -# Static events table of the handlers connected using event table
+        -# Static events table of the handlers binded using event table
            macros is searched for this event handler. If this fails, the base
            class event table table is tried, and so on until no more tables
            exist or an appropriate function was found. If a handler is found,
@@ -533,17 +533,17 @@ public:
         @see wxWindow::HandleWindowEvent
     */
     bool SafelyProcessEvent(wxEvent& event);
-    
+
     /**
-        Processes the pending events previously queued using QueueEvent() or 
+        Processes the pending events previously queued using QueueEvent() or
         AddPendingEvent(); you must call this function only if you are sure
         there are pending events for this handler, otherwise a @c wxCHECK
         will fail.
-        
+
         The real processing still happens in ProcessEvent() which is called by this
         function.
-        
-        Note that this function needs a valid application object (see 
+
+        Note that this function needs a valid application object (see
         wxAppConsole::GetInstance()) because wxApp holds the list of the event
         handlers with pending events and this function manipulates that list.
     */
@@ -552,13 +552,13 @@ public:
     /**
         Deletes all events queued on this event handler using QueueEvent() or
         AddPendingEvent().
-        
+
         Use with care because the events which are deleted are (obviously) not
         processed and this may have unwanted consequences (e.g. user actions events
         will be lost).
     */
     void DeletePendingEvents();
-    
+
     /**
         Searches the event table, executing an event handler function if an appropriate
         one is found.
@@ -580,7 +580,7 @@ public:
 
                  If a suitable function is called but calls wxEvent::Skip, this
                  function will fail, and searching will continue.
-                 
+
          @todo this function in the header is listed as an "implementation only" function;
                are we sure we want to document it?
 
@@ -601,6 +601,11 @@ public:
         Connects the given function dynamically with the event handler, id and
         event type.
 
+        Notice that Bind() provides a more flexible and safer way to do the
+        same thing as Connect(), please use it in any new code -- while
+        Connect() is not formally deprecated due to its existing widespread
+        usage, it has no advantages compared to Bind().
+
         This is an alternative to the use of static event tables. It is more
         flexible as it allows to connect events generated by some object to an
         event handler defined in a different object of a different class (which
@@ -609,7 +614,7 @@ public:
         Do make sure to specify the correct @a eventSink when connecting to an
         event of a different object.
 
-        See @ref overview_events_connect for more detailed explanation
+        See @ref overview_events_bind for more detailed explanation
         of this function and the @ref page_samples_event sample for usage
         examples.
 
@@ -639,6 +644,8 @@ public:
             Object whose member function should be called. It must be specified
             when connecting an event generated by one object to a member
             function of a different object. If it is omitted, @c this is used.
+
+        @see Bind<>()
     */
     void Connect(int id, int lastId, wxEventType eventType,
                  wxObjectEventFunction function,
@@ -724,6 +731,143 @@ public:
     //@}
 
 
+    /**
+        @name Binding and Unbinding
+    */
+    //@{
+
+    /**
+        Binds the given function, functor or method dynamically with the event.
+
+        This offers basically the same functionality as Connect(), but it is
+        more flexible as it also allows you to use ordinary functions and
+        arbitrary functors as event handlers. It is also less restrictive then
+        Connect() because you can use an arbitrary method as an event handler,
+        where as Connect() requires a wxEvtHandler derived handler.
+
+        See @ref overview_events_bind for more detailed explanation
+        of this function and the @ref page_samples_event sample for usage
+        examples.
+
+        @param eventType
+            The event type to be associated with this event handler.
+        @param functor
+            The event handler functor. This can be an ordinary function but also
+            an arbitrary functor like boost::function<>.
+        @param id
+            The first ID of the identifier range to be associated with the event
+            handler.
+        @param lastId
+            The last ID of the identifier range to be associated with the event
+            handler.
+        @param userData
+            Data to be associated with the event table entry.
+
+        @since 2.9.0
+    */
+    template <typename EventTag, typename Functor>
+    void Bind(const EventTag& eventType,
+              Functor functor,
+              int id = wxID_ANY,
+              int lastId = wxID_ANY,
+              wxObject *userData = NULL);
+
+    /**
+        See the Bind<>(const EventTag&, Functor, int, int, wxObject*) overload for
+        more info.
+
+        This overload will bind the given method as the event handler.
+
+        @param eventType
+            The event type to be associated with this event handler.
+        @param method
+            The event handler method. This can be an arbitrary method (doesn't need
+            to be from a wxEvtHandler derived class).
+        @param handler
+            Object whose method should be called. It must always be specified
+            so it can be checked at compile time whether the given method is an
+            actual member of the given handler.
+        @param id
+            The first ID of the identifier range to be associated with the event
+            handler.
+        @param lastId
+            The last ID of the identifier range to be associated with the event
+            handler.
+        @param userData
+            Data to be associated with the event table entry.
+
+        @since 2.9.0
+    */
+    template <typename EventTag, typename Class, typename EventArg, typename EventHandler>
+    void Bind(const EventTag &eventType,
+              void (Class::*method)(EventArg &),
+              EventHandler *handler,
+              int id = wxID_ANY,
+              int lastId = wxID_ANY,
+              wxObject *userData = NULL);
+    /**
+        Unbinds the given function, functor or method dynamically from the
+        event handler, using the specified parameters as search criteria and
+        returning @true if a matching function has been found and removed.
+
+        This method can only unbind functions, functors or methods which have
+        been added using the Bind<>() method. There is no way to unbind
+        functions binded using the (static) event tables.
+
+        @param eventType
+            The event type associated with this event handler.
+        @param functor
+            The event handler functor. This can be an ordinary function but also
+            an arbitrary functor like boost::function<>.
+        @param id
+            The first ID of the identifier range associated with the event
+            handler.
+        @param lastId
+            The last ID of the identifier range associated with the event
+            handler.
+        @param userData
+            Data associated with the event table entry.
+
+        @since 2.9.0
+    */
+    template <typename EventTag, typename Functor>
+    bool Unbind(const EventTag& eventType,
+                Functor functor,
+                int id = wxID_ANY,
+                int lastId = wxID_ANY,
+                wxObject *userData = NULL);
+
+    /**
+        See the Unbind<>(const EventTag&, Functor, int, int, wxObject*)
+        overload for more info.
+
+        This overload unbinds the given method from the event..
+
+        @param eventType
+            The event type associated with this event handler.
+        @param method
+            The event handler method associated with this event.
+        @param handler
+            Object whose method was called.
+        @param id
+            The first ID of the identifier range associated with the event
+            handler.
+        @param lastId
+            The last ID of the identifier range associated with the event
+            handler.
+        @param userData
+            Data associated with the event table entry.
+
+        @since 2.9.0
+    */
+    template <typename EventTag, typename Class, typename EventArg, typename EventHandler>
+    bool Unbind(const EventTag &eventType,
+                void (Class::*method)(EventArg&),
+                EventHandler *handler,
+                int id = wxID_ANY,
+                int lastId = wxID_ANY,
+                wxObject *userData = NULL );
+    //@}
     /**
         @name User-supplied data
     */