Selecting and Highlighting a Row in a DBGrid

Giving the newbies some design advice
Yuri_Arcurs/DigitalVision/Getty Images

Have you ever seen a menu or table column/row highlight to a different color when your mouse hovers over it? That's what our goal is here: to have a row become highlighted when the mouse pointer is within range.

The TDBGrid Delphi component is one of the jewels of the VCL. Designed to enable a user to view and edit data in a tabular grid, the DBGrid provides various ways of customizing the way it represents its own data.

For example, adding color to your database grids will enhance the appearance and differentiate the importance of certain rows or columns within the database.

However, don't be fooled by over simplistic tutorials on this topic. It might seem easy enough to just set the dgRowSelect property, but remember that when dgRowSelect is included in Options, the dgEditing flag is ignored, meaning that editing the data using the grid, is disabled.

What you'll find below is an explanation on how to enable the OnMouseOver type of event for a DBGrid row, so that the mouse is recorded and located, making the record active so as to highlight the corresponding row in a DBGrid.

How to Work With OnMouseOver

The first order of business is writing code for the OnMouseMove event in a TDBGrid component so that it can locate the DBGrid's row and column (cell) that the mouse is hovering over.

If the mouse is over the grid (handled in the OnMouseMove event handler), you can use the MoveBy method of a DataSet component to set the current record to one displayed "below" the mouse cursor.

type THackDBGrid = class(TDBGrid);
...
procedure TForm1.DBGrid1MouseMove
 (Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
 gc: TGridCoord;
begin
 gc:= DBGrid1.MouseCoord(x, y);

 if (gc.X > 0) AND (gc.Y > 0) then
 begin
 DBGrid1.DataSource.DataSet.MoveBy
 (gc.Y - THackDBGrid(DBGrid1).Row);
 end;
end;

Note: Similar code can be used to show which cell the mouse is hovered over and to change the cursor when it's over the title bar.

In order to correctly set the active record, you need to hack a DBGrid and get your hands on the protected Row property. The Row property of a TCustomDBGrid component holds the reference to the current active row.

Many Delphi components have useful properties and methods that are marked invisible, or protected, to a Delphi developer. Hopefully, to access such protected members of a component, a simple technique called the "protected hack" can be used.

With the code above, when you move the mouse over the grid, the selected record is the one displayed in the grid "below" the mouse cursor. There's no need to click the grid to change the current record.

Have the active row highlighted to enhance the user's experience:

procedure TForm1.DBGrid1DrawColumnCell
 (Sender: TObject; const Rect: TRect; DataCol: Integer; 
 Column: TColumn; State: TGridDrawState);
begin
 if (THackDBGrid(DBGrid1).DataLink.ActiveRecord + 1 = 
 THackDBGrid(DBGrid1).Row)
 or (gdFocused in State) or (gdSelected in State) then
 begin
 DBGrid1.Canvas.Brush.Color := clSkyBlue;
 DBGrid1.Canvas.Font.Style := DBGrid1.Canvas.Font.Style + [fsBold];
 DBGrid1.Canvas.Font.Color := clRed;
 end;
end;

The OnDrawColumnCell event is used to handle the need for customized drawing for the data in the cells of the grid.

You can use a little trick to differentiate the selected row from all the other rows... Consider that the Row property (integer) is equal to the ActiveRecord (+1) property of the DataLink object that the selected row is about to be painted.

Note: You'll probably want to disable this behavior (the MoveBy method in OnMouseMove event handler) when DataSet connected to a DBGrid is in Edit or Insert mode.