Create Form // Tabsheet // access Methods on Form

I am writing an application like this:

There is a main form with a PageControl on it, In the Page Control I create Tabsheets, In the Tabsheets, forms are placed.

This helps because the user can create one type of form more than once, like a standard pdf viewer opened in more than one tab, but displaying different data, in essence its the same form.

This works very well and is very useful! Unfortunately something important isn't working, this is the problem:

This code will work fine:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Caption := 'Hello';  
end;

The caption will change, however, if I would like to call a method instead, like this:

Procedure changeLabel(str : String);
Begin
  Form1.Label1.Caption := str;
End;

procedure TForm1.Button1Click(Sender: TObject);
begin
  changeLabel('Hello');
end;

I get an access violation at Form1.Label1.Caption := str; in the procedure

Here is how I created the form:

procedure TfrmPage.CDMA1Click(Sender: TObject);
var
  TabSheet: TTabSheet;
  frmTest : TForm;

begin
  TabSheet := TTabSheet.Create(PageControl1);
  TabSheet.Caption := 'kjklhhj';
  TabSheet.PageControl := PageControl1;

  frmTest := TForm1.Create(Nil);
  frmTest.Show;
  frmTest.Parent := TabSheet;
end;

I did everything as everyone said here: another stackoverflow question

My Question, how can the newly created form, pinned to the Tabsheet, access its own procedures without throwing exceptions? Another piece that might be important: When I have delphi Auto-Create the form, theres no access violation but the method does nothing to the form, so I think the procedure might be changing things on the wrong form, one thats not created yet (which gives AV), and not to the one i just created, or the application is not calling the method on my new form, but calling one somewhere where that form isn't created yet.

If I auto-create the form, calling the procedure probably changes the label on the form that was created when the application started and not the new form..

Any help would be appreciated, as I've been googling for hours now with no real help to this problem

Thanks in advance :)

Upvotes: 0

Views: 992

Answers (1)

Tom Brunberg
Tom Brunberg

Reputation: 21033

If you plan to create several instances of the TForm1 class, it is correct to not auto-create Form1. In fact you should delete the Form1: TForm1 declaration altogether to reduce the risk of errors. You probably want to keep references to the forms you create f.ex. in a TList, possibly hosted by the TfrmPage instance depending on what TfrmPage is. (See below in discussion about AV)

Access Violation

When you created an instance of TForm1 in TfrmPage.CDMAClick() you assigned the reference of the created form to a local variable frmTest and then you show it in a tabsheet. You can click Button1 and change caption of Label1. However when you call the ChangeLabel procedure you state

  Form1.Label1.Caption := str;

but the Form1 variable has never been assigned, therefore is nil and the AV is triggered. Now, since you assigned the forms reference to the local frmTest variable in TfrmPage.CDMAClick() you don't really have any reference anymore to the form, and cannot access it (actually, since you parented it to the tabsheet, you can search for it in the tabsheets controls). This is why I suggested to keep references to the forms you create in a list. Then you can access the forms through that list when needed.

My Question, how can the newly created form, pinned to the Tabsheet, access its own procedures without throwing exceptions?

You can always access an objects methods, fields and properties from the object itself without using a reference variable. In fact, you should never use the objects reference variable from within the object:

  Label1.Caption := 'Whatever'; // correct from within the form

Sometimes it may be necessary to use a reference within the object and for that purpose you can use self f.ex.:

  self.Label1.Caption := 'Whatever'; // self can be used if needed

From an external method/procedure/function you need to use a reference to the object

  Form1.Label1.Caption := 'Whatever'; // assuming Form1 has been assigned

Upvotes: 1

Related Questions