我正试图从另一个表单访问dbgrid.field的Caption
。
我在这里使用MDI,两种形式都是MDI儿童。
我试图从另一个表单执行以下ShowMessage
,但它导致了访问冲突:
ShowMessage(Form1.DBGrid1.Columns[1].Title.Caption); // 1st try
ShowMessage(Unit1.Form1.DBGrid1.Columns[1].Title.Caption); // 2nd try
已在两个表单之间使用集合。
错误消息为
模块中地址000010363F9处的访问冲突。读取地址000000006F0。
这里缺少什么?
UPDATE:这是这个案例的精确复制(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.
错误消息
模块"Project7.exe"中地址0081B314处的访问冲突。第页,共页地址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的实例是自动创建的CCD_ 7。
使用自动创建的表单,除了主表单之外,通常被认为是一种糟糕的做法,因为它会引发这样的事故,所以最好改掉使用它们的习惯。
从另一个窗体(或数据模块(访问一个窗体时,一种不太容易发生意外的技术是在"另一个"窗体上以需要指定要操作的对象实例的方式编写代码
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实例意思是说,因为当你有多个相同的实例时,正确处理可能非常重要表单(即使没有,因为它可能会提示您怀疑实例是否已创建(。