Grid table problems

I’m sure this will turn out to be a simple problem, but I can’t seem to figure it out.

I have a grid and a table.
Table implements a list of rows, and implements GetNumberRows() as len(therows).
Table implements InsertRows() as inserting a row in the data list and return True

The grid initializes and displays correctly with correct number of rows.

The problem is that grid does not update correctly on InsertRows(). What I see is that the blank row is inserted, rows are shifted down correctly, but last row falls off the grid because grid did not add a row to the display. I verified in a debugger that the data is correctly updated in the table, in this case the number of rows went from 21 to 22 and there is an empty default row at the correct location.

Behavior is as if grid.ForceRefresh() did not query table.GetNumberRows() to determine how many rows should be displayed.

Here is code in my grid class for inserting a row:

def rowInsertAt(self, row):

    if row < 0:
        return
    print self.grid.Table.GetNumberRows()    <--- prints 21, correct
    ok = self.grid.InsertRows(row, 1)
    self.grid.ForceRefresh()
    print self.grid.Table.GetNumberRows()    <--- prints 22, correct

Here is supporting code in table:

def GetNumberRows(self):
    return len(self._data)

def InsertRows(self, row, n):  
    self._data[row:row] = [self._default_row] * n

    return True
···


Mike Conley

Here is a full example illustrating the problem

http://pastebin.com/m306cb144

···


Mike Conley

Here is a qick fix, I'm not sure if this is how you are supposed to do
it but it works.

Don't take ownership of the table in SetTable and call SetTable before
ForceRefresh

[...]
    def __init__(self):
        wx.Frame.__init__(self, None, title="Grid Headers",
                          size=(500,200))
        self.grid = wx.grid.Grid(self)
        self.table = MyTable()
        self.grid.SetTable(self.table)
[...]
    def rowInsertAt(self, row):
        if row < 0:
            return
        self.grid.InsertRows(row, 1)
        self.grid.SetTable(self.table)
        self.grid.ForceRefresh()

    def rowDelete(self, evt):
        row, col = self.gridpos
        if row < 0:
            return
        self.grid.DeleteRows(row, 1)
        self.grid.SetTable(self.table)
        self.grid.ForceRefresh()
[...]

Mike Conley wrote:

I'm sure this will turn out to be a simple problem, but I
can't seem to figure it out.

I have a grid and a table.
Table implements a list of rows, and implements
GetNumberRows() as len(therows).
Table implements InsertRows() as inserting a row in the data
list and return True

The grid initializes and displays correctly with correct
number of rows.

The problem is that grid does not update correctly on
InsertRows(). What I see is that the blank row is inserted,
rows are shifted down correctly, but last row falls off the
grid because grid did not add a row to the display. I
verified in a debugger that the data is correctly updated in
the table, in this case the number of rows went from 21 to 22
and there is an empty default row at the correct location.

There is an extra step you have to take, but I have never seen it in any
formal documentation. The only place I have seen it is in some of the Grid
examples in the demo.

After appending, inserting, or deleting rows (or columns) in the table, you
must notify the grid of the change, like this -

    import wx.grid as gridlib

    msg = gridlib.GridTableMessage(self, # The table
          gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED, # what we did to it
          1 # how many
          )

or

    msg = gridlib.GridTableMessage(self, # The table
          gridlib.GRIDTABLE_NOTIFY_ROWS_INSERTED, # what we did to it
          5, # from which row
          1 # how many
          )

or

    msg = gridlib.GridTableMessage(self, # The table
          gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, # what we did to it
          5, # from which row
          1 # how many
          )

followed by

    self.GetView().ProcessTableMessage(msg)

This assumes that it is called from the Table class.

If it is called from the Grid class, change self to self.GetTable(), and
self.GetView() to self.

HTH

Frank Millman

And it works!!!

For those interested, here is change I put in the MyTable class. With this change, ForceRefresh() was no longer needed in the grid logic either since EndBatch() will do that.

def InsertRows(self, row, n):

    self.rowLabels.insert(row, "")
   

    # notify the grid about change
    grid = self.GetView()

    grid.BeginBatch()
    msg = wx.grid.GridTableMessage(

            self, wx.grid.GRIDTABLE_NOTIFY_ROWS_INSERTED, row, n
            )

    grid.ProcessTableMessage(msg)
    grid.EndBatch()

   
    return True


def DeleteRows(self, row, n):

    for i in range(n):
        del self.rowLabels[row]

   
    # notify the grid about change

    grid = self.GetView()
    grid.BeginBatch()

    msg = wx.grid.GridTableMessage(
            self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, row, n

            )
    grid.ProcessTableMessage(msg)

    grid.EndBatch()
   

    return True
···