Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 346
  • Last Modified:

AV Error in accessing a public method

I have a User Interface for a game like this:
Form1 - main container
Form2 - inside Form1
Form3 - inside Form2
Form1 is created by Delphi, Form2 is dynamically created and its parent set to Form1, Form3 is also dynamically created and its parent is set to Form2.
I need to call a paint procedure in Form2 from Form3. I do this via a public method on Form2, however I get an AV error bec/ 'Self' inside the Form2 public method is nil. So all references to Self inside this Form2 public method produce an AV.
Accessing public methods for Form1 (the main container) are ok, but not so for Form2. How can I fix this?
I should mention that Form2 and Form3 were coded separately (and ran fine) and then added to Form1, which is why this error was not caught earlier.

public method in Form2:
public
    { Public declarations }
    procedure paintBackground(input: TPoint);

Then, from Form3 onMouseMove:

Unit2.Form2Container.paintBackground(Point(X, Y));

Form2 public method is called but AV error occurs when reference to Self is made:

Self.canvas.brush.color := clRed
0
dc_mo
Asked:
dc_mo
  • 3
  • 2
1 Solution
 
Ephraim WangoyaCommented:

This could be due to a couple of reasons which we really cant tell unless we see the code

You could be destroying Form2 and still trying to reference it in your code. If you are using AutoCreated forms especially, be care full of things like Action := caFree

Otherwise we need more information
0
 
dc_moAuthor Commented:
Well, as I mentioned, only Form1 is created automatically. As for Form2 and Form3, this is how they're created:

procedure TForm1.FormCreate(Sender: TObject);
begin
  form2 := TForm2.Create(Self);
  form2.Parent := IDE;
  form2.Show;
end;

I actually simplified things quite a bit and made a test project with the 3 forms as indicated. Declaring and calling any form2 public method from form3 causes AV error. Please try it yourself:
Form 1 code (Form1 created automatically):

uses Unit2;

var
  Form2: TForm2;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form2 := TForm2.Create(Self);
  Form2.Parent := Self;
  Form2.Show;
end;

Same thing for Form 2:

type
  TForm2 = class(TForm)
private
  { Private declarations }
  procedure paintBGLogic(input: TPoint);
public
 { Public declarations }
    property PaintBackground: TPoint write paintBGLogic;
end;

uses Unit3;

var
  Form3: TForm3;

procedure TForm2.FormCreate(Sender: TObject);
begin
  Form3 := TForm3.Create(Self);
  Form3.Parent := Self;
  Form3.Show;
end;

procedure TForm2.paintBGLogic(input: TPoint);
begin
 Self.canvas.brush.color := clRed; //oops! reference to self causes AV error
 Self.canvas.rectangle(input.X, input.Y, 100, 100); 
end;


Now for Form3:

type
  TForm3 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
   end;

var
  Form3: TForm3

implementation

{$R *.dfm}

uses Unit2;

rocedure TForm3.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  //call Form2 public method
  Unit2.Form2.PaintBackground := Point(X, Y);
end;

Open in new window

0
 
Ephraim WangoyaCommented:

You need to get rid of the global form declarations and make them members of the forms they are intended to be on. that will be more cleaner. You can add a check for the validity of Form2.
Also don't use property in this case, call the function directly

Last thing, the logic does not seem correct, you are drawing on Form2 Canvas using dimensions from Form3, thus you are assuming Form3 is the exact size of Form2


type
  TForm2 = class(TForm)
private
  { Private declarations }
public
 { Public declarations }
    procedure PaintBackground(Input: TPoint);
end;

procedure TForm2.PaintBackground(Input: TPoint);
begin
 Canvas.brush.color := clRed; //oops! reference to self causes AV error
 Canvas.rectangle(input.X, input.Y, 100, 100); 
end;

//////////////////////

procedure TForm3.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  //call Form2 public method
  if Assigned(Form2) then
    Form2.PaintBackground(TPoint(X, Y)); //this is actually painting on form2 canvas
end;

Open in new window

0
 
dc_moAuthor Commented:
Sorry but that doesn't seem to fix it. Please email me and I'll send you a simple project to test. myspac09[at]gmail.com
0
 
Ephraim WangoyaCommented:

Removed the local declarations of Form2 and Form3 which were clashing with the global declarationa

Unit1
.........

implamentation

{$R *.dfm}

uses Unit2;

var
  Form2: TForm2;
.........


and in
Unit2
.........

implamentation

{$R *.dfm}

uses Unit3;

var
  Form3: TForm3;
.........
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now