Доступ к DBGrid1.Columns [1]. Заголовок. Заголовок из другой формы - PullRequest
2 голосов
/ 25 февраля 2020

Я пытаюсь получить доступ к Caption поля dbgrid.field из другой формы.

Я использую здесь MDI, и обе формы являются MDIChildren.

Я попытался выполнить следующее ShowMessage из другой формы, но это вызвало нарушение прав доступа:

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

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

Используется набор уже между 2 формами.

Сообщение об ошибке

Нарушение прав доступа по адресу 000010363F9 в модуле. Чтение адреса 000000006F0.

Что мне здесь не хватает?


ОБНОВЛЕНИЕ: Вот точная копия (RME) этого случая.

MDI Parent

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.

Сообщение об ошибке

Нарушение доступа по адресу 0081B314 в модуле ' Project7.exe. Чтение адреса 000003D0.

Ответы [ 2 ]

2 голосов
/ 25 февраля 2020

Вероятно, один из объектов не назначен, я подозреваю, что это может быть 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');
1 голос
/ 25 февраля 2020

При написании кода типа Form1Unit.ChildForm1.dbgrd1.Columns[2].Title.Caption) создается ожидающая авария, поскольку предполагается, что экземпляр ChildForm1, с которым вы хотите работать, является автоматически созданным ChildForm1.

Использование автоматически созданных форм За исключением, пожалуй, основной формы, обычно считается плохой практикой, потому что она поощряет несчастные случаи, подобные этой, поэтому, вероятно, лучше избавиться от привычки их использовать.

Менее склонная к несчастным случаям техника доступа к одному Форма (или модуль данных) от другого - это написать код в «другой» форме таким образом, чтобы вы указали экземпляр объекта для работы. Примерно так:

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 вы имеете в виду, потому что получить это право может быть очень важно, если у вас есть несколько экземпляров одного и того же формы (и даже если вы этого не сделаете, потому что это может побудить вас задаться вопросом, был ли создан экземпляр).

...