Подтвердить что ты не робот

Объявлять общедоступную глобальную переменную в Delphi

Скажем, у меня две формы в проекте delphi, я хочу иметь доступ к переменным form1 из form2. Кто-нибудь должен объявить, скажем, "общедоступную" переменную в форме1, которая может быть прочитана из всех форм?

Я попытался поместить переменную в публичную декларацию

    { private declarations }
  public
    { public declarations }
  test: integer;
  end;     

и в форме 2 i

    unit Unit2;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, unit1;

type

  { TForm2 }

  TForm2 = class(TForm)
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 

var
  Form2: TForm2; 
implementation

{$R *.lfm}

{ TForm2 }

procedure TForm2.FormCreate(Sender: TObject);
begin
  form1 //<---------- DOES NOT GET RECOGNIZED
end;

end.

Затем я помещаю 'Unit1' в раздел uses в Form2, но, похоже, я не могу этого сделать из-за круговой ссылки. Я хотел бы воздержаться от использования указателей, если это возможно.

4b9b3361

Ответ 1

Во-первых,, если вы должны использовать глобальные переменные (возможно, лучше не использовать глобальные переменные, как это указывал Крейг), тогда вы должны поместить глобальные переменные, которые вы хотите использовать в SharedGlobals.pas:

unit SharedGlobals;
interface
var
   {variables here}
   Something:Integer;
implementation
    { nothing here?}

Теперь используйте этот блок, из двух блоков, которые вы хотите предоставить доступ к этой переменной. Альтернативно, как для ссылки, так и для другого объекта, который называется чем-то разумным, и чтобы этот объект был создан, как держатель состояния (переменная значения), что эти два экземпляра (формы или классы или что-то еще) должны делиться.

Вторая идея, поскольку ваши две единицы, у которых у вас уже есть зависимости друг от друга, вы также можете обойти свою круговую зависимость, используя блок, который будет создавать циклическую зависимость, из раздела реализации вместо интерфейса:

 unit Unit2;
 interface
   /// stuff
 implementation
    uses Unit1; 

...

 unit Unit1;
 interface
   /// stuff
 implementation
    uses Unit2; 

Ответ 2

Сначала, лучше притвориться, что глобальные символы вообще не существуют. Если вы начнете программирование с костылем глобальных переменных, вы просто избегаете изучения самых простых методов, которые позволят вам обойтись без них. Вы беспокоитесь об использовании указателей (что на самом деле не помогло бы вашей проблеме вообще), но не беспокоило об использовании глобальных переменных, которые на самом деле более опасны.

Глобалы опасны, потому что:

  • Они обеспечивают связь между единицами, которые их разделяют (концепция называется жесткой связью)
  • Эта ссылка скрыта в том смысле, что она не является очевидной точной природой ссылки, не изучая детали кода.
  • Ваш код будет усеян побочными эффектами, то есть, когда вы делаете что-то в методе, происходят и другие неожиданные вещи. Это увеличивает вероятность и сложность тонких ошибок.
  • Кумулятивный эффект вышеуказанных пунктов состоит в том, что даже если вы разбиваете проект на 20 единиц, ваш мозг все равно должен думать обо всех 20 единицах одновременно, как если бы они были всего лишь единицей. Это побеждает цель взломать ваш проект на более мелкие управляемые устройства.
  • Вы быстро обнаружите, что даже средние проекты начинают очень трудно поддерживать.

Циркулярные ссылки

Пожалуйста, взгляните на мой ответ на предыдущий вопрос для размышлений о работе с циркулярными ссылками в более общем плане.

В вашем случае вам просто нужно переместить Unit1 из interface в использование implementation.

var
  Form2: TForm2; 

implementation

uses
  Unit1;

{$R *.lfm}

{ TForm2 }

procedure TForm2.FormCreate(Sender: TObject);
begin
  Form1.test; //Is now accessible, but remember: it will cause a runtime error if Form1 hasn't been created or has already been destroyed.
end;

Обмен данными без глобальных привязок

Вы заметите, что технически вы все еще используете глобальные переменные; хотя и созданные Дельфи, а не ваши собственные. Вот техника, которую вы можете использовать для обмена данными более контролируемым образом.

unit Unit3;

interface

type
  TSharedData = class(TObject)
  public
    Test1: Integer;
    Test2: Integer;
  end;

Затем в Form1 вы добавляете следующее:

implementation

uses
  ...
  Unit3;

type
  TForm1 = class(TForm)
  ...
  public
    SharedData: TSharedData;
  end;

//Inside either the constructor or OnCreate event add the following line:
SharedData := TSharedData.Create;
//Inside either the destructor or OnDestroyevent add the following line:
SharedData.Free;

Затем в Form2 вы делаете что-то немного другое, потому что хотите использовать данные с данными Form1, а не собственные "общие данные".

implementation

uses
  ...
  Unit3;

type
  TForm2 = class(TForm)
  ...
  public
    Form1SharedData: TSharedData;
  end;

//Nothing added to constructor/destructor or OnCreate/OnDestroy events

Наконец, после создания обеих форм вы даете Form2 ссылку на Form1 общие данные:

procedure RunApplicationWithoutFormGlobals;
var
  LForm1: TForm1;
  LForm2: TForm2;
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, LForm1);
  Application.CreateForm(TForm2, LForm2);
  LForm2.Form1SharedData := LForm1.SharedData;
  Application.Run;
end;

Вышеописанное показывает, как легко вы можете справиться даже с глобальными переменными Delphi.


Отказ от ответственности. Некоторые из кодов соответствуют общепринятым принципам инкапсуляции, но только для иллюстративных целей.

Ответ 3

в примере показаны Form1 (main) и Form2 (другие), которые лучше всего подходят для организации;


FORM1 только декларация интерфейса;

можно прочитать из всех форм;

interface

procedure oncreate(Sender: TObject);

implementation
uses Form2;

procedure TForm1.oncreate(Sender: TObject);
begin
  Form2.test1;
  //{Form2.test2} are not visible to Form1;
end;

FORM2 интерфейс и объявления реализации;

объявление реализации является локальным для устройства; не может быть прочитан из всех форм;

interface

procedure test1;

implementation

procedure test2; //declared under implementation;

procedure TForm2.test1;
begin
  ShowMessage('form2 test1 message');
end;

procedure TForm2.test2;
begin
  ShowMessage('form2 test2 message');
end;


любая операционная система , , , может быть локальной для исполняемого модуля.
он также очищает intellisense (Ctrl + Space) от объявлений, используемых только для устройства;