I'm trying to implement Find functionality in my grid application. I can move the cursor using SetGridCursor(self, row, col)
, but I can't figure out how to move the "viewport" of the grid to the new cursor position. In other words, when the cursor is moved to the cell the user is looking for, the user still has to manually scroll around until he finds the cursor cell.
How do I programmatically scroll the grid so I can centre the grid cursor in the viewport?
By random, while writing this question, I went to the Grid wiki page, searched for the word "scroll" and found:
MakeCellVisible( int row, int col )
— forces the particular cell to be visible, effectively works to scroll the grid to be given cell
Which almost solves my problem. I would like the cell to be centred in the viewport, but this function only scrolls until the cell is visible at the edge of the screen. I can't find any functions that only affect the scroll position of the grid without also affecting the cursor position. Thoughts?
In situations like this, have a look at which methods are exposed by wxWidgets
(the core C++ library). wxGrid
subclasses wxScrolled
. wxScrolled
exposes these methods:
Scroll
Scrolls a window so the view start is at the given point.
GetVirtualSize
Gets the size in device units of the scrollable window area (as opposed to the client size, which is the area of the window currently visible).
I think you can use these methods to calculate the center coordinates of the scrollable window. Now, what you need is the coordinates of the cell you would like to center on. wxGrid
exposes this method:
CellToRect
Return the rectangle corresponding to the grid cell's size and position in logical coordinates.
Now, in C++ you would cast your
wxGrid
to a
wxScrolled
and call the methods you want. However,
wxPython
does not always expose all methods available in
wxWidgets
, so here is where you have to get a little creative using unbound methods. Below is some pseudocode, it is untested, but should give you an idea on how to do this.
grid = wx.Grid()
cell_coords = grid.CellToRect(12,12)
# get the virtual size by calling it as unbound method
virtual_size = wx.Scrolled.GetVirtualSize(grid)
# calculate the upper-left coordinate
scroll_coords = (cell_coords.x - virtual_size.width / 2,
cell_coords.y - virtual_size.height / 2)
# call Scroll as unbound method
wx.Scrolled.Scroll(grid, scroll_coords)
This works for me for vertical scrolling to keep the grid cursor in the middle of the page:
def set_grid_cursor(grid, irow, icol):
# move the cursor to the cell as usual
grid.GoToCell(irow, icol)
# scroll to keep irow in the middle of the page
ppunit = grid.GetScrollPixelsPerUnit()
cell_coords = grid.CellToRect(irow, icol)
y = cell_coords.y / ppunit[1] # convert pixels to scroll units
scrollPageSize = grid.GetScrollPageSize(wx.VERTICAL)
scroll_coords = (0, y - scrollPageSize / 2)
grid.Scroll(scroll_coords)
You might have to call that using wx.CallAfter(set_grid_cursor, grid, irow, icol)
if you just updated the grid.