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" 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.
I've received many email messages from Delphi developers (beginners as well as experts) asking about highlighting a row in a DBGrid component – and at the same time enabling a user to edit data using the grid.
Don't get fooled about this question. One could say "nothing easier, just set dgRowSelect in Options property and off you go", but would go off the wrong track. Recall that when dgRowSelect is included in Options, the dgEditing flag is ignored and editing data using the grid is disabled, thus leaving you with a DBGrid that is not-editable.
What you will find in this article is how to enable the "OnMouseOver" type of event for a row in a DBGrid. The idea is to locate the record the mouse is hovering over, make this record active and highlight the corresponding row in a DBGrid.
I'm sure you've seen this behavior many times – many tables on the Web change the background color of their rows as mouse hovers over them.
First, we write code for the OnMouseMove event in a TDBGrid component to locate the DBGrid's row and column (cell) that the mouse is hovering over.
If the mouse is over the grid (handled in OnMouseMove event handler), we 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 1: similar code can be used to show over what cell in a DBGrid the cursor is, and to change the cursor when over the title bar.
Note 2: In order to correctly set the active record, we need to hack a DBGrid and get our 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 ("protected") to a Delphi developer. Hopefully, to access such protected members of a component, a simple technique called the "protected hack" can be used.
Having 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 – no need to click the Grid to change the current record.
Now, to enhance the user experience, we'll highlight the active row … this trick will allow us to have the code that changes the appearance of the row behind the mouse cursor:
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;
let's read the code… The OnDrawColumnCell event is used to handle the need for customized drawing for the data in the cells of the grid. To be able to differentiate the selected row from all other rows, we use a little trick. If 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.