How to set active cell in TDBGrid?

Heinrich Ulbricht picture Heinrich Ulbricht · Nov 2, 2011 · Viewed 18.1k times · Source

I want to activate a cell in a TDBGrid by code. By "activate" I mean like the user clicked inside the cell, ready to edit the cell content. How could I do this?

Edit: This probably involves two steps: change the currently active cell, then enter edit mode.

Answer

Andriy M picture Andriy M · Nov 2, 2011

If you mean ‘activate the edit mode for the currently active cell’, then you should probably do like this:

MyDBGrid.EditorMode := True;

Activating a particular cell can be done either via SelectedIndex:

MyDBGrid.SelectedIndex := 2;  { or maybe MyDBGrid.SelectedIndex + 1 }

or via SelectedField:

MyDBGrid.SelectedField := MyDataSet.FieldByName('Name');

To determine which cell is under the mouse cursor at the moment, you can use MouseCoord, which returns a TGridCoord record holding the coordinates of the cell under the cursor. The TGridCoord.X field can be used directly to set the grid's active column.

var
  Cell: TGridCoord;

...

Cell := MyDBGrid.MouseCoord(X, Y);
MyDBGrid.SelectedIndex := Cell.X;

Setting the row is trickier, and so far the only way I could find involves the so called protected hack, the method of accessing protected properties and methods of a class. And it's the TDBGrid class that we need to ‘hack’.

Basically, you declare an empty descendant of TDBGrid, like this:

type
  THackDBGrid = class(TDBGrid);

Then, when you need to access a protected property or method, you simply cast the instance of a standard class (MyDBGrid in this case) to the ‘hacked’ type (THackDBGrid):

… THackDBGrid(MyDBGrid).protected_property_or_method

The item we are interested in is the Row property. It returns the Y coordinate of the active row. We need to know it to determine the difference between the active row and the one under the cursor, so we could then move the underlying dataset's record pointer accordingly. Here's how:

MyDataSet.MoveBy(Cell.Y - THackDBGrid(MyDBGrid).Row);

The Row value is not absolute: it is relative to the visible top row, but so is TGridCoord.Y, so the difference between the two corresponds to the difference between the data rows in the underlying dataset.

One thing that I'd like to stress: this protected hack method should be used discreetly. Protected items are protected for a reason. So, if you can avoid it, please do so. And if you can't (there's no other way or it helps you to do things much more easily), please remember to refrain from changing anything directly using protected hack. I mean, it might be all right, but generally you never know for sure. You can see that I only used the method to read the protected contents, I didn't change anything directly. The object's state was eventually changed, but that was the result of a standard mechanism triggered by the MoveBy method.

You can read more about protected hack here.