]> git.saurik.com Git - wxWidgets.git/commitdiff
Add wxEvtHandler::CallAfter() for asynchronous method calls.
authorVadim Zeitlin <vadim@wxwidgets.org>
Tue, 23 Oct 2012 12:02:24 +0000 (12:02 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Tue, 23 Oct 2012 12:02:24 +0000 (12:02 +0000)
Add wxAsyncMethodCallEvent that is handled simply by calling the method this
event was created for and add default handler for this event to wxEvtHandler.

Implement CallAfter() overloads for up to 2 parameters only for now.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72722 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/event.h
interface/wx/event.h
src/common/event.cpp

index 095511a1d9ec2dcc5840731084ebfc8400aac46b..4bd6cef11f69dff6245abafbfb7df205f57f4e67 100644 (file)
@@ -529,6 +529,7 @@ Major new features in this release
 
 All:
 
+- Add wxEvtHandler::CallAfter() method for asynchronous method calls.
 - Add support for symlinks to wxFileName (David Hart).
 - Allow testing for symlink/FIFO/socket existence in wxFileName (David Hart).
 - Many important bug fixes in wxFileSystemWatcher (David Hart).
index 5db787ce6c952d9c17b3f3bd4a4368cac4f09c16..e28d5c29708f993883195c7a2c7bb5ede552a6bc 100644 (file)
@@ -33,6 +33,8 @@
     #include "wx/meta/convertible.h"
 #endif
 
+#include "wx/meta/removeref.h"
+
 // ----------------------------------------------------------------------------
 // forward declarations
 // ----------------------------------------------------------------------------
@@ -621,6 +623,7 @@ extern WXDLLIMPEXP_BASE const wxEventType wxEVT_USER_FIRST;
     // Need events declared to do this
 class WXDLLIMPEXP_FWD_BASE wxIdleEvent;
 class WXDLLIMPEXP_FWD_BASE wxThreadEvent;
+class WXDLLIMPEXP_FWD_BASE wxAsyncMethodCallEvent;
 class WXDLLIMPEXP_FWD_CORE wxCommandEvent;
 class WXDLLIMPEXP_FWD_CORE wxMouseEvent;
 class WXDLLIMPEXP_FWD_CORE wxFocusEvent;
@@ -681,8 +684,9 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TOOL_ENTER, wxCommandEv
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_COMBOBOX_DROPDOWN, wxCommandEvent);
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_COMBOBOX_CLOSEUP, wxCommandEvent);
 
-    // Thread events
+    // Thread and asynchronous method call events
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_BASE, wxEVT_THREAD, wxThreadEvent);
+wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_BASE, wxEVT_ASYNC_METHOD_CALL, wxAsyncMethodCallEvent);
 
     // Mouse event types
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_LEFT_DOWN, wxMouseEvent);
@@ -1266,6 +1270,159 @@ private:
 };
 
 
+// Asynchronous method call events: these event are processed by wxEvtHandler
+// itself and result in a call to its Execute() method which simply calls the
+// specified method. The difference with a simple method call is that this is
+// done asynchronously, i.e. at some later time, instead of immediately when
+// the event object is constructed.
+
+// This is a base class used to process all method calls.
+class wxAsyncMethodCallEvent : public wxEvent
+{
+public:
+    wxAsyncMethodCallEvent(wxObject* object)
+        : wxEvent(wxID_ANY, wxEVT_ASYNC_METHOD_CALL)
+    {
+        SetEventObject(object);
+    }
+
+    wxAsyncMethodCallEvent(const wxAsyncMethodCallEvent& other)
+        : wxEvent(other)
+    {
+    }
+
+    virtual void Execute() = 0;
+};
+
+// This is a version for calling methods without parameters.
+template <typename T>
+class wxAsyncMethodCallEvent0 : public wxAsyncMethodCallEvent
+{
+public:
+    typedef T ObjectType;
+    typedef void (ObjectType::*MethodType)();
+
+    wxAsyncMethodCallEvent0(ObjectType* object,
+                            MethodType method)
+        : wxAsyncMethodCallEvent(object),
+          m_object(object),
+          m_method(method)
+    {
+    }
+
+    wxAsyncMethodCallEvent0(const wxAsyncMethodCallEvent0& other)
+        : wxAsyncMethodCallEvent(other),
+          m_object(other.m_object),
+          m_method(other.m_method)
+    {
+    }
+
+    virtual wxEvent *Clone() const
+    {
+        return new wxAsyncMethodCallEvent0(*this);
+    }
+
+    virtual void Execute()
+    {
+        (m_object->*m_method)();
+    }
+
+private:
+    ObjectType* const m_object;
+    const MethodType m_method;
+};
+
+// This is a version for calling methods with a single parameter.
+template <typename T, typename T1>
+class wxAsyncMethodCallEvent1 : public wxAsyncMethodCallEvent
+{
+public:
+    typedef T ObjectType;
+    typedef void (ObjectType::*MethodType)(T1 x1);
+    typedef typename wxRemoveRef<T1>::type ParamType1;
+
+    wxAsyncMethodCallEvent1(ObjectType* object,
+                            MethodType method,
+                            const ParamType1& x1)
+        : wxAsyncMethodCallEvent(object),
+          m_object(object),
+          m_method(method),
+          m_param1(x1)
+    {
+    }
+
+    wxAsyncMethodCallEvent1(const wxAsyncMethodCallEvent1& other)
+        : wxAsyncMethodCallEvent(other),
+          m_object(other.m_object),
+          m_method(other.m_method),
+          m_param1(other.m_param1)
+    {
+    }
+
+    virtual wxEvent *Clone() const
+    {
+        return new wxAsyncMethodCallEvent1(*this);
+    }
+
+    virtual void Execute()
+    {
+        (m_object->*m_method)(m_param1);
+    }
+
+private:
+    ObjectType* const m_object;
+    const MethodType m_method;
+    const ParamType1 m_param1;
+};
+
+// This is a version for calling methods with two parameters.
+template <typename T, typename T1, typename T2>
+class wxAsyncMethodCallEvent2 : public wxAsyncMethodCallEvent
+{
+public:
+    typedef T ObjectType;
+    typedef void (ObjectType::*MethodType)(T1 x1, T2 x2);
+    typedef typename wxRemoveRef<T1>::type ParamType1;
+    typedef typename wxRemoveRef<T2>::type ParamType2;
+
+    wxAsyncMethodCallEvent2(ObjectType* object,
+                            MethodType method,
+                            const ParamType1& x1,
+                            const ParamType2& x2)
+        : wxAsyncMethodCallEvent(object),
+          m_object(object),
+          m_method(method),
+          m_param1(x1),
+          m_param2(x2)
+    {
+    }
+
+    wxAsyncMethodCallEvent2(const wxAsyncMethodCallEvent2& other)
+        : wxAsyncMethodCallEvent(other),
+          m_object(other.m_object),
+          m_method(other.m_method),
+          m_param1(other.m_param1),
+          m_param2(other.m_param2)
+    {
+    }
+
+    virtual wxEvent *Clone() const
+    {
+        return new wxAsyncMethodCallEvent2(*this);
+    }
+
+    virtual void Execute()
+    {
+        (m_object->*m_method)(m_param1, m_param2);
+    }
+
+private:
+    ObjectType* const m_object;
+    const MethodType m_method;
+    const ParamType1 m_param1;
+    const ParamType2 m_param2;
+};
+
 #if wxUSE_GUI
 
 
@@ -3137,6 +3294,44 @@ public:
         // NOTE: uses AddPendingEvent(); call only from secondary threads
 #endif
 
+    // Asynchronous method calls: these methods schedule the given method
+    // pointer for a later call (during the next idle event loop iteration).
+    //
+    // Notice that the method is called on this object itself, so the object
+    // CallAfter() is called on must have the correct dynamic type.
+    //
+    // These method can be used from another thread.
+
+    template <typename T>
+    void CallAfter(void (T::*method)())
+    {
+        QueueEvent(
+            new wxAsyncMethodCallEvent0<T>(static_cast<T*>(this), method)
+        );
+    }
+
+    // Notice that we use P1 and not T1 for the parameter to allow passing
+    // parameters that are only convertible to the type taken by the method
+    // instead of being exactly the same, to be closer to the usual method call
+    // semantics.
+    template <typename T, typename T1, typename P1>
+    void CallAfter(void (T::*method)(T1 x1), P1 x1)
+    {
+        QueueEvent(
+            new wxAsyncMethodCallEvent1<T, T1>(
+                static_cast<T*>(this), method, x1)
+        );
+    }
+
+    template <typename T, typename T1, typename T2, typename P1, typename P2>
+    void CallAfter(void (T::*method)(T1 x1, T2 x2), P1 x1, P2 x2)
+    {
+        QueueEvent(
+            new wxAsyncMethodCallEvent2<T, T1, T2>(
+                static_cast<T*>(this), method, x1, x2)
+        );
+    }
+
 
     // Connecting and disconnecting
     // ----------------------------
index 3946f05f998b2902bb97b48e5d87ddcb20a7d876..3aae72f4a130b81c61f9bfddce93240c715b4048 100644 (file)
@@ -477,6 +477,53 @@ public:
     */
     virtual void AddPendingEvent(const wxEvent& event);
 
+    /**
+         Asynchronously call the given method.
+
+         Calling this function on an object schedules an asynchronous call to
+         the method specified as CallAfter() argument at a (slightly) later
+         time. This is useful when processing some events as certain actions
+         typically can't be performed inside their handlers, e.g. you shouldn't
+         show a modal dialog from a mouse click event handler as this would
+         break the mouse capture state -- but you can call a method showing
+         this message dialog after the current event handler completes.
+
+         The method being called must be the method of the object on which
+         CallAfter() itself is called.
+
+         Notice that it is safe to use CallAfter() from other, non-GUI,
+         threads, but that the method will be always called in the main, GUI,
+         thread context.
+
+         Example of use:
+         @code
+         class MyFrame : public wxFrame {
+            void OnClick(wxMouseEvent& event) {
+                CallAfter(&MyFrame::ShowPosition, event.GetPosition());
+            }
+
+            void ShowPosition(const wxPoint& pos) {
+                if ( wxMessageBox(
+                        wxString::Format("Perform click at (%d, %d)?",
+                                         pos.x, pos.y), "", wxYES_NO) == wxYES )
+                {
+                    ... do take this click into account ...
+                }
+            }
+         };
+         @endcode
+
+         @param method The method to call.
+         @param x1 The (optional) first parameter to pass to the method.
+         @param x2 The (optional) second parameter to pass to the method.
+
+         Note that currently only up to 2 arguments can be passed.
+
+         @since 2.9.5
+     */
+    template<typename T, typename T1, ...>
+    void CallAfter(void (T::*method)(T1, ...), T1 x1, ...);
+
     /**
         Processes an event, searching event tables and calling zero or more suitable
         event handler function(s).
index fa39ae924b710be0f4f55c234150b8a4f0776c58..07e5fc334107eb4ea19208e9a09fd3824a1137e4 100644 (file)
@@ -156,8 +156,9 @@ const wxEventType wxEVT_NULL = wxNewEventType();
 
 wxDEFINE_EVENT( wxEVT_IDLE, wxIdleEvent );
 
-// Thread event
+// Thread and asynchronous call events
 wxDEFINE_EVENT( wxEVT_THREAD, wxThreadEvent );
+wxDEFINE_EVENT( wxEVT_ASYNC_METHOD_CALL, wxAsyncMethodCallEvent );
 
 #endif // wxUSE_BASE
 
@@ -1564,6 +1565,15 @@ bool wxEvtHandler::TryHereOnly(wxEvent& event)
     if ( GetEventHashTable().HandleEvent(event, this) )
         return true;
 
+    // There is an implicit entry for async method calls procession in every
+    // event handler:
+    if ( event.GetEventType() == wxEVT_ASYNC_METHOD_CALL &&
+            event.GetEventObject() == this )
+    {
+        static_cast<wxAsyncMethodCallEvent&>(event).Execute();
+        return true;
+    }
+
     // We don't have a handler for this event.
     return false;
 }