我在哪里可以拦截派生 TDBGrid 中的行更改?

Where can I intercept the row change in a derivative TDBGrid?

我想知道是否覆盖了 DrawColumnCell 网格是否正在绘制其活动行。

我想保留一个 ActiveRecno 私有变量来检查 DrawColumnCell 是否正在绘制该行。我尝试拦截数据源的 DataChange 以跟踪那个 ActiveRecno。

TMyDBGrid = class(TDBGrid)
  protected
    OnDataChange_Original: TDataChangeEvent;
    procedure TrackPosition(Sender: TObject; Field: TField);
    procedure DrawColumnCell(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); override;
  public
    ActiveRecno: integer;
    constructor Create(AOwner: TComponent): override;
  ...
  ...

implementation

constructor TMyDBGrid.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  OnDataChange_Original := nil;
  if Assigned(DataSource) then begin
    OnDataChange_Original := Datasource.OnDataChange;
    Datasource.OnDataChange := TrackPosition;
  end;
end;

procedure TMyDBGrid.TrackPosition(Sender: TObject; Field: TField);
begin
  ActiveRecno := Datasource.DataSet.RecNo;
  if Assigned(OnDataChange_Original) then OnDataChange_Original(Sender, Field);
end;

procedure TMyDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); 
var ActiveRow: boolean;
begin
  ActiveRow := (Self.ActiveRecno = Self.DataSource.Dataset.Recno); 
  ...
  ...

  inherited DrawColumnCell(Rect, DataCol, Column, State);
end;

但 ActiveRecno 始终为 0,使得 ActiveRow 始终为 False。那是因为在构造函数中数据源仍然是零,所以我从来没有设置 TrackPosition 来保持 ActiveRecno。

我在哪里可以为那个事件设置我的处理程序?SetDataSource 过程是私有的,所以我不能覆盖它。

你能推荐我另一种方法来跟踪活动行,或者在 DrawColumnCell 中检测要绘制的行是否是活动行吗?

谢谢。

我认为你想要的很简单,除了当前行 无论是 DBGrid 还是在 OnDrawrDataCell 事件中绘制的行都可以在事件内部轻松访问。

幸运的是,使用中介层 TDBGrid class 克服这些问题相当简单,如下所示。

插入器 TDBGrid class 只是将 TCustomGrid 的行 属性 公开为 ActiveRow

OnDrawDataCell 事件是从 TCustomDBGrid.DrawCell 调用的,它是虚拟的,因此可以被覆盖 在插入器中 class。如下所示,覆盖版本首先复制使用的行号(ARow 参数) 在 TCustomDBGrid.DrawCell 中进入 FRowBeingDrawn 字段,然后调用继承的 DrawDataCell,后者又调用 OnDrawDataCell 处理程序。由于这个处理程序 看到插入器 class,网格的 ActiveRow 和 RowBeingDrawn 都可以在内部访问 OnDrawDataCell 事件。

type
  TDBGrid = class(DBGrids.TDBGrid)
  private                                   ,
    FRowBeingDrawn : Integer;
    function GetActiveRow: Integer;
  protected
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
    property RowBeingDrawn : Integer read FRowBeingDrawn write FRowBeingDrawn;
    property ActiveRow : Integer read GetActiveRow;
  end;

  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    ClientDataSet1: TClientDataSet;
    DataSource1: TDataSource;
    ComboBox1: TComboBox;
    DBNavigator1: TDBNavigator;
    procedure FormCreate(Sender: TObject);
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
  end;

[...]

procedure TForm1.FormCreate(Sender: TObject);
var
  AField : TField;
begin
  AField := TIntegerField.Create(Self);
  AField.FieldKind := fkData;
  AField.FieldName := 'ID';
  AField.DataSet := ClientDataSet1;

  AField := TStringField.Create(Self);
  AField.FieldKind := fkData;
  AField.FieldName := 'AValue';
  AField.DataSet := ClientDataSet1;

  ClientDataSet1.CreateDataSet;
  ClientDataSet1.InsertRecord([1, 'One']);
  ClientDataSet1.InsertRecord([2, 'Two']);
  ClientDataSet1.InsertRecord([3, 'Three']);
  ClientDataSet1.InsertRecord([4, 'Four']);
  ClientDataSet1.InsertRecord([5, 'Five']);

  DBGrid1.DefaultDrawing := True;
end;

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
   if (Sender as TDBGrid).RowBeingDrawn = (Sender as TDBGrid).Row then
     Caption := IntToStr((Sender as TDBGrid).RowBeingDrawn);

  DBGrid1.DefaultDrawDataCell(Rect, Column.Field, State);

end;

procedure TDBGrid.DrawCell(ACol, ARow: Integer; ARect: TRect;
  AState: TGridDrawState);
begin
  RowBeingDrawn := ARow;
  try
    inherited;
  finally
    RowBeingDrawn := -1;
  end;
end;

function TDBGrid.GetActiveRow: Integer;
begin
  Result := Row;
end;

end.

插入器 class 当然可以包含在一个单独的单元中,前提是它出现在使用单元的使用列表中的 DBGrids 之后。

需要注意的一点是,上面的代码没有考虑网格的标题行是否可见,如果不可见,则需要进行微调。