Wednesday, June 16, 2010

A grid to select rows

I want to use a grid to select, for example, a customer from the customers table.

I need a grid with the following features:
  • read-only
  • when I click the grid I want to select the whole row.
Solving this problem was harder than expected. First I tried the new wxDataViewListCtrl control. It has a lot of interesting functionalities, so I spent some time trying to use it. Unfortunately I found a number of bugs that showed how this control was too young for production code.

Then I tried wxDataListCtrl in report mode. I already used it in other projects so I had some experience with it, and it looked like a good solution. After writing some test code I again found a couple of problems.
The first is that it is not possible to have the first column right aligned, so it is not possible to show numbers in the first column.
The second is that a bitmap shown in a column is always left-aligned, while it would often be useful to have it centered.
Both limitations derive from the native control used, so they are not wxWidgets' fault.

So I was left only with the venerable wxGrid, and I tried it. I have been able to obtain a good result, and I learned something about wxGrid that will be useful in the future.

I derived a new class from wxGrid, with the following modifications:

The constructor calls the following code to set the visual properties of the grid:
EnableEditing( false );
SetCellHighlightPenWidth( 0 );  // disable highlight
EnableGridLines( false );
ShowScrollbars( wxSHOW_SB_DEFAULT, wxSHOW_SB_ALWAYS );
// select the first row
if( GetNumberRows() > 0 )
    SelectRow( 0 );

the wxEVT_GRID_SELECT_CELL handler calls
SelectRow( event.GetRow() );

the wxEVT_GRID_RANGE_SELECT handler uses this code
if( event.Selecting() && (event.GetTopRow() != event.GetBottomRow()) ) {
to see if it needs to call
SelectRow( GetGridCursorRow() );
to select the current row only.

the wxEVT_GRID_LABEL_LEFT_CLICK handler calls
SelectRow( GetGridCursorRow() );

the wxEVT_GRID_ROW_SIZE handler calls
SelectRow( GetGridCursorRow() );

the wxEVT_GRID_COL_SIZE handler calls
SelectRow( GetGridCursorRow() );

the wxEVT_KEY_DOWN handler ignores events that would make the cursor go outside the grid, making the selection disappear. For example:
if( event.GetKeyCode() == WXK_RIGHT && GetGridCursorCol() == GetNumberCols() - 1 )
    ignore = true;

The resulting grid is very satisfactory for my needs.

No comments:

Post a Comment