سؤال

Edit the body for more details.

I have a Form called ENP, defined in the EnpView unit. The ENP form, is created and shown from the handler event of a click a toolbar item in the Main Form (TPrincipal).

procedure TPrincipal.ENP1Click(Sender: TObject);
begin
  TENP.Create(self).Show();
end;

Enp form knows (in public declaration) clearGrid() message.

ENP Form have a TStringGrid called StringGrid. And a button called "Add". When click "Add" button other Form is created and shown: AddEnp form, defined in EnpViewAdd unit.

procedure TENP.opAgregarClick(Sender: TObject);
begin
  TAddEnp.Create(self).Show();
end;

The AddEnp form, have any TEdits. The values of the inputs must be adding in the EnpView.StringGrid.

I try this:

implementation

uses
  EnpView, Main;
procedure TAddEnp.AgregarClick(Sender: TObject);
begin

  { Agrego el nodo xml }
  Globals.Xml.agregarMuestra(muestra.Text);
  Globals.Xml.insertEnp(muestra.Text,golpes.Text,metros.Text);

  { Send messages to EnpView Form }
  ENP.clearGrid();
  ENP.populateGrid();

end;

ClearGrid messages fails in line 1, with access violation:

procedure TENP.clearGrid();
begin
  Self.StringGrid.RowCount := 2;
  Self.StringGrid.Rows[1].Clear();
end;

The clearGrid methods works if is send within the class. Any ideas ?.

هل كانت مفيدة؟

المحلول

Create a property named, for instance, ENPForm in TAddENP and assign the ENP form just after creating it. Declare it as follows:

TAddENP = class(TForm)
private
  FENPForm: TENP;

// all of your already existing declarations

public
  property ENPForm: TENP read FENPForm write FENPForm;
end;

Now that you have a possible reference to ENP form, you can use it as you like.

During the creation of TAddENP form, do as follows:

procedure TENP.opAgregarClick(Sender: TObject);
var
  addForm: TAddENP;
begin
  addForm := TAddEnp.Create(Self);
  addForm.EnpForm := Self;
  addForm.Show;
end;

Now you created the second form and gave it a secure reference to the first one. They can now talk to each other safely.

I advise you to avoid having one form operating other one´s components, because this increses the dependency between them. Instead, declare public methods to do that, so the forms will depend on their interfaces, not their implementations.

I hope this helps.

نصائح أخرى

From your question (I added code-style to make it more clear):

I have a Form called ENP, defined in the EnpView unit. The ENP form, is created and shown from the handler event of a click a toolbar item in the Main Form (TPrincipal).

procedure TPrincipal.ENP1Click(Sender: TObject);
begin
  TENP.Create(self).Show();
end;

This does nothing with your ENP form variable.
You create an instance of the TENP form class and show it using Show, but the ENP variable is not assigned.
You cannot assign the instance to the ENP variable, as each button click creates a new instance (so you have multiple instances of TENP) around.

Then you create a convoluted depedency of a TAddEnp instance and the (never assinged ENP variable).
You do this by creating a TAddEnp instance (why TAddEnp here, and not TAddENP?) show it using Show (giving the users the opportunity to go back to the TENP instance and again click on the opAgregar button to create more instances of TAddEnp):

procedure TENP.opAgregarClick(Sender: TObject);
begin
  TAddEnp.Create(self).Show();
end;

Followed by having the TAddEnp depend on the ENP variable:

procedure TAddEnp.AgregarClick(Sender: TObject);
begin
//...
  ENP.clearGrid();
  ENP.populateGrid();
end;

This will indeed fail:

ClearGrid messages fails in line 1, with access violation:

procedure TENP.clearGrid();
begin
  Self.StringGrid.RowCount := 2;
  Self.StringGrid.Rows[1].Clear();
end;

The reason is that ENP is not assigned (by default it will be nil), so inside clearGrid, the Self will also be nil.

Solutions you could implement

  1. Keep a single instance of TENP and TAddEnp around, using ShowModal to force modality to prevent the user from clicking on the same buttons multiple times.
  2. Keep your existing Show behaviour, but binding each TAddEnp instance to the TENP instance it was created from.

For the first solution, your code will become this:

procedure TPrincipal.ENP1Click(Sender: TObject);
begin
  ENP := TENP.Create(Application);
  ENP.ShowModal();
  ENP.Release();
  ENP := nil;
end;

and

procedure TENP.opAgregarClick(Sender: TObject);
begin
  AddEnp := TAddEnp.Create(Application);
  AddEnp.ShowModal();
  AddEnp.Release();
  AddEnp := nil;
end;

The second will take more effort, as you need to prevent the use of the existing variables.

  • Delete the ENP variable.
  • Delete the AddENP variable.

Fix the self -> Self in the methods

procedure TPrincipal.ENP1Click(Sender: TObject);
begin
  TENP.Create(Self).Show();
end;

and

procedure TENP.opAgregarClick(Sender: TObject);
begin
  TAddEnp.Create(Self).Show();
end;

Here add the dependency:

procedure TAddEnp.AgregarClick(Sender: TObject);
var
  ENP: TENP;
begin
//...
  ENP := Owner as TENP; // Owner will be of type TENP because of the Create(Self) in the ENP1Click method
  ENP.clearGrid();
  ENP.populateGrid();
end;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top