Search code examples
formsdelphivclcircular-reference

How to create a shared code unit for other units?


I have two VCL Forms: Form1 in Unit1 and Form2 in Unit2.

I also added another Unit into the Project, the Unit3.

In the Unit3, the Unit1 and Unit2 were added in the uses list. I have managed to create a class that may manipulate other units (Unit1 & Unit2):

unit Unit3;

interface

uses
  Vcl.Forms, Unit1, Unit2;

type
  Tmain = class
    private
      procedure openForm1;
      procedure openForm2;
  end;

var
  Form1: TForm1;
  Form2: TForm2;

implementation

procedure Tmain.openForm1;
begin
  //I will create code to open Form1 soon
end;

procedure Tmain.openForm2;
begin
  //I will create code to open Form2 soon
end;

end.

How can I run (or create properly) a Shared Code Unit for managing the Form1 & Form2 if the Project1's Source Code seemed not to run my Shared Code Unit (Unit3)?

program Project1;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2},
  Unit3 in 'Unit3.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.

I am trying these algorithms to avoid circular references as my level of understanding through Lieven Keersmaekers's answer on How to manage circular references in delphi units?


Solution

  • First some basics in Delphi VCL applications. At the top is the Application: TApplication object, which is created very early during initialization of your program (.exe). As you have seen, it is first referred to in your program files, in the .dpr:

    begin 
      Application.Initialize; 
      Application.MainFormOnTaskbar := True; 
      Application.CreateForm(TForm1, Form1);  
      Application.CreateForm(TForm2, Form2); 
      Application.Run;
    end.
    

    The Application object is not visible. Therefore, Delphi has a concept of MainForm. The main form is intended to be the primary UI for the user, and is created by the first call to Application.CreateForm(). Unless prevented by the programmer, the main form is made visible, so the user can interact with the application. When the main form is closed, the application is terminated. Broadly taken, we can say that the main form controls the lifetime of the application.

    The main form usually provides menus or other UI elements with wich the user can activate and/or show other forms and perform the tasks of the program.

    Delphi names the form types, as you have seen, TForm1, TForm2 ... etc, and also declares a global variable for each form type to hold an instance of the form: Form1, Form2 ... etc. And once again, with these standard names Form1 is the main form of the application if it is the first to be created with a call to Application.CreateForm().

    In your case it would be natural to design three forms:

    • Form1, a new form that replaces your current Unit3 and acts as the main form, with f.ex. two buttons, each one to show Form2 and Form3 respectively.
    • Form2, actually current Form1 simply renamed as Form2.
    • Form3, actually current Form2 simply renamed as Form3.

    In this case you would need to add Unit2 and Unit3 to the uses clause of Unit1:

    implementation
      uses Unit2, Unit3;
    

    The event handlers for the buttons on Form1 look like this:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Form2.Show;
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      Form3.Show;
    end;