views:

53

answers:

2

I have created a wx.grid.Grid with a wx.grid.PyGridTableBase derived class to provide its data. I want to also to control the editors used on the table. Towards that end I defined the following method

def GetAttr(self, row, col, kind):
    attr = wx.grid.GridCellAttr()
    if col == 0:
        attr.SetEditor( wx.grid.GridCellChoiceEditor() )
    return attr

However, this causes a segmentation fault whenever I attempt to created the editor in the grid. I did try creating the editor beforehand and passing it in as a parameter but received the error:

    TypeError: in method 'GridCellAttr_SetEditor', expected argument 2 of type 
'wxGridCellEditor *'

I suspect the second error is caused by the GridCellAttr taking ownership off and then destroying my editor.

I also tried using the SetDefaultEditor method on the wx.grid.Grid and that works, but naturally does not allow me to have a column specific editing strategy.

See Full Example of crashing program: http://pastebin.com/SEbhvaKf

A: 

This should solve it:

import wx
import wx.grid as gridlib

and change:

def GetAttr(self, row, col, kind):
    attr = gridlib.GridCellAttr()
    if col == 0:
        attr.SetEditor( gridlib.GridCellChoiceEditor() )
    return attr

Obs: I have no idea why you need to do it this way because:

>>> import wx
>>> attr = wx.grid.GridCellAttr()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'grid'

Do not work but:

import wx.grid as gridlib
attr = gridlib.GridCellAttr()

works... but:

print attr
<wx.grid.GridCellAttr; proxy of <wx.grid.GridCellAttr; proxy of <Swig Object of type 'wxGridCellAttr *' at 0x97cb398> > >

It says: <wx.grid.GridCellAttr; proxy of <wx.grid.GridCellAttr>...> !

Obs2: if you use the ChoiceEditor on the whole column 0, you could also define it only one time before showing the grid with:

attr.SetEditor( gridlib.GridCellChoiceEditor() )
yourGrid.SetColAttr(0, attr)

and you could remove all the code from the GetAttr method (I think it should be faster - but i never timed that).

laurent-rpnet
if you import wx.grid instead of just wx, then you won't get the attribute error.Other then changing the import style, I'm not seeing what you are doing differently that is supposed to fix it.Using SetColAttr works fine, and is a better way to do it, thanks. But I would like to know why I was getting segmentation faults...
Winston Ewert
Yes, exactly, the fix is to change the import style. As you can see in the console outputs, the objects from wx.grid do not work if you import `wx` instead of `wx.grid`. I don't know why because when imported, the object is listed as `wx.grid`. Anyways, this is always this way, not only in your case. You had the segmentation fault only when using the Editor because it had a wrong type or no type because not properly initialized with wx.grid.
laurent-rpnet
Changing the import style does not fix the problem. (Yes, I tried it to be sure)
Winston Ewert
http://pastebin.com/3z3PLh7a has my code after I applied your fix. It does not solve my segmentation faults at least for me. Perhaps you could try running it and seeing if it works there?
Winston Ewert
If you run the code in my answer, I think you'll see that your import as trick is unnecessary.
Winston Ewert
Sure your code works. It was not an import trick, it was only to say you need to import `wx.grid` instead of `wx` only. However, True, I forgot about the `IncRef()` needed when you return different `attr`. I use it like `attr.IncRef()` in `GetAttr()` before returning and without the 2 `self._editor.IncRef()` as I think it is a little more flexible allowing you to have other "different" attributes to add requiring to `IncRef()` without changing anything.
laurent-rpnet
I was always importing wx.grid, that had nothing to do with my segmentation fault.
Winston Ewert
Only the IncRef in GetAttr is actually needed in my sample, I'll remove the other one. As for calling IncRef() on on attr that is not a good idea. That will prevent the object from every being deallocated and be a memory leak.
Winston Ewert
+1  A: 

I figured out the problem:

The wxWidgets code assumes that the same Editor will be consistently returned from GetCellAttr. Returning a different editor each time as I was doing caused the segmentation faults.

In order to return the same editor multiple times I also need to call IncRef() on the editor to keep it alive.

For anybody else hitting the same problem in future, see my working code:

import wx.grid 

app = wx.PySimpleApp()

class Source(wx.grid.PyGridTableBase):
    def __init__(self):
        super(Source, self).__init__()
        self._editor = wx.grid.GridCellChoiceEditor()

    def IsEmptyCell(self, row, col):
        return False

    def GetValue(self, row, col):
        return repr( (row, col) )

    def SetValue(self, row, col, value):
        pass

    def GetNumberRows(self):
        return 5

    def GetNumberCols(self):
        return 5

    def GetAttr(self, row, col, kind):
        attr = wx.grid.GridCellAttr()
        self._editor.IncRef()
        attr.SetEditor( self._editor )
        return attr


frame = wx.Frame(None)
grid = wx.grid.Grid(frame)
grid.SetTable( Source() )
frame.Show()

app.MainLoop()
Winston Ewert