Доступ к DBGrid1.Columns[1].Title.Caption из другой формы

Я пытаюсь получить доступ к 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-родитель

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.

Детская форма MDI1

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.

Детская форма MDI2

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.


person Juke    schedule 25.02.2020    source источник
comment
Вы уверены, что Form1 указывает на экземпляр вашей формы? Можете ли вы показать нам код, где вы создаете форму?   -  person Marc Guillot    schedule 25.02.2020
comment
Забыл упомянуть здесь, что я использую MDI, и обе формы - MDIChildren. Форма создается из ParentMainForm.   -  person Juke    schedule 25.02.2020
comment
Пожалуйста, ВСЕГДА, когда вы получаете сообщение об ошибке, скопируйте (щелкните правой кнопкой мыши окно сообщения и затем нажмите Ctrl-C) сообщение об ошибке на свой вопрос. И, пожалуйста, не расширяйте свой вопрос здесь, в комментариях. отредактируйте свой вопрос.   -  person Tom Brunberg    schedule 25.02.2020
comment
Пожалуйста, покажите код, который вы используете, и покажите его в контексте, а не просто как один оператор, такой как ShowMessage (...) - читатели не должны гадать.   -  person MartynA    schedule 25.02.2020
comment
@MartynA Я создам для этого RME. Дай мне минуту.   -  person Juke    schedule 25.02.2020
comment
Предоставляется РМЭ. Надеюсь, теперь это достаточно ясно. Я чувствую, что ChildForm2 не может иметь прямого доступа к ChildForm1. Так как это должно пройти сначала с помощью ParentForm? Здесь нужен свет...   -  person Juke    schedule 25.02.2020
comment
Вы должны назначить ChildForm1:=TChildForm1.Create(Self); ChildForm1.Show();. В вашем коде ChildForm1 равно нулю.   -  person BrakNicku    schedule 25.02.2020
comment
@BrakNicku Ты понял! Теперь это работает! Спасибо! Можете ли вы придумать ответ здесь, чтобы я мог пометить его и закрыть это уже.   -  person Juke    schedule 25.02.2020
comment
Итак, Джук. Если бы вы последовали предложению @Fabrizio проверить назначение Form1 (и др.), У вас был бы ответ! Или, по крайней мере, четкое указание, что может быть не так.   -  person Tom Brunberg    schedule 25.02.2020
comment
@TomBrunberg Да, я понимаю и уже понял это.   -  person Juke    schedule 25.02.2020


Ответы (2)


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

person MartynA    schedule 25.02.2020
comment
Я знаю. Я только что узнал об этом отсюда. Я уже изменил некоторые из моих кодов, относящихся к этому. Большое спасибо. - person Juke; 25.02.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');
person Fabrizio    schedule 25.02.2020
comment
На самом деле столбцы уже существуют в том виде, в котором они указаны. Я имел в виду конкретный столбец в этом случае. Я не уверен, что код, который вы дали, работает. Я попытался получить к нему доступ в той же форме, используя ShowMessage, и он выполнился, используя это — ShowMessage(DBGrid1.Columns[1].Title.Caption); - person Juke; 25.02.2020
comment
Поэтому я думаю, что объект Form1 не назначен или не принадлежит к ожидаемому типу класса. попробуй проверить - person Fabrizio; 25.02.2020
comment
Я забыл упомянуть, что я использую здесь MDI. Кстати, обе формы являются MDIChildren. - person Juke; 25.02.2020