Python sequence wrappers for wxLists

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@46280 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2007-06-02 23:42:18 +00:00
parent 616fdc4311
commit eefcdd4b0f
6 changed files with 259 additions and 42 deletions

View File

@@ -1,6 +1,28 @@
Recent Changes for wxPython
=====================================================================
2.8.4.1
-------
*
Added some SWIG magic that allows wx C++ lists to be exposed to
wxPython as sqequence-like wrappers around the real list, instead of
making a Python list that is a copy of the real list as was done
before. These sequence-like objects support indexing, iteration and
containment tests ("obj in seq") but not anything that would modify the
sequence. If you need to have a real list object like before you can
pass the sequence to Python's list() function to convert it. Current
functions that are affected by this are wx.Window.GetChildren,
wx.GetTopLevelWindows, wx.Sizer.GetChildren, and
wx.Menu.GetMenuItems. Care should be taken to be sure that you don't
try to use the sequence after the C++ object the list belongs to has
been destroyed.
2.8.4.0
-------
* 14-May-2007

View File

@@ -408,6 +408,19 @@ typedef unsigned long wxUIntPtr;
%enddef
#endif
#ifdef _DO_FULL_DOCS
%define %RenameDocStr(newname, docstr, details, type, decl)
%feature("docstring") decl docstr;
%rename(newname) decl;
type decl
%enddef
#else
%define %RenameDocStr(newname, docstr, details, type, decl)
%feature("docstring") decl docstr details;
%rename(newname) decl;
type decl
%enddef
#endif
//---------------------------------------------------------------------------
// Generates a base_On* method that just wraps a call to the On*, and mark it
@@ -459,6 +472,204 @@ FORWARD_DECLARE(wxIcon, Icon);
FORWARD_DECLARE(wxStaticBox, StaticBox);
//---------------------------------------------------------------------------
// This macro makes a class to wrap a type specific class derived from wxList,
// and make it look like a Python sequence, including with iterator support
%define wxLIST_WRAPPER(ListClass, ItemClass)
// first a bit of C++ code...
%{
class ListClass##_iterator
{
public:
ListClass##_iterator(ListClass::compatibility_iterator start)
: m_node(start) {}
ItemClass* next() {
ItemClass* obj = NULL;
if (m_node) {
obj = m_node->GetData();
m_node = m_node->GetNext();
}
else PyErr_SetString(PyExc_StopIteration, "");
return obj;
}
private:
ListClass::compatibility_iterator m_node;
};
%}
// Now declare the classes for SWIG
DocStr(ListClass##_iterator,
"This class serves as an iterator for a ListClass object.", "");
class ListClass##_iterator
{
public:
//ListClass##_iterator();
~ListClass_iterator();
KeepGIL(next);
ItemClass* next();
};
DocStr(ListClass,
"This class wraps a wxList-based class and gives it a Python
sequence-like interface. Sequence operations supported are length,
index access and iteration.", "");
class ListClass
{
public:
//ListClass(); This will always be created by some C++ function
~ListClass();
%extend {
KeepGIL(__len__);
size_t __len__() {
return self->size();
}
KeepGIL(__getitem__);
ItemClass* __getitem__(size_t index) {
if (index < self->size()) {
ListClass::compatibility_iterator node = self->Item(index);
if (node) return node->GetData();
}
PyErr_SetString(PyExc_IndexError, "Invalid list index");
return NULL;
}
KeepGIL(__contains__);
bool __contains__(const ItemClass* obj) {
return self->Find(obj) != NULL;
}
KeepGIL(__iter__);
%newobject __iter__;
ListClass##_iterator* __iter__() {
return new ListClass##_iterator(self->GetFirst());
}
}
%pythoncode {
def __repr__(self):
return "ListClass: " + repr(list(self))
}
};
%enddef
// This macro is similar to the above, but it is to be used when there isn't a
// type-specific C++ list class to use. In other words the C++ code is using
// a plain wxList and typecasting the node values, so we'll do the same.
%define wxUNTYPED_LIST_WRAPPER(ListClass, ItemClass)
// first a bit of C++ code...
%{
class ListClass
{
public:
ListClass(wxList* theList)
: m_list(theList) {}
~ListClass() {}
public:
wxList* m_list;
};
class ListClass##_iterator
{
public:
ListClass##_iterator(wxList::compatibility_iterator start)
: m_node(start) {}
ItemClass* next() {
ItemClass* obj = NULL;
if (m_node) {
obj = (ItemClass*)m_node->GetData();
m_node = m_node->GetNext();
}
else PyErr_SetString(PyExc_StopIteration, "");
return obj;
}
private:
wxList::compatibility_iterator m_node;
};
%}
// Now declare the classes for SWIG
DocStr(ListClass##_iterator,
"This class serves as an iterator for a ListClass object.", "");
class ListClass##_iterator
{
public:
//ListClass##_iterator();
~ListClass_iterator();
KeepGIL(next);
ItemClass* next();
};
DocStr(ListClass,
"This class wraps a wxList-based class and gives it a Python
sequence-like interface. Sequence operations supported are length,
index access and iteration.", "");
class ListClass
{
public:
//ListClass(); This will always be created by some C++ function
~ListClass();
%extend {
KeepGIL(__len__);
size_t __len__() {
return self->m_list->size();
}
KeepGIL(__getitem__);
ItemClass* __getitem__(size_t index) {
if (index < self->m_list->size()) {
wxList::compatibility_iterator node = self->m_list->Item(index);
if (node) return (ItemClass*)node->GetData();
}
PyErr_SetString(PyExc_IndexError, "Invalid list index");
return NULL;
}
KeepGIL(__contains__);
bool __contains__(const ItemClass* obj) {
return self->m_list->Find(obj) != NULL;
}
KeepGIL(__iter__);
%newobject __iter__;
ListClass##_iterator* __iter__() {
return new ListClass##_iterator(self->m_list->GetFirst());
}
}
%pythoncode {
def __repr__(self):
return "ListClass: " + repr(list(self))
}
};
// A typemap to handle converting a wxList& return value to this new list
// type. To use this just change the return value type in the class
// definition to this typedef instead of wxList, then SWIG will use the
// typemap.
%{
typedef wxList ListClass##_t;
%}
%typemap(out) ListClass##_t& {
ListClass* mylist = new ListClass($1);
$result = SWIG_NewPointerObj(SWIG_as_voidptr(mylist), SWIGTYPE_p_##ListClass, SWIG_POINTER_OWN );
}
%enddef
//---------------------------------------------------------------------------
%{

View File

@@ -16,6 +16,9 @@
//---------------------------------------------------------------------------
%newgroup
wxLIST_WRAPPER(wxMenuItemList, wxMenuItem);
MustHaveApp(wxMenu);
@@ -169,12 +172,7 @@ public:
// get the items
size_t GetMenuItemCount() const;
%extend {
PyObject* GetMenuItems() {
wxMenuItemList& list = self->GetMenuItems();
return wxPy_ConvertList(&list);
}
}
wxMenuItemList& GetMenuItems();
// search
int FindItem(const wxString& item) const;

View File

@@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Name: _window.i
// Name: _panel.i
// Purpose: SWIG interface for wxPanel and wxScrolledWindow
//
// Author: Robin Dunn

View File

@@ -169,6 +169,11 @@ border size.", "");
};
//---------------------------------------------------------------------------
%newgroup
wxLIST_WRAPPER( wxSizerItemList, wxSizerItem );
DocStr(wxSizerItem,
"The wx.SizerItem class is used to track the position, size and other
@@ -1223,21 +1228,12 @@ as well.", "");
// wxList& GetChildren();
%extend {
DocAStr(GetChildren,
"GetChildren(self) -> list",
"Returns a list of all the `wx.SizerItem` objects managed by the sizer.", "");
PyObject* GetChildren() {
wxSizerItemList& list = self->GetChildren();
return wxPy_ConvertList(&list);
}
}
DocStr(GetChildren,
"Returns all of the `wx.SizerItem` objects managed by the sizer in a
list-like object.", "");
wxSizerItemList& GetChildren();
// Manage whether individual windows or subsizers are considered
// in the layout calculations or not.
%extend {
DocAStr(Show,
"Show(self, item, bool show=True, bool recursive=false) -> bool",

View File

@@ -24,6 +24,9 @@ MAKE_CONST_WXSTRING(PanelNameStr);
%newgroup
wxLIST_WRAPPER(wxWindowList, wxWindow);
DocStr(wxVisualAttributes,
"struct containing all the visual attributes of a control", "");
@@ -956,26 +959,16 @@ before win instead of putting it right after it.", "");
// parent/children relations
// -------------------------
//wxWindowList& GetChildren(); // TODO: Do a typemap or a wrapper for wxWindowList
%extend {
DocStr(GetChildren,
"Returns a list of the window's children. NOTE: Currently this is a
copy of the child window list maintained by the window, so the return
value of this function is only valid as long as the window's children
do not change.", "");
PyObject* GetChildren() {
wxWindowList& list = self->GetChildren();
return wxPy_ConvertList(&list);
}
}
"Returns an object containing a list of the window's children. The
object provides a Python sequence-like interface over the internal
list maintained by the window..", "");
wxWindowList& GetChildren();
DocDeclStr(
wxWindow *, GetParent() const,
@@ -2284,14 +2277,11 @@ MustHaveApp(wxWindow_FromHWND);
//---------------------------------------------------------------------------
DocStr(GetTopLevelWindows,
"Returns a list of the the application's top-level windows, (frames,
dialogs, etc.) NOTE: Currently this is a copy of the list maintained
by wxWidgets, and so it is only valid as long as no top-level windows
are closed or new top-level windows are created.
", "");
"Returns a list-like object of the the application's top-level windows, (frames,
dialogs, etc.)", "");
%inline %{
PyObject* GetTopLevelWindows() {
return wxPy_ConvertList(&wxTopLevelWindows);
wxWindowList& GetTopLevelWindows() {
return wxTopLevelWindows;
}
%}