wxGrid, PyGridTableBase, strange SWIG error message!

I'm trying to create a special widget that is a Grid and also a
PyGridTableBase. In my special case of application, I really need to
have a grid that uses itself for getting cell data and cell
attributes.

Here is a test program, demonstrating my problem:

import wx
from wx.grid import Grid,PyGridTableBase

class SpecialGrid(Grid,PyGridTableBase):
    def __init__(self,*args,**kwargs):
        PyGridTableBase.__init__(self)
        Grid.__init__(self,*args,**kwargs)
        self.SetTable(self)

    def SetTable(self,table):
        if table is not self:
            raise Exception("Grid must be its own table!")
        else:
            PyGridTableBase.SetTable(self,self,takeOwnership=False)

app=wx.App(redirect=None)
frame=wx.Frame(None)
g = SpecialGrid(parent=frame)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(g,1,wx.EXPAND)
frame.SetSizer(sizer)
frame.Show()
frame.Maximize()
app.MainLoop()

This program throws:

Traceback (most recent call last):
  File "test.py", line 18, in <module>
    g = SpecialGrid(parent=frame)
  File "test.py", line 6, in __init__
    PyGridTableBase.__init__(self)
  File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/
grid.py", line 910, in __init__
    self._setOORInfo(self);PyGridTableBase._setCallbackInfo(self,
self, PyGridTableBase)
  File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/
_core.py", line 3886, in _setOORInfo
    val = _core_.EvtHandler__setOORInfo(*args, **kwargs)
TypeError: in method 'EvtHandler__setOORInfo', expected argument 1 of
type 'wxEvtHandler *'

This makes no sense to me. If I swap the constructor calls:

    def __init__(self,*args,**kwargs):
        Grid.__init__(self,*args,**kwargs)
        PyGridTableBase.__init__(self)
        self.SetTable(self)

Then I get this:

Traceback (most recent call last):
  File "test.py", line 18, in <module>
    g = SpecialGrid(parent=frame)
  File "test.py", line 7, in __init__
    PyGridTableBase.__init__(self)
  File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/
grid.py", line 910, in __init__
    self._setOORInfo(self);PyGridTableBase._setCallbackInfo(self,
self, PyGridTableBase)
  File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/
_core.py", line 3887, in _setOORInfo
    args[0].this.own(False)
  File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/
_core.py", line 14586, in __getattr__
    raise PyDeadObjectError(self.attrStr % self._name)
wx._core.PyDeadObjectError: The C++ part of the SpecialGrid object has
been deleted, attribute access no longer allowed.

What the heck?

Background information: this special grid has special renderers that
create multiple labels for the grid for every row and column. The
styles of these "extra" labels are controlled by several methods The
data that is needed to build the header labels are implemented with
several data access methods. Within the same grid, different cells
need to have different styles, depending on various conditions that
I'm not going to explain here. Unfortunately, cell level data access
and attribute access methods are defined in PyGridTableBase. So there
are methods that are used for styling and the methods that are used
for virtual data table implementation. They are mixed in two classes:
Grid and PyGridTableBase. My goal is to create mixin classes that can
implement "styling" and "data access" in different ways. For example,
one mixin class that does styling by a CSS file. Another class that
does styling by special attributes stored in a file etc. But because
style/attribute access methods are defined in both Grid and
PyGridTableBase, first I need to create a special grid class that
uses itself as its table, and has all methods from both Grid and
PyGridTableBase (plus the ones needed for the extra renderers).

How do I do that? Apparently, inheriting from Grid + PyGridTableBase
doesn't work.

Pseudo code for my imaginary class hierarchy:

class specialgrid( grid, pygridtablebase):
  """special grid that uses itself as the table and has methods for
extra renderers too"""
  def specgetattr1():
  def specgetattr2():
  def specgetlabeldata():
  ...
  def getcellattr():
   ...

And then here is a mixin class for implementing styles as CSS:

class CSSSpecialStyleMixIn(object):
  """overrides methods for all attributes, including table/cell
attributes and special renderers"""
  def specgetattr1():
  def specgetattr2():
  def getcellattr():

And here is a mixin class that implements data access to header labels
AND grid cell data:

class Model1SpecialGridMixin():
  """overrides methods for all data, including table/cell values and
label values. uses a specific data model."""
   def specgetlabeldata():
      return data_from_model1
  def getcellvalue():
     return data_from_model1

etc.

If there cannot be a commin specialgrid class, then there cannot be
compact mixin classes - but I need them!

Thanks,

   Laszlo

I'm trying to create a special widget that is a Grid and also a
PyGridTableBase.

Multiple inheritance can be a trick -- for instance, you can not inherit from two different wx.Windows. I dont know if that's a problem per-se with PyGridTableBase, but it may be best to avoid it.

In my special case of application, I really need to
have a grid that uses itself for getting cell data and cell
attributes.

Does it HAVE to be itself? Or could you use a "has a" rather than a "is a" relationship -- i.e. have the PyGridTableBase be a attribute of your custom grid.

It's wouldn't change much really:

class SpecialGrid(Grid):
       def __init__(self, *args,**kwargs):
           Grid.__init__(self,*args,**kwargs)
           self.Table = PyGridTableBase()

Then you may have to re-direct some Grid methods to self.Table:

     def A_method(self, *args, **kwargs):
  return self.Table.A_method(*args, **kwargs)

-Chris

···

On 5/6/11 9:45 AM, nagylzs wrote:

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Then you may have to re-direct some Grid methods to self.Table:

def A_method(self, *args, **kwargs):

    return self.Table.A_method(*args, **kwargs)

This won’t work because sometimes “A_method” is a built-in method of PyGridTableBase. For example, how would you do this for PyGridTableBase.GetAttr ? This won’t work:

class SpecialGrid(Grid):

  def __init__(self, *args,**kwargs):

      Grid.__init__(self,*args,**kwargs)

self.Table = PyGridTableBase()

 def GetAttr(self,*args,**kwargs):
     return self.Table.GetAttr(*args,**kwargs)

Because:

class MyStyleMixIn(object):
def GetAttr(self,*args,**kwargs):

     do_something

class ExampleGrid(SpecialGrid,MyStyleMixIn):
pass

It does not matter what you put in MyStyleMixIn.GetAttr. It will never be called because it has to be the method of PyGridTableBase, not Grid! It is called from the C++ code and we cannot change it.

Of course I can create many many wrapper methods for all of the PyGridTableBase methods. Example:

class MyPyGridTable(PyGridTableBase):
def init(self,grid,*args,**kwargs):
self._grid = grid
PyGridTableBase.init(self,*args,**kwargs)
def GetAttr(self,…):
return self._grid.GetAttr(…)

 def GetValue(self,...):
     return self._grid.GetValue(....)
 # etc needs at least 10 method wrappers here!

class class SpecialGrid(Grid):

  def __init__(self, *args,**kwargs):

      Grid.__init__(self,*args,**kwargs)

self._table = MyPyGridTable(self.)

 def GetAttr(self,...):
     raise NotImplemented

And finally:

class MyStyleMixIn(object):

 def GetAttr(self,*args,**kwargs):

I know that this WOULD work. But I did not want to do it unless I had to, because:

  • it is unpythonic - the natural way would be multiple inheritance.
  • full of method name repetitions
  • messy - instead of simply using multiple inheritance, I need to do wrapper methods. So I have to re-document every single one of them (because they are not “inherited”)

Well if there is no better way to do it, then I have to go this route.

Best,

Laszlo