wx.grid -- How to quickly display only those rows matching a criterion? -- correction

Please ignore my note (same subject line) of a few minutes ago, as there was a misnamed variable in the code I posted. That's corrected in this resend.

Bob

Bob Klahn wrote:

Let's say I have a wx.grid grid containing 2000 rows, with text strings in column 0.
The user can scroll through this grid, just like any other grid, =or= can press a certain key combo, say <ctrl-?>. and be prompted for a search string. Say that search string is found in a handful of those 1000 rows. The application must quickly show the user just those rows.
The user could then press <ctrl-?> again and specify a different search string, at which point the application must be able to quickly show just those rows. Selected from the full 1000-row grid, not just from the currently-displayed rows. All without flicker.
The question: What's the best way to accomplish the above?

Do the magic in your table class. When you process the filter the table can figure out which rows match and how many there are, tell the grid how many are in the result set, tell it to redraw, and then map the requests that the grid will make to the real values. For example if the first matching row is 5 then when the grid asks for the value of a cell in the 0th row your table would give it the value from the real 5th row instead, and so on.

Oh, of course, the grid table! A feature I haven't used before. So now I've converted my code to use a grid table, and it behaves as it should.

But now I'm trying to implement what you said above, and I'm missing one point: How do I "tell the grid how many are in the result set"? Let's say I have 200 rows in the grid table. So I specify a filter; let's say there are 10 matching rows. The 10 matching rows are displayed at the top, but the grid still thinks it has 200 rows, so I get index-out-of-range errors as it tries to repaint the 190 non-matching rows, which become blank cells.

Here's the relevant grid-table code:

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

     def GetValue(self,row,col):
         baserow = self.filter[row]
         return self.data[baserow][col]

     def Filter(self,search_str):
         self.filter =
         for row in range(len(self.data)):
             datum = self.data[row][0]
             if datum.upper().find(search_str) != -1:
                 self.filter.append(row)
         self.grid.ForceRefresh()

I thought GetNumberRows() would be called when self.grid.ForceRefresh() executes, but it's not.

What am I missing??

Bob

···

At 04:39 PM 1/30/2008, Robin Dunn wrote:

Thanks, Robin, that's what I needed; your code (which I've pulled in as a separate method) works like a charm. I'm sure glad you're here!

Bob

···

At 05:01 PM 1/31/2008, you wrote:

Bob Klahn wrote:

Please ignore my note (same subject line) of a few minutes ago, as there was a misnamed variable in the code I posted. That's corrected in this resend.
Bob
At 04:39 PM 1/30/2008, Robin Dunn wrote:

Bob Klahn wrote:

Let's say I have a wx.grid grid containing 2000 rows, with text strings in column 0.
The user can scroll through this grid, just like any other grid, =or= can press a certain key combo, say <ctrl-?>. and be prompted for a search string. Say that search string is found in a handful of those 1000 rows. The application must quickly show the user just those rows.
The user could then press <ctrl-?> again and specify a different search string, at which point the application must be able to quickly show just those rows. Selected from the full 1000-row grid, not just from the currently-displayed rows. All without flicker.
The question: What's the best way to accomplish the above?

Do the magic in your table class. When you process the filter the table can figure out which rows match and how many there are, tell the grid how many are in the result set, tell it to redraw, and then map the requests that the grid will make to the real values. For example if the first matching row is 5 then when the grid asks for the value of a cell in the 0th row your table would give it the value from the real 5th row instead, and so on.

Oh, of course, the grid table! A feature I haven't used before. So now I've converted my code to use a grid table, and it behaves as it should.
But now I'm trying to implement what you said above, and I'm missing one point: How do I "tell the grid how many are in the result set"? Let's say I have 200 rows in the grid table. So I specify a filter; let's say there are 10 matching rows. The 10 matching rows are displayed at the top, but the grid still thinks it has 200 rows, so I get index-out-of-range errors as it tries to repaint the 190 non-matching rows, which become blank cells.

The table needs to tell the grid how the table dimensions changed, and there is a GridTableMessage class to help do that. Unfortunately there isn't a nice simple message that tells the grid to redo everything, but there are messages to tell the grid that rows or columns have been inserted, appended or deleted, and there is a message that tells the grid to refetch all the values for the visible cells and redraw them. So in your example above you would want to do something like this after calculating the items that match the filter.

        if newNumRows < oldNumRows:
                msg = wx.grid.GridTableMessage(
                        self, # the table
                        wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED,
                        newNumRows, # position
                        oldNumRows - newNumRows) # how many
                self.GetView().ProcessTableMessage(msg)

        elif newNumRows > oldNumRows:
                msg = wx.grid.GridTableMessage(
                        self, # the table
                        wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED,
                        newNumRows - oldNumRows) # how many
                self.GetView().ProcessTableMessage(msg)

        msg = wx.grid.GridTableMessage(
                        self,
                        wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
        self.GetView().ProcessTableMessage(msg)

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!