diff --git a/etg/event.py b/etg/event.py index 0dcce309..dd355715 100644 --- a/etg/event.py +++ b/etg/event.py @@ -128,7 +128,7 @@ def run(): body="""\ success = 0 for et in self.evtType: - success += target.Disconnect(id1, id2, et, handler) + success += int(target.Disconnect(id1, id2, et, handler)) return success != 0 """), @@ -196,8 +196,7 @@ def run(): body="""\ if (PyCallable_Check(func)) { self->Connect(id, lastId, eventType, - (wxObjectEventFunction)(wxEventFunction) - &wxPyCallback::EventThunker, + (wxObjectEventFunction)&wxPyCallback::EventThunker, new wxPyCallback(func)); } else if (func == Py_None) { @@ -219,7 +218,7 @@ def run(): body="""\ if (func && func != Py_None) { // Find the current matching binder that has this function - // pointer and dissconnect that one. Unfortuneatly since we + // pointer and disconnect that one. Unfortunately since we // wrapped the PyObject function pointer in another object we // have to do the searching ourselves... wxList::compatibility_iterator node = self->GetDynamicEventTable()->GetFirst(); @@ -229,12 +228,15 @@ def run(): if ((entry->m_id == id) && ((entry->m_lastId == lastId) || (lastId == wxID_ANY)) && ((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) && - // FIXME? - //((entry->m_fn->IsMatching((wxObjectEventFunction)(wxEventFunction)&wxPyCallback::EventThunker))) && + entry->m_fn->IsMatching(wxObjectEventFunctor((wxObjectEventFunction)&wxPyCallback::EventThunker, NULL)) && (entry->m_callbackUserData != NULL)) { + wxPyThreadBlocker block; wxPyCallback *cb = (wxPyCallback*)entry->m_callbackUserData; - if (cb->m_func == func) { + // NOTE: Just comparing PyObject pointers is not enough, as bound + // methods can result in different PyObjects each time obj.Method + // is evaluated. (!!!) + if (PyObject_RichCompareBool(cb->m_func, func, Py_EQ) == 1) { delete cb; self->GetDynamicEventTable()->Erase(node); delete entry; @@ -247,8 +249,7 @@ def run(): } else { return self->Disconnect(id, lastId, eventType, - (wxObjectEventFunction) - &wxPyCallback::EventThunker); + (wxObjectEventFunction)&wxPyCallback::EventThunker); } """) diff --git a/unittests/test_event.py b/unittests/test_event.py index c4e4f22a..d4d2f657 100644 --- a/unittests/test_event.py +++ b/unittests/test_event.py @@ -1,10 +1,11 @@ import unittest +from unittests import wtc import wx #--------------------------------------------------------------------------- -class Events(unittest.TestCase): +class Events(wtc.WidgetTestCase): # Test the constructors to make sure the classes are not abstract, except # for wx.Event @@ -45,7 +46,6 @@ class Events(unittest.TestCase): evt = wx.FocusEvent() def test_HelpEvent_ctor(self): - app = wx.App() evt = wx.HelpEvent() def test_IconizeEvent_ctor(self): @@ -138,14 +138,88 @@ class Events(unittest.TestCase): def OnSize(self, evt): self.gotEvent = True evt.EventObject.Close() - app = wx.App() frm = Frame(None) frm.Show() frm.SetSize((200,100)) - #app.MainLoop() + self.myYield() self.assertTrue(frm.gotEvent) + def test_eventUnbinding1(self): + "Unbind without specifying handler" + self.gotEvent = False + + def _onSize(evt): + self.gotEvent = True + + self.frame.Bind(wx.EVT_SIZE, _onSize) + val = self.frame.Unbind(wx.EVT_SIZE) + assert val, "Unbind returned false" + + self.frame.SetSize((200,200)) + self.myYield() + assert not self.gotEvent, "Expected gotEvent to still be False" + + + def test_eventUnbinding2(self): + "Unbind with specifying handler, simple function object" + self.gotEvent = False + + def _onSize(evt): + self.gotEvent = True + + self.frame.Bind(wx.EVT_SIZE, _onSize) + val = self.frame.Unbind(wx.EVT_SIZE, handler=_onSize) + assert val, "Unbind returned False" + + self.frame.SetSize((200,200)) + self.myYield() + assert not self.gotEvent, "Expected gotEvent to still be False" + + + def test_eventUnbinding3(self): + "Unbind with specifying handler, a bound method" + + class Frame(wx.Frame): + def __init__(self, *args, **kw): + wx.Frame.__init__(self, *args, **kw) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.gotEvent = False + self.obj = self.OnSize + + def doUnBind(self): + #assert id(self.obj) != id(self.OnSize) # Strange, but it's possible + val = self.Unbind(wx.EVT_SIZE, handler=self.OnSize) + assert val, "Unbind returned False" + + def OnSize(self, evt): + self.gotEvent = True + evt.EventObject.Close() + + frm = Frame(None) + frm.doUnBind() + frm.Show() + frm.SetSize((200,100)) + self.myYield() + assert not frm.gotEvent, "Expected gotEvent to still be False" + + + def test_eventUnbinding4(self): + "Unbind by passing None to Bind()" + self.gotEvent = False + + def _onSize(evt): + self.gotEvent = True + + self.frame.Bind(wx.EVT_SIZE, _onSize) + self.frame.Bind(wx.EVT_SIZE, None) + + self.frame.SetSize((200,200)) + self.myYield() + assert not self.gotEvent, "Expected gotEvent to still be False" + + + def test_DropFilesEvent_tweaks(self): evt = wx.DropFilesEvent(123, 'one two three four five'.split()) self.assertTrue(evt.NumberOfFiles == 5)