mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-06 03:50:06 +01:00
SIP now does the RightThing with __[sg]etattr__ methods, so use them to provide a simpler implementation for wx.PyEvent and wx.PyCommandEvent. Put any attributes set from Python into a separate dictionary object, and copy that dictionary in Clone().
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@66489 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
248
src/pyevent.sip
248
src/pyevent.sip
@@ -1,4 +1,4 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////
|
//--------------------------------------------------------------------------
|
||||||
// Name: pyevent.sip
|
// Name: pyevent.sip
|
||||||
// Purpose: A set of event classes that can be derived from in Python
|
// Purpose: A set of event classes that can be derived from in Python
|
||||||
// and that preserve their attributes when cloned.
|
// and that preserve their attributes when cloned.
|
||||||
@@ -8,145 +8,185 @@
|
|||||||
// Created: 18-Dec-2010
|
// Created: 18-Dec-2010
|
||||||
// Copyright: (c) 2010 by Total Control Software
|
// Copyright: (c) 2010 by Total Control Software
|
||||||
// Licence: wxWindows license
|
// Licence: wxWindows license
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
// These Event classes can be derived from in Python and passed through the
|
// The wxPyEvent and wxPyCommandEvent classes can be derived from in Python
|
||||||
// event system without loosing anything. They do this by copying any
|
// and passed through the event system without losing anything.
|
||||||
// attributes added to the Python object for the original event over to the
|
|
||||||
// new cloned event in the Clone method.
|
%ModuleHeaderCode
|
||||||
|
// This class holds a Python dictionary object and is used to store any
|
||||||
|
// attributes that are set from Python code for the wx.PyEvent and
|
||||||
|
// wx.PyCommandEvent classes. This dictionary is used to make it easy to
|
||||||
|
// transport those attributes over to the clone when wx needs to make a copy
|
||||||
|
// of the event instance.
|
||||||
|
|
||||||
|
// NOTE: This class is intentionally not exposed to SIP (see wxPyEvent
|
||||||
|
// and wxPyCommandEvent)
|
||||||
|
class wxPyEvtDict
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
wxPyEvtDict()
|
||||||
|
{
|
||||||
|
m_dict = PyDict_New();
|
||||||
|
}
|
||||||
|
|
||||||
|
wxPyEvtDict(const wxPyEvtDict& other)
|
||||||
|
{
|
||||||
|
m_dict = PyDict_Copy(other.m_dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
~wxPyEvtDict()
|
||||||
|
{
|
||||||
|
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||||
|
Py_DECREF(m_dict);
|
||||||
|
m_dict = NULL;
|
||||||
|
wxPyEndBlockThreads(blocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* _getDict()
|
||||||
|
{
|
||||||
|
Py_INCREF(m_dict);
|
||||||
|
return m_dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* __getattr__(PyObject* name)
|
||||||
|
{
|
||||||
|
PyObject* value = NULL;
|
||||||
|
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||||
|
if (PyDict_Contains(m_dict, name)) {
|
||||||
|
value = PyDict_GetItem(m_dict, name);
|
||||||
|
Py_INCREF(value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_SetObject(PyExc_AttributeError, name);
|
||||||
|
}
|
||||||
|
wxPyEndBlockThreads(blocked);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __setattr__(PyObject* name, PyObject* value)
|
||||||
|
{
|
||||||
|
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||||
|
PyDict_SetItem(m_dict, name, value);
|
||||||
|
wxPyEndBlockThreads(blocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __delattr__(PyObject* name)
|
||||||
|
{
|
||||||
|
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||||
|
if (PyDict_Contains(m_dict, name))
|
||||||
|
PyDict_DelItem(m_dict, name);
|
||||||
|
else
|
||||||
|
PyErr_SetObject(PyExc_AttributeError, name);
|
||||||
|
wxPyEndBlockThreads(blocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PyObject* m_dict;
|
||||||
|
};
|
||||||
|
%End
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
// TODO: Use this comment for a docstring
|
class wxPyEvent : wxEvent
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
wx.PyEvent can be used as a base class for implementing custom event types
|
||||||
|
in Python. You should derive from this class instead of `wx.Event` because
|
||||||
|
this class is Python-aware and is able to transport its Python bits safely
|
||||||
|
through the wxWidgets event system and have them still be there when the
|
||||||
|
event handler is invoked. Note that since wx.PyEvent is taking care of
|
||||||
|
preserving the extra attributes that have been set then you do not need to
|
||||||
|
implement the Clone method in your derived classes.
|
||||||
|
|
||||||
// wx.PyEvent can be used as a base class for implementing custom event
|
:see: `wx.PyCommandEvent`
|
||||||
// types in Python. You should derive from this class instead of
|
%End
|
||||||
// `wx.Event` because this class is Python-aware and is able to transport
|
// first declare the C++ version of the class
|
||||||
// its Python bits safely through the wxWidgets event system and have
|
|
||||||
// them still be there when the event handler is invoked.
|
|
||||||
// :see: `wx.PyCommandEvent`
|
|
||||||
class wxPyEvent : wxEvent {
|
|
||||||
%TypeCode
|
%TypeCode
|
||||||
class wxPyEvent : public wxEvent
|
class wxPyEvent : public wxEvent, public wxPyEvtDict
|
||||||
{
|
{
|
||||||
DECLARE_DYNAMIC_CLASS(wxPyEvent)
|
DECLARE_DYNAMIC_CLASS(wxPyEvent)
|
||||||
public:
|
public:
|
||||||
wxPyEvent(int winid=0, wxEventType commandType = wxEVT_NULL)
|
wxPyEvent(int id=0, wxEventType eventType = wxEVT_NULL)
|
||||||
: wxEvent(winid, commandType) {}
|
: wxEvent(id, eventType) {}
|
||||||
|
|
||||||
// Create a new instance of the Python object for the cloned event,
|
virtual wxEvent* Clone() const { return new wxPyEvent(*this); }
|
||||||
// and then copy the attributes from the original Python instance to
|
|
||||||
// the clone.
|
|
||||||
virtual wxEvent* Clone() const
|
|
||||||
{
|
|
||||||
wxPyEvent* newEvent = new wxPyEvent(*this);
|
|
||||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
|
||||||
PyObject* thisObj = sipGetPyObject((void*)this, sipType_wxPyEvent);
|
|
||||||
PyObject* newObj = sipConvertFromType((void*)newEvent,
|
|
||||||
sipType_wxPyEvent,
|
|
||||||
NULL);
|
|
||||||
PyObject* newDict = PyObject_GetAttrString(newObj, "__dict__");
|
|
||||||
PyObject* thisDict = PyObject_GetAttrString(thisObj, "__dict__");
|
|
||||||
PyDict_Update(newDict, thisDict);
|
|
||||||
Py_DECREF(newDict);
|
|
||||||
Py_DECREF(thisDict);
|
|
||||||
wxPyEndBlockThreads(blocked);
|
|
||||||
return newEvent;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxPyEvent, wxEvent);
|
IMPLEMENT_DYNAMIC_CLASS(wxPyEvent, wxEvent);
|
||||||
%End
|
%End
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxPyEvent(int winid=0, wxEventType eventType = wxEVT_NULL );
|
wxPyEvent(int id=0, wxEventType eventType = wxEVT_NULL );
|
||||||
|
virtual wxEvent* Clone() const /Factory/;
|
||||||
virtual wxEvent* Clone() const /Factory, NoArgParser/;
|
|
||||||
|
SIP_PYOBJECT __getattr__(SIP_PYOBJECT name);
|
||||||
%MethodCode
|
%MethodCode
|
||||||
PyObject *sipParseErr = NULL;
|
sipRes = sipCpp->__getattr__(name);
|
||||||
bool sipSelfWasArg = (!sipSelf || sipIsDerived((sipSimpleWrapper *)sipSelf));
|
%End
|
||||||
wxPyEvent *sipCpp;
|
|
||||||
if (sipParseArgs(&sipParseErr, sipArgs, "B", &sipSelf, sipType_wxPyEvent, &sipCpp))
|
void __setattr__(SIP_PYOBJECT name, SIP_PYOBJECT value);
|
||||||
{
|
%MethodCode
|
||||||
wxEvent *sipRes;
|
sipCpp->__setattr__(name, value);
|
||||||
sipRes = (sipSelfWasArg ? sipCpp->wxPyEvent::Clone() : sipCpp->Clone());
|
%End
|
||||||
// Note that this MethodCode is nearly identical to what is normally generated,
|
|
||||||
// except for the following lines. wxPyEvent::Clone already made a PyObject,
|
void __delattr__(SIP_PYOBJECT name);
|
||||||
// so just fetch it.
|
%MethodCode
|
||||||
PyObject* obj = sipGetPyObject(sipRes, sipType_wxPyEvent);
|
sipCpp->__delattr__(name);
|
||||||
sipTransferBack(obj);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
sipNoMethod(sipParseErr, sipName_PyEvent, sipName_Clone, NULL); //doc_wxPyEvent_Clone);
|
|
||||||
return NULL;
|
|
||||||
%End
|
%End
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// wx.PyCommandEvent can be used as a base class for implementing custom
|
class wxPyCommandEvent : wxCommandEvent
|
||||||
// event types in Python, where the event should travel up to parent
|
{
|
||||||
// windows looking for a handler. You should derived from this class
|
%Docstring
|
||||||
// instead of `wx.CommandEvent` because this class is Python-aware and is
|
wx.PyCommandEvent can be used as a base class for implementing custom event types
|
||||||
// able to transport its Python bits safely through the wxWidgets event
|
in Python. You should derive from this class instead of `wx.CommandEvent` because
|
||||||
// system and have them still be there when the event handler is invoked.
|
this class is Python-aware and is able to transport its Python bits safely
|
||||||
// :see: `wx.PyEvent`
|
through the wxWidgets event system and have them still be there when the
|
||||||
class wxPyCommandEvent : wxCommandEvent {
|
event handler is invoked. Note that since wx.PyCommandEvent is taking care of
|
||||||
|
preserving the extra attributes that have been set then you do not need to
|
||||||
|
implement the Clone method in your derived classes.
|
||||||
|
|
||||||
|
:see: `wx.PyEvent`
|
||||||
|
%End
|
||||||
|
// first declare the C++ version of the class
|
||||||
%TypeCode
|
%TypeCode
|
||||||
class wxPyCommandEvent : public wxCommandEvent
|
class wxPyCommandEvent : public wxCommandEvent, public wxPyEvtDict
|
||||||
{
|
{
|
||||||
DECLARE_DYNAMIC_CLASS(wxPyCommandEvent)
|
DECLARE_DYNAMIC_CLASS(wxPyCommandEvent)
|
||||||
public:
|
public:
|
||||||
wxPyCommandEvent(wxEventType eventType = wxEVT_NULL, int id=0)
|
wxPyCommandEvent(wxEventType eventType = wxEVT_NULL, int id=0)
|
||||||
: wxCommandEvent(eventType, id) {}
|
: wxCommandEvent(eventType, id) {}
|
||||||
|
|
||||||
// Create a new instance of the Python object for the cloned event,
|
virtual wxEvent* Clone() const { return new wxPyCommandEvent(*this); }
|
||||||
// and then copy the attributes from the original Python instance to
|
|
||||||
// the clone.
|
|
||||||
virtual wxEvent* Clone() const
|
|
||||||
{
|
|
||||||
wxPyCommandEvent* newEvent = new wxPyCommandEvent(*this);
|
|
||||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
|
||||||
PyObject* thisObj = sipGetPyObject((void*)this, sipType_wxPyCommandEvent);
|
|
||||||
PyObject* newObj = sipConvertFromNewType((void*)newEvent,
|
|
||||||
sipType_wxPyCommandEvent,
|
|
||||||
NULL);
|
|
||||||
PyObject* newDict = PyObject_GetAttrString(newObj, "__dict__");
|
|
||||||
PyObject* thisDict = PyObject_GetAttrString(thisObj, "__dict__");
|
|
||||||
PyDict_Update(newDict, thisDict);
|
|
||||||
Py_DECREF(newDict);
|
|
||||||
Py_DECREF(thisDict);
|
|
||||||
wxPyEndBlockThreads(blocked);
|
|
||||||
return newEvent;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent, wxCommandEvent);
|
IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent, wxCommandEvent);
|
||||||
%End
|
%End
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxPyCommandEvent(wxEventType eventType = wxEVT_NULL, int id=0);
|
wxPyCommandEvent(wxEventType eventType = wxEVT_NULL, int id=0);
|
||||||
|
virtual wxEvent* Clone() const /Factory/;
|
||||||
virtual wxEvent* Clone() const /Factory, NoArgParser/;
|
SIP_PYOBJECT _getDict();
|
||||||
|
|
||||||
|
SIP_PYOBJECT __getattr__(SIP_PYOBJECT name);
|
||||||
%MethodCode
|
%MethodCode
|
||||||
PyObject *sipParseErr = NULL;
|
sipRes = sipCpp->__getattr__(name);
|
||||||
bool sipSelfWasArg = (!sipSelf || sipIsDerived((sipSimpleWrapper *)sipSelf));
|
%End
|
||||||
wxPyCommandEvent *sipCpp;
|
|
||||||
if (sipParseArgs(&sipParseErr, sipArgs, "B", &sipSelf, sipType_wxPyCommandEvent, &sipCpp))
|
void __setattr__(SIP_PYOBJECT name, SIP_PYOBJECT value);
|
||||||
{
|
%MethodCode
|
||||||
wxEvent *sipRes;
|
sipCpp->__setattr__(name, value);
|
||||||
sipRes = (sipSelfWasArg ? sipCpp->wxPyCommandEvent::Clone() : sipCpp->Clone());
|
%End
|
||||||
// Note that this MethodCode is nearly identical to what is normally generated,
|
|
||||||
// except for the following lines. wxPyCommandEvent::Clone already made a PyObject,
|
void __delattr__(SIP_PYOBJECT name);
|
||||||
// so just fetch it.
|
%MethodCode
|
||||||
PyObject* obj = sipGetPyObject(sipRes, sipType_wxPyCommandEvent);
|
sipCpp->__delattr__(name);
|
||||||
sipTransferBack(obj);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
sipNoMethod(sipParseErr, sipName_PyCommandEvent, sipName_Clone, NULL); //doc_wxPyEvent_Clone);
|
|
||||||
return NULL;
|
|
||||||
%End
|
%End
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Temporary testing code, get rid of this later
|
// TODO: Temporary testing code, get rid of this later
|
||||||
%ModuleCode
|
%ModuleCode
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class PyEvents(unittest2.TestCase):
|
|||||||
rc2 = sys.getrefcount(evt2)
|
rc2 = sys.getrefcount(evt2)
|
||||||
rc3 = sys.getrefcount(evt1)
|
rc3 = sys.getrefcount(evt1)
|
||||||
#print '\n****', rc1, rc2, rc3
|
#print '\n****', rc1, rc2, rc3
|
||||||
##self.assertTrue(rc1 == rc2 == rc3) TODO: rc2 has an extra refcount. Why?
|
self.assertTrue(rc1 == rc2 == rc3)
|
||||||
self.assertTrue(evt1.attr == evt2.attr)
|
self.assertTrue(evt1.attr == evt2.attr)
|
||||||
|
|
||||||
#def test_AA(self):
|
#def test_AA(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user