Recent

Author Topic: Only class methods can be referred with class references  (Read 12996 times)

MorbidFractal

  • Jr. Member
  • **
  • Posts: 97
Only class methods can be referred with class references
« on: June 29, 2011, 10:45:25 am »
It would seem I do not have a 'method'... I shall explain by way of a simplified example.

Form1 the main Form

Code: [Select]
unit unit_form;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  unit_frame00,
  unit_frame01;

var
  FrameAA: TFrame00;
  FrameBB: TFrame01;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FrameAA := TFrame00.Create(nil);
  FrameAA.Parent := Panel1;
  FrameBB := TFrame01.Create(nil);
  FrameBB.Parent := Panel2;
end;

initialization
  {$I unit_form.lrs}

end.

It has two Panels and on creation creates two frames placing one on panel1 and the other on panel2.

The Frames,

TFrame00;

Code: [Select]
unit unit_frame00;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, StdCtrls;

type

  { TFrame00 }

  TFrame00 = class(TFrame)
    Edit01: TEdit;
    Edit02: TEdit;
    Edit03: TEdit;
    procedure EditChange(Sender: TObject);
    procedure EditUpdate(Edit1,Edit2,Edit3: String);
  private
    { private declarations }
    MyObj: TObject;
  public
    { public declarations }
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

uses
  unit_frame01;

procedure TFrame00.EditChange(Sender: TObject);
begin
  TFrame01.EditUpdate(Edit01.Text,Edit02.Text,Edit03.Text);//Error
end;

procedure TFrame00.EditUpdate(Edit1,Edit2,Edit3: String);
begin
  Edit01.Text := Edit1;
  Edit02.Text := Edit2;
  Edit03.Text := Edit3;
end;

constructor TFrame00.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  MyObj := TObject.Create;
end;

destructor TFrame00.Destroy;
begin
  MyObj.Free;
  inherited Destroy;
end;


initialization
  {$I unit_frame00.lrs}

end.

TFrame01;

Code: [Select]
unit unit_frame01;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, StdCtrls;

type

  { TFrame01 }

  TFrame01 = class(TFrame)
    Edit01: TEdit;
    Edit02: TEdit;
    Edit03: TEdit;
    procedure EditChange(Sender: TObject);
    procedure EditUpdate(Edit1,Edit2,Edit3: String);
  private
    { private declarations }
    MyObj: TObject;
  public
    { public declarations }
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

uses
  unit_frame00;

procedure TFrame01.EditChange(Sender: TObject);
begin
  TFrame00.EditUpdate(Edit01.Text,Edit02.Text,Edit03.Text);//Error
end;

procedure TFrame01.EditUpdate(Edit1,Edit2,Edit3: String);
begin
  Edit01.Text := Edit1;
  Edit02.Text := Edit2;
  Edit03.Text := Edit3;
end;

constructor TFrame01.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  MyObj := TObject.Create;
end;

destructor TFrame01.Destroy;
begin
  MyObj.Free;
  inherited Destroy;
end;

initialization
  {$I unit_frame01.lrs}

end.

They are 'duplicates'.

As suggested this is a simplified example. In this case what I am trying to do is transfer the content of the Edit boxes on FrameAA to the Edit boxes on FrameBB when a change occurs and vice versa.

If I do not declare,

procedure TFrame00.EditUpdate(Edit1,Edit2,Edit3: String);
procedure TFrame01.EditUpdate(Edit1,Edit2,Edit3: String);

within the Class Type definitions then the compiler does not recognise the references to,

Edit01.Text
Edit02.Text
Edit03.Text

Declaring them within the Class Type definitions prevents me from accessing the procedures from outside the unit with...

Quote
Only class methods can be referred with class references

Any pointers/solutions would be appreciated.
« Last Edit: June 29, 2011, 11:00:38 am by MorbidFractal »

Arbee

  • Full Member
  • ***
  • Posts: 223
Re: Only class methods can be referred with class references
« Reply #1 on: June 29, 2011, 01:32:46 pm »
There is a lot of thing I could see go wrong in your code.
One thing is that in the EditChange method you are calling TFramexx.EditUpdate.
You should not call the class definition  itself, but rather a variable that is of class TFramexx.

Each frame should therefore be aware of each other (which may be a tricky one, because of circular references).

To avoid that (and if these frame classes are identical anyway) why create two?  Why not one class and two instances thereof?
« Last Edit: June 29, 2011, 02:14:12 pm by Arbee »
1.0/2.6.0  XP SP3 & OS X 10.6.8

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Only class methods can be referred with class references
« Reply #2 on: June 29, 2011, 02:26:29 pm »
Arbee:
Quote
To avoid that (and if these frame classes are identical anyway) why create two?  Why not one class and two instances thereof?
I believe he is planning to have two different Frames in future. Maybe he only made it simple in this example.
Anyway, I maybe found solution but I didn't test it properly.
Add one variable to declaration of both your frames:
Code: [Select]
TFrame00 = class(TFrame)
    Edit01: TEdit;
    Edit02: TEdit;
    Edit03: TEdit;
    PairFrame: TFrame;
............
and
Code: [Select]
TFrame01 = class(TFrame)
    Edit01: TEdit;
    Edit02: TEdit;
    Edit03: TEdit;
    PairFrame: TFrame;
...............
You will have to determine somewhere which frames will be pair (it cannot be in constructor !!! - it is too early).
Then modify methods:
Code: [Select]
procedure TFrame01.EditChange(Sender: TObject);
begin
  EditUpdate(TFrame00(PairFrame).Edit01.Text,TFrame00(PairFrame).Edit02.Text,TFrame00(PairFrame).Edit03.Text);//Error
end;     
and
Code: [Select]
procedure TFrame00.EditChange(Sender: TObject);
begin
  EditUpdate(TFrame01(PairFrame).Edit01.Text,TFrame01(PairFrame).Edit02.Text,TFrame01(PairFrame).Edit03.Text);//Error
end;   
This is at least compilable and it avoids the circular reference as mentioned Arbee.
Have luck !

EDIT: I striked through piece of text because it is not true.
« Last Edit: June 29, 2011, 02:29:50 pm by Blaazen »
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

MorbidFractal

  • Jr. Member
  • **
  • Posts: 97
Re: Only class methods can be referred with class references
« Reply #3 on: June 29, 2011, 02:33:22 pm »
Hi. Arbee. Thanks for the reply.

and Blaazen. I shall read your suggestions now, I was just typing this whilst you were responding.

I am just presenting a 'do nothing' example that demonstrates what I am attempting to do so the two TFrames are, more or less, identical apart from names.

In the real program they will certainly be different but one will be repeatedly used by others to perform a specific but same function part of which involves it being updated by the other differing Frames and passing back information to update them.

The TFrames and their contents, the TEdits, are created at design time..

File|New|Frame

http://wiki.lazarus.freepascal.org/Frames

If you refer back to the main Form then that is where I create the Frames, FrameAA and FrameBB, and place them on the appropriate panels.

It sounds like you are suggesting that I should be attempting to reference the underlying procedure, EditUpdate, via FrameAA and/or FrameBB rather than directly through the Type definition which does sort of make sense.

However I would still be no further forward in terms of making such a thing happen.

Regarding 'awareness' then looking back at the code snippets I have,

in unit_frame00 that it uses unit_fram01
and
in unit_frame01 that it uses unit_fram00

under the second implementation clause. I believe this avoids complaints about circular references. Within the IDE then when I enter the code in unit_frame00,

TFrame01. EditUpdate(Edit01.Text,Edit02.Text,Edit03.Text)

the auto-complete picks up when I enter the first . and suggests the available procedure as an option. Obviously I still get the error but otherwise it recognises the availability and on compiling does not throw up a circular reference error....

Thank You Again


Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Only class methods can be referred with class references
« Reply #4 on: June 29, 2011, 02:47:34 pm »
Code: [Select]
procedure TFrame00.EditChange(Sender: TObject);
begin
  TFrame01.EditUpdate(Edit01.Text,Edit02.Text,Edit03.Text);//Error
end;
IMO this can never work. TFrame01 is just a class (=not real) and can have many "REAL" instances. How can compiler know which one of all created instances should select ? Or what if no instance will be created at all ? You are looking for "real" strings in "real" Edits therefore you need real instances and not classes.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

MorbidFractal

  • Jr. Member
  • **
  • Posts: 97
Re: Only class methods can be referred with class references
« Reply #5 on: June 29, 2011, 03:14:33 pm »
Quote
IMO this can never work. TFrame01 is just a class (=not real) and can have many "REAL" instances. How can compiler know which one of all created instances should select ? Or what if no instance will be created at all ? You are looking for "real" strings in "real" Edits therefore you need real instances and not classes.

Yes, I am known by myself as someone who does things that do not work. :-[

Your modification compiled because it meant the Frame was referring to its own procedure declared within itself. I want it, or the created version of it, to refer to the procedure in the other Frame.

As you and Arbee are saying it seems I need to reference the procedure via FrameAA or FrameBB rather than the Type/Class declaration itself so need some way of 'exposing' it

Scratches head. OK, as previously coded with FrameAA/FrameBB declared within unit_form the IDE will recognise,

FrameAA.EditUpdate(); [have to add the variables to be passed]...

within that unit..

Perhaps

With FrameAA do EditUpdate(Edit01.Text,Edit02.Text,Edit03.Text);

which causes no complaints... and auto-completes the Edit01.Text etc indicating it knows what I am on about.. so maybe if I move the Variable declarations out of unit_form and into unit_frame00 and unit_frame01 something better might happen.

Confident in my failure I shall go and try it in a while. I shall leave you know.

Thanks Again
« Last Edit: June 29, 2011, 03:16:09 pm by MorbidFractal »

MorbidFractal

  • Jr. Member
  • **
  • Posts: 97
Re: Only class methods can be referred with class references
« Reply #6 on: June 29, 2011, 03:41:02 pm »
OK.... fixed???.... maybe.

As you two suggested it was down to referencing a 'real' thing rather than its Type/Class definition. What it came down to was where the 'real' thing was declared and what got 'sight' of it or how it was exposed.

Update after a bit of a poke and tidy up.


MorbidFractal

  • Jr. Member
  • **
  • Posts: 97
Re: Only class methods can be referred with class references
« Reply #7 on: June 29, 2011, 04:01:57 pm »
unit_form The main form becomes,

Code: [Select]
unit unit_form;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  unit_frame00,
  unit_frame01;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FrameAA := TFrame00.Create(nil);
  FrameAA.Parent := Panel1;
  FrameBB := TFrame01.Create(nil);
  FrameBB.Parent := Panel2;
end;

initialization
  {$I unit_form.lrs}

end.
 

I am no longer declaring FrameAA and FrameBB as variable within this unit but the uses clause gives it access to declarations of them in unit_frame00 and unit-frame01.

I'm sorry but it is difficult, as a novice, to understand the order of declaration of things and where those declarations are made to achieve the right results without being moaned at... I might actually be getting there. On the other hand I might be breaking all the house rules.

unit_frame00

Code: [Select]
unit unit_frame00;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, StdCtrls;

type

  { TFrame00 }

  TFrame00 = class(TFrame)
    Edit01: TEdit;
    Edit02: TEdit;
    Edit03: TEdit;
    procedure EditChange(Sender: TObject);
    procedure EditUpdate(Edit1,Edit2,Edit3: String);
  private
    { private declarations }
    MyObj: TObject;
  public
    { public declarations }
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
  end;

var
  FrameAA: TFrame00;//Declared here to expose it externally

implementation

uses
  unit_frame01;//To give it access to FrameBB

procedure TFrame00.EditChange(Sender: TObject);
begin
  With FrameAA do FrameBB.EditUpdate(Edit01.Text,Edit02.Text,Edit03.Text);
  {References FrameBB exposed in the uses clause and saves having to write FrameAA.Edit01.Text etc}
end;

procedure TFrame00.EditUpdate(Edit1,Edit2,Edit3: String);
begin
  Edit01.Text := Edit1;
  Edit02.Text := Edit2;
  Edit03.Text := Edit3;
end;

constructor TFrame00.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  MyObj := TObject.Create;
end;

destructor TFrame00.Destroy;
begin
  MyObj.Free;
  inherited Destroy;
end;


initialization
  {$I unit_frame00.lrs}

end.

unit_frame01

Code: [Select]
unit unit_frame01;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, StdCtrls;

type

  { TFrame01 }

  TFrame01 = class(TFrame)
    Edit01: TEdit;
    Edit02: TEdit;
    Edit03: TEdit;
    procedure EditChange(Sender: TObject);
    procedure EditUpdate(Edit1,Edit2,Edit3: String);
  private
    { private declarations }
    MyObj: TObject;
  public
    { public declarations }
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
  end;

var
  FrameBB: TFrame01;//Declared here to expose it externally

implementation

uses
  unit_frame00;//To give it access to FrameAA

procedure TFrame01.EditChange(Sender: TObject);
begin
  With FrameBB do FrameAA.EditUpdate(Edit01.Text,Edit02.Text,Edit03.Text);
  {References FrameAA exposed in the uses clause and saves having to write FrameBB.Edit01.Text etc}
end;

procedure TFrame01.EditUpdate(Edit1,Edit2,Edit3: String);
begin
  Edit01.Text := Edit1;
  Edit02.Text := Edit2;
  Edit03.Text := Edit3;
end;

constructor TFrame01.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  MyObj := TObject.Create;
end;

destructor TFrame01.Destroy;
begin
  MyObj.Free;
  inherited Destroy;
end;

initialization
  {$I unit_frame01.lrs}

end.

and now things compile and run and the frames are 'talking to each other'. I might be certain that there would be a 'better' way but it works.

Once again, Thank You for providing the assistance. I shall now have to glue the hair I tore out yesterday back on.

Assuming I am right.. Do I mark this as 'Solved'?

 

TinyPortal © 2005-2018