[wx-dev] #9527: Patch to improve wxGrid::BlockToDeviceRect. dramatic speed improvement on large grids

wxTrac noreply at wxsite.net
Mon Jun 2 18:39:44 PDT 2008


Ticket URL: <http://trac.wxwidgets.org/ticket/9527>

#9527: Patch to improve wxGrid::BlockToDeviceRect.  dramatic speed improvement on
large grids
-------------------------------------------------------------------------------------------------------+
 Reporter:  kjones at cedrus.com                                                                          |       Owner:       
     Type:  optimization                                                                               |      Status:  new  
 Priority:  normal                                                                                     |   Milestone:       
Component:  GUI-generic                                                                                |     Version:  2.8.7
 Keywords:  speed optimization wxGrid wxGridCellAttrProvider wxGridSelection ClearSelection SelectCol  |   Blockedby:       
    Patch:  1                                                                                          |    Blocking:       
-------------------------------------------------------------------------------------------------------+
 I have created a patch to eliminate unnecessary looping during column-
 selection events.  This is a significant speed optimization (especially
 for large grids).

 I noticed that when I have a grid containing 10,000 rows or so, if I
 perform a single left click on a column heading (to select the column),
 there is a noticeable lag between the moment when I make the click and the
 moment when the grid paints the selected column with the selection color.
 This lag can be as long as 1 or 2 seconds.

 (Note: This slowness might not be so noticeable in a grid that does not
 use attributes.  I am using wxGrid::SetRowAttr, which causes the grid to
 construct and use a wxGridCellAttrProvider internally.)

 I discovered that the slowness is being caused by some unnecessary looping
 in wxGrid::BlockToDeviceRect.

 The inefficiency of wxGrid::BlockToDeviceRect can be described as follows:

         BlockToDeviceRect receives as input two pairs of (row,col)
 coordinates.  It receives the (row,col) pair for both the Top Left cell
 and the Bottom Right cell that define the targeted block of cells.

         For example, if I select all of "column 4" in a grid that has
 10,000 rows, then the Top Left cell parameter is set to ( 0, 4 ) and the
 Bottom Right parameter is set to ( 9999, 4 ).

         What BlockToDeviceRect then does is to loop through all 10,000
 cells to find what I will call the "total bounding rectangle" that will
 fully contain all of the selected cells.  You might think that knowing the
 rectangle of the Top Left cell and knowing the rectangle of the Bottom
 Right cell would be sufficient for you to extrapolate the "total"
 rectangle that would bound the entire column.  However, that is **NOT**
 sufficient.  Why not?  Answer: because somewhere in the middle of the
 column there could be a cell which has been merged into its neighbor cell.
 That merged cell will be twice as wide as the other cells.  I will need to
 expand my total bounding rectangle to accommodate that "extra-wide" cell
 in the middle of the column.

         After looping through 10,000 cells, BlockToDeviceRect then calls
 upon wxWindowBase::GetClientSize to determine how much of that "total
 bounding rectangle" is actually shown in the viewable displayed area of
 the grid's scroll window.

         The end result is that BlockToDeviceRect will return a rectangle
 that represents the overlap of the ClientSize (the actual "on screen"
 window) and the absolute selection rectangle (which is very large....
 10,000 rows tall).



 CONCLUSION:   It is wasteful for BlockToDeviceRect to loop through 10,000
 rows (or more) when we have readily-available methods of determining how
 many of those rows are actually viewable in the client window.

 I have submitted a patch which takes advantage of the binary search that
 has already been a part of wxGrid for as long as I have known wxGrid.

 The wxGrid class already makes available "internalXToCol(x)" and
 "internalYToRow(y)", which both make good use of a binary search to help
 quickly determine which column and which row are at any given pixel
 location of the viewable area.

 My patch simply makes new use of this already-implemented binary search by
 applying internalXToCol and internalYToRow inside of
 wxGrid::BlockToDeviceRect.

 This has sped up column selection events for me dramatically.  (Again, one
 reason why my grid objects might be more sensitive to this slowdown than
 someone else's grid objects is that I am using attributes, which means
 that every time the size of a cell is queried, wxGridTableBase::GetAttr
 will call m_attrProvider->GetAttr(row, col, kind) ).


--
Ticket URL: <http://trac.wxwidgets.org/ticket/9527>


More information about the wx-dev mailing list