如何在TDBGrid中设置活动单元格?

发布于 2024-12-13 09:18:06 字数 125 浏览 3 评论 0原文

我想通过代码激活 TDBGrid 中的单元格。我所说的“激活”是指用户在单元格内部单击,准备编辑单元格内容。我怎么能这样做呢?

编辑:这可能涉及两个步骤:更改当前活动的单元格,然后进入编辑模式。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

相思故 2024-12-20 09:18:06

如果您的意思是“激活当前活动单元格的编辑模式”,那么您可能应该这样做:

MyDBGrid.EditorMode := True;

激活特定单元格可以通过 SelectedIndex:

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

或通过SelectedField

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

要确定当前鼠标光标位于哪个单元格,可以使用 MouseCoord,它返回一个 TGridCoord 记录,其中包含光标下的单元格。 TGridCoord.X 字段可直接用于设置网格的活动列。

var
  Cell: TGridCoord;

...

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

设置行比较棘手,到目前为止,我能找到的唯一方法涉及所谓的“受保护的黑客”,即访问类的受保护属性和方法的方法。我们需要“破解”的正是 TDBGrid 类。

基本上,您声明 TDBGrid 的空后代,如下所示:

type
  THackDBGrid = class(TDBGrid);

然后,当您需要访问受保护的属性或方法时,只需转换标准类的实例 (MyDBGrid 在本例中)到“黑客”类型 (THackDBGrid):

… THackDBGrid(MyDBGrid).protected_property_or_method

我们感兴趣的项目是 Row 属性。它返回活动行的 Y 坐标。我们需要知道它来确定活动行和光标下的行之间的差异,以便我们可以相应地移动基础数据集的记录指针。具体方法如下:

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

Row 值不是绝对的:它是相对于可见顶行的,但 TGridCoord.Y 也是如此,因此两者之间的差异对应于差异基础数据集中的数据行之间。

我想强调的一件事是:这种受保护的黑客方法应该谨慎使用。受保护的项目受到保护是有原因的。所以,如果你能避免它,请尽量避免。如果您不能(没有其他方法或者它可以帮助您更轻松地完成任务),请记住不要使用受保护的黑客直接更改任何内容。我的意思是,这可能没问题,但通常你永远无法确定。你可以看到,我只是使用该方法读取受保护的内容,我没有直接更改任何内容。对象的状态最终发生了变化,但这是由 MoveBy 方法触发的标准机制的结果。

您可以在 此处阅读有关 protected hack 的更多信息

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.

似梦非梦 2024-12-20 09:18:06

我的实现基于 Andriy 出色的侦探工作

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;

:(网格选择跟随鼠标光标。但是 SelectDBGridCell 也可用于根据其他条件选择单元格。)

从技术角度来看,它就像一个超级按钮。可用性是另一个问题。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文