4

I want to access a main form variable from a class that is called from the main from. Something like this:

Unit1:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,Unit2, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
  public
  end;
var
  Form1: TForm1;
  Chiled:TChiled;
const
 Variable = 'dsadas';
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Chiled.ShowMainFormVariable;
end;

end.

Unit2:

unit Unit2;

interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

  type
  TChiled = class
  private
  public
    procedure ShowMainFormVariable;
  end;
var
  Form1: TForm1;
implementation

procedure TChiled.ShowMainFormVariable;
begin
  ShowMessage(Form1.Variable);
end;
end.

if in Unit2 i add to uses Unit1 an circular errors pops up.

How to make the Unit1 to be GLOBAL?

LU RD
  • 34,438
  • 5
  • 88
  • 296
TreantBG
  • 1,192
  • 6
  • 25
  • 44

4 Answers4

6

As other answers tell, you should use one of the units in implementation section.

Suppose you chose in 'unit2' you'd use 'unit1' in implementation. then you need to devise a mechanism to tell the 'TChiled' how to access 'Form1'. That's because since you haven't used 'unit1' in interface section of 'unit2', you cannot declare the 'Form1:TForm1' variable in interface section. Below is just one possible solution:

unit2

type
  TChiled = class
  private
    FForm1: TForm;
  public
    procedure ShowMainFormVariable;
    property Form1: TForm write FForm1;
  end;

implementation

uses
  unit1;

procedure TChild.ShowMainFormVariable;
begin
  ShowMessage((FForm1 as TForm1).Variable);
end;

then in unit1 you can set the Form1 property of TChiled before calling TChiled's method:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Chiled.Form1 := Self;
  Chiled.ShowMainFormVariable;
end;
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
3

Well, the simple naive answer is that you should add Unit1 to the uses clause of the implementation section of Unit2:

unit Unit2;
......
implementation

uses
  Unit1;
.....

You can't add it to the uses clause in the interface section of Unit2 since that would create a circular reference at the interface section. In order words, the interface of Unit1 would uses Unit2, and the interface of Unit2 would use Unit1. The language does not allow that. The common solution is to use one of the units at the implementation level.


Having said that, your code is rather confused and fails in many other ways. Your problems run deeper than the circular reference. For example, what do you mean by Form1.Variable? The constant Variable is not a member of TForm1. You declare two global variables named Form1 of type TForm1. Why do you do that?

Also, you have spelled child incorrectly.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
3

the simplest solution is to add Unit1 to a uses clause inside Unit2's implementation section as this gets around the circular reference.

However I'd suggest that this design is flawed. It is hard to see what you are trying to achieve with the sample code so it is difficult to offer any real advice.

John Pickup
  • 5,015
  • 2
  • 22
  • 15
1

I generally create a Data Module (or any type of non-visual container) to share global variables. This way both units can use the variable without a circular reference.

Celal Ergün
  • 955
  • 2
  • 14
  • 30
  • Whilst that might be a good idea, it would be better if you answered the question that was asked, as well as offering sound advice. – David Heffernan Apr 16 '12 at 13:01
  • 1
    @golez Why not? I mean a data module is over the top I guess, a plain unit would do. But do you mean more than that? – David Heffernan Apr 16 '12 at 13:14
  • Well, no special reason to use a DataModule. I almost always use a data module in my projects and I used to share globals in it. More over, he asked a form variable but the example has a unit variable (e.g. not defined in private or public sections of form). I just brought another unit. This is my point of view for this very problem I think. – Celal Ergün Apr 16 '12 at 13:42
  • I think an application shouldn't have many (or any) globals at all. You could get away with globals for a main form and/or a main datamodule, but if you need to create a unit or datamodule to contain 'all' your globals, I think you should consider a redesign. Especially in this case. I think circular references between forms is bad. Use events, or some observer like construction instead. Usually it takes maybe 5 lines of code to eliminate such a dependancy. – GolezTrol Apr 16 '12 at 14:18
  • @golez in this case the 'variable' is a constant. I see no problems with constants of global scope. Centralising them in a single unit often makes sense. – David Heffernan Apr 16 '12 at 17:42