Tuesday, October 30, 2007

Highlighting Delphi's DBGrid Row On Mouse over

Memberikan efek Highlight pada DbGrid pada event on mouse over

Hot Tracking for TDBGrid

Delphi's TDBGrid displays and manipulates records from a dataset in a tabular grid.

Contrary to what most novice developers think, the DBGrid component allows various customizations. changing the color of a specific cell or a column or even a row is not complicated at all.
What most are not aware of, is that you can even implement the OnMouseHover (hot tracking)change the display (color, font, etc.) of the DBGRid's (data) row underneath the mouse - *not* the currently selected row - thus making it look like today's web driven interfaces.
behavior to
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.

Coloring DBGrid's Row On Mouse Hover

To follow the source code provided later on, create a new application. On the form ("Form1") drop a DBGrid ("DBGrid1"). Use any type of TDataset descentand and connect to some database data to make sure the dbgrid has some data to show.

Note: All he code goes inside the Form1's unit source!!

For a start, prepare the protected hack for the DBGrid component. In the interface section, just add the following line:

___THackDBGrid = class(TDBGrid) ;

Next, add a private integer property "MouseOverRow" - you'll use it to track the index position of the row the mouse is over.

private fMouseOverRow: integer;
procedure SetMouseOverRow(const Value: integer) ;
property MouseOverRow : integer read fMouseOverRow write
To be able to track the row the mouse is over you need to handle the OnMouseMove DBGrid1's event.
//DBGrid1 OnMouseMove
procedure TForm1.DBGrid1MouseMove(Sender: TObject;Shift: TShiftState;X, Y: Integer) ;
___ gc: TGridCoord;
___gc := DBGrid1.MouseCoord(x, y) ;
___MouseOverRow := gc.Y;
The MouseOverRow property's setter calls the Refresh method that will in turn fire the DrawColumnCell event.
procedure TForm1.SetMouseOverRow(const Value: integer) ;
___if fMouseOverRow <> Value then
______fMouseOverRow := Value;
As expected the tricky part goes inside the OnDrawColumnCell event handling procedure.
//DBGrdi1 OnDrawColumnCell
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject;const Rect: TRect;DataCol: Integer;Column: TColumn;State: TGridDrawState) ;
___if NOT ((gdFocused in State) or (gdSelected in State)) AND (MouseOverRow = 1 + THackDBGrid(DBGrid1).DataLink.ActiveRecord) then
______with DBGrid1.Canvas do
_________Brush.Color := clSilver;
_________Font.Color := clNavy;

___DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State) ;

What we want is to change the drawing color of the row the mouse is over.


If MouseOverRow matches the ActiveRecord value of the protected DataLink property and the cell being drawn does not have the focus and is not selected: change the Canvas's coloring to actually "draw" the row highlighted.

The tricky part here was the protected DataLink property and the ActiveRecord value. The DataLink property helps the data-aware grid manage its link to the data source and respond to data events. The ActiveRecord specifies the index of the current record within the internal record buffer maintained by the dataset for the Owner of the TDataLink object.

You might think that ActiveRecord points to the currently selected record for the data displayed in the grid, but it is not.

Note: you might ask yourself: "how does he know this". Here's the answer: I read Delphi Help files and browse the VCL source code

While Delphi draws data the DBGrid displays it changes the ActiveRecord to match the row being drawn.

And this is the trick: match the currently drawn row woth the one the mouse is over. That's it. Beauty!

1 comment:

Kofi said...


I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

Delphi development