How to set active cell in TDBGrid?

大兔子大兔子 提交于 2019-12-10 17:36:44

问题


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.


回答1:


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.




回答2:


My implementation based on Andriy's excellent detective work:

type
  TDBGridAccess = class(TDBGrid);

// Set the currently active grid cell to (DestCol, DestRow). Both values are
// relative to the currently _visible_ upper left grid cell.
procedure SelectDBGridCell(Grid: TDBGrid; DestCol, DestRow: Integer);
var
  CurrentRow: Integer;
begin
  if not Assigned(Grid.DataSource) or not Assigned(Grid.DataSource.DataSet) then
    Exit;

  CurrentRow := TDBGridAccess(Grid).Row;
  Grid.DataSource.DataSet.MoveBy(DestRow-CurrentRow);
  // check if the leftmost grid column is the indicator column which has no
  // equivalent field in the dataset
  if dgIndicator in Grid.Options then
    Grid.SelectedIndex := DestCol-1 else
    Grid.SelectedIndex := DestCol;
end;

procedure TDBGridController.HandleDBGridMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  CellAtMousePos: TGridCoord;
  CurrentRow: Integer;
  DBGrid: TDBGrid;
begin
  DBGrid := Sender as TDBGrid;
  CellAtMousePos := DBGrid.MouseCoord(X, Y);
  if (CellAtMousePos.X<>-1) and (CellAtMousePos.Y<>-1)  then
    SelectDBGridCell(DBGrid, CellAtMousePos.X, CellAtMousePos.Y);
end;

(The grid selection follows the mouse cursor. But SelectDBGridCell could also be used to select a cell based on other criteria.)

Works like a charm from a technical standpoint. Usability is another question.



来源:https://stackoverflow.com/questions/7978780/how-to-set-active-cell-in-tdbgrid

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!