从另一个表单访问 DBGrid1.Columns[1].Title.Caption

Access DBGrid1.Columns[1].Title.Caption from another Form

我正在尝试从另一个表单访问 dbgrid.field 的 Caption

我这里用的是MDI,两种形式都是MDIChildren。

我试图从另一个表单执行以下 ShowMessage 但它导致了访问冲突:

ShowMessage(Form1.DBGrid1.Columns[1].Title.Caption); // 1st try

ShowMessage(Unit1.Form1.DBGrid1.Columns[1].Title.Caption); // 2nd try

已在 2 种形式之间使用集合。

错误信息是

Access Violation at address 000010363F9 in module. Read of address 000000006F0.

我在这里错过了什么?


更新:这是本案例的精确复制 (RME)。

MDI 父级

unit MainUnit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus;

type
  TParentForm = class(TForm)
    mmMenu: TMainMenu;
    miForm1: TMenuItem;
    miForm2: TMenuItem;
    procedure miForm1Click(Sender: TObject);
    procedure miForm2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  ParentForm: TParentForm;

implementation

uses
  Form1Unit, Form2Unit;

{$R *.dfm}

procedure TParentForm.miForm1Click(Sender: TObject);
begin
  TChildForm1.Create(self).Show;
end;

procedure TParentForm.miForm2Click(Sender: TObject);
begin
  TChildForm2.Create(self).Show;
end;

end.

MDI ChildForm1

unit Form1Unit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Datasnap.DBClient,
  Datasnap.Provider, MemDS, DBAccess, Uni, UniProvider, MySQLUniProvider,
  Vcl.Grids, Vcl.DBGrids;

type
  TChildForm1 = class(TForm)
    dbgrd1: TDBGrid;
    ucn1: TUniConnection;
    mup1: TMySQLUniProvider;
    uq1: TUniQuery;
    dsp1: TDataSetProvider;
    cds1: TClientDataSet;
    ds1: TDataSource;
    smlntfldcds1actor_id: TSmallintField;
    strngfldcds1first_name: TStringField;
    strngfldcds1last_name: TStringField;
    dtmfldcds1last_update: TDateTimeField;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  ChildForm1: TChildForm1;

implementation

uses
  MainUnit, Form2Unit;

{$R *.dfm}

end.

MDI ChildForm2

unit Form2Unit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TChildForm2 = class(TForm)
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  ChildForm2: TChildForm2;

implementation

uses
  MainUnit, Form1Unit;

{$R *.dfm}

procedure TChildForm2.btn1Click(Sender: TObject);
begin
  ShowMessage(Form1Unit.ChildForm1.dbgrd1.Columns[2].Title.Caption);
end;

end.

错误信息

Access Violation at address 0081B314 in module 'Project7.exe'. Read of address 000003D0.

可能有一个对象没有分配,我怀疑它可能是 Columns[1](注意 Columns 集合是从零开始的索引,所以第一列是 Columns[0])

试试这个:

if(not Assigned(Form1)) then 
  raise Exception.Create('Form1 not assigned');

if(not Assigned(Form1.DBGrid1)) then 
  raise Exception.Create('Form1.DBGrid1 not assigned');

if(Form1.DBGrid1.Columns.Count < 2) then 
  raise Exception.Create('Form1.DBGrid1 has not the Columns[1] item');

编写像 Form1Unit.ChildForm1.dbgrd1.Columns[2].Title.Caption) 这样的代码是在制造一个等待发生的事故, 因为它假定您要操作的 ChildForm1 实例是自动创建的 ChildForm1.

使用自动创建的表单,也许主表单除外,通常被认为是不好的做法,因为它会助长此类事故,因此最好改掉使用它们的习惯。

从一个表单(或数据模块)访问另一个表单(或数据模块)的一种不太容易发生事故的技术是以一种需要您指定要操作的对象实例的方式在 "other" 表单上编写代码。像这样:

procedure TChildForm2.DoSomethingWithForm1(Form1Instance : TForm1);
begin
  ShowMessage(Form1Instance.dbgrd1.Columns[2].Title.Caption);
end;

procedure TChildForm2.btn1Click(Sender: TObject);
begin
  DoSomethingWithForm1(Form1Unit.ChildForm1);
end;

这样做的意义在于,它会迫使您考虑要使用哪个 Form1 实例 意思是,因为当您有多个相同的实例时,正确处理可能非常重要 表单(即使您不这样做,因为它可能会提示您怀疑实例是否已创建)。