Issue with custom class

Delphi_developer
Delphi_developer used Ask the Experts™
on
Hi

I have a custom class defined:

tTelemetryPanel = class(Panel)
public
  Parent:TWinControl
  Constructor Create(AOwner: TComponent); Override;
private
  property  fParent: TWinControl read Parent write Parent;
Published
    Procedure CreateTelemetryPanel;
end;


...

and

Procedure tTelemetryPanel.CreateTelemetryPanel;
Begin

  TTelemetryPanel(Self).OnResize := myPanelResize;
  TTelemetryPanel(Self).BorderStyle := bsNone;


  vImage := Timage.Create(Nil);

  vImage.Parent := Self;
  vImage.Align := alLeft;

end;

this is defined in new unit.

In Form1 on button click I have this:

procedure TForm1.Button1Click(Sender: TObject);
var vA,vB:TTelemetryPanel;
begin
  vA:=TTelemetryPanel.Create(Self);
  vA.Parent:=Form1.SCPanel147;
  vA.CreateTelemetryPanel;

  vB:=TTelemetryPanel.Create(nil);
  vA.Parent:=Form1.SCPanel144;
  vB.CreateTelemetryPanel;
end;


So, I would like to have two TelemetryPanels on SCPanel147 and 144.

I have a couple of questions:

1. I had to set public 'Parent' otherwise this code failed:

vA.Parent:=Form1.SCPanel147;

Why does it work like that? Shouldn't Parent property work as a basic property?

2. Now it fails on  

vImage.Parent := Self;

when I try to create vImage on this TelemetryPanel. Why it doesn't work? I also tried

 vImage.Parent := TTelemetryPanel(Self);

also didn't work.


3) I would like to have new telemetry panels's width and height as it's parent! How can I do this, can I do this in Create constructor or do I need to have separate code to assign these values?



Thank you
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Try setting the Timage as a subcomponent

Here you have the help entry for it:

Call SetSubComponent to indicate that this component is or is not a subcomponent. A subcomponent is a component whose Owner is a component other than the form or data module in which it resides. Unless such a component calls SetSubComponent with IsSubComponent set to true, its published properties will not be saved to the form file.
 
IsSubComponent indicates whether the component is a subcomponent (true) or not (false).
 
SetSubComponent is called at design time either
 
From the constructor of a component that always acts as a subcomponent. In this case, the component calls its own SetSubComponent method from the constructor with IsSubComponent set to true.
 
Immediately after constructing an instance of the subcomponent. In this case, the Owner calls the SetSubComponent method of a component it has just instantiated, with IsSubComponent set to true.
Oracle dba
Top Expert 2009
Commented:
you are missing all the basics in component creation
you'll have to read up on Delphi to be succesfull at creating components
try this ebook
http://veerle-en-geert.be/delphi/ebooks/Delphi%20-%20Teach%20Yourself%20Borland%20Delphi%204%20in%2021%20Days.pdf

i'll start at the top

// Remark 1
// Changed Panel to TPanel
TTelemetryPanel = class(TPanel)
private
  // Remark 2
  // TPanel is descendant from TWincontrol, so it allready has a Parent
  //  property  fParent: TWinControl read Parent write Parent;
public
  // Same as remark 2
  //Parent:TWinControl
  constructor Create(AOwner: TComponent); override;
  // Remark 3
  // Create ? this is only done with a constructor
  // you can set all necessary properties in a constructor
  // so you don't need below procedure
  // procedure CreateTelemetryPanel;
  // Remark 4
  // published is only for properties that need to appear in the Delphi IDE (for nothing else)
end;
// Remark 5
try and work in the correct order, private protected public published
easier to follow ...

looking at what you want,
you seem to want a panel with a image (left aligned) in it ?

then your class declaration would look more like this
type 
  TTelemetryPanel = class(TPanel)
  private
    fImage: TImage;
    procedure SetImage(const Value: TImage);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published 
    property Image: TImage read fImage write SetImage;
  end;
 
procedure TTelemetryPanel.SetImage(const Value: TImage);
begin
  if Assigned(Value) then 
    fImage.Assign(Value);
end;
 
constructor TTelemetryPanel.Create(AOwner: TComponent); 
begin
  inherited Create(AOwner);
  fImage := TImage.Create(Self);
  fImage.Parent := Self;
  fImage.Align := alLeft;
end;
 
destructor TTelemetryPanel.Destroy; 
begin
  FreeAndNil(fImage);
  inherited Destroy;
end;
 
  

Open in new window

Geert GOracle dba
Top Expert 2009

Commented:
1. I had to set public 'Parent' otherwise this code failed:
>>You descended from Panel, not TPanel
didn't this give a compiler error ?

2. Now it fails on
>>Probably because it doesn't know which parent as it is declared in TPanel allready  

3) I would like to have new telemetry panels's width and height as it's parent! How can I do this, can I do this in Create constructor or do I need to have separate code to assign these values?
>>set Align to alClient

it would be better to describe what you want with an image ...
Exploring SQL Server 2016: Fundamentals

Learn the fundamentals of Microsoft SQL Server, a relational database management system that stores and retrieves data when requested by other software applications.

Geert GOracle dba
Top Expert 2009

Commented:
if this is for your telemetry component
i'll give you a rough estimate so you know what the workload will be (this is not to put you off)

for me (it would take me roughly 3 months to get this working)
this is for just the basic things (drawing the graphs and interaction)
the real testing in a production environment would probably add a month for testing and tweaking
this is normal workdays
i would need to up my skills for painting of graphs
and probably some math would be involved too

this is so you know what you are getting into

you'll need to read some books to get this component working
Sam's teach yourself Delphi is the start
Mastering Delphi (very good for component creation)
Tomes of Delphi good too

if your a beginner at delphi, it will probably take 6 to 12 months

Author

Commented:
Geert, thank you, but here is the situation:

I already have the telemetry panel done. It is a very simple panel, which consist of scrollbox and 2 images - create a graph. The 'interactive mode' - to mark points on the graph (image) on MouseOver and some other very simple, but useful actions. So, it works very well, for a prototype... I still need to polish small issues, like antialiasing lines and some discrepancies in scaling.

Now it works as a simple program where all objects are created in code and it all works well... but I need 2 or more of them, so I just wanted to have one class, called twice and create all objects on two separate normal panels. (I was sure component is called when you install new VCL object - component; I didn't know a new class type is already regarded as a component... ).

I got this very basic, but almost suitable/usable, in a few days. I'm a total beginner in components, classes, but not really in Delphi.

The other way to make this work, is to have one unit for each telemetry panel, this would work, but clearly is not a good solution.

I will try you suggestions now. I'll let you know how it goes.
Geert GOracle dba
Top Expert 2009

Commented:
a component is something that functions on it's own (or allmost)

maybe you need to go in the direction of Frames ?
you can create frames like forms, then right click on it to add to Component palette
and then drop them on a form (multiple times too) from the component palette

Author

Commented:
I would like to make this work, if possible...

It seems I'm getting somewhere. Now I have a procedure 'DrawGraphTemplate', which draws graph's grid, but it fails on this code:


from Form1.Button1clisk I call 'DrawTelemetry' which calls 'DrawGVraphTemplate', which has:

ImageGraph.Picture.Bitmap.Height := ImageGraph.Height;
ImageGraph.Picture.Bitmap.Width := ImageGraph.Width; // FAILS HERE: The parameter is incorrect
ImageGraph.Canvas.Brush.Color := clWhite;

Any suggestions?

I have:
private
    fImageLeft: TImage;
    fImageGraph: TImage;
    fSB: TScrollBox;
    procedure SetImageLeft(const Value: TImage);
    procedure SetImageGraph(const Value: TImage);
    procedure SetSB(const Value: TScrollBox);

Published
     property ImageLeft: TImage read fImageLeft write SetImageLeft;
     property ImageGraph: TImage read fImageGraph write SetImageGraph;
     property SB: TScrollBox read fSB write SetSB;


And also a follow up question... what is the difference if I use 'fImageLeft' or 'ImageLeft', in the code of tTelemetryPanel own's procedures?

Thanx
Geert GOracle dba
Top Expert 2009

Commented:
good for you to have this working allready

ImageLeft is a property
fImageLeft is a private variable (in this case)

a property is like using a in between person to do things (like a waiter)
you tell the waiter (property) to set a certain value
you ask the waiter (property) to get something (a value)

where this waiter gets or sets the value is component specific

the component itself doesn't need to use the waiter, it can go directly in private methods (procedures and functions)
as from protected methods it is supposed to use the property

Have you checked if Picture and Picture.Bitmap <> nil ?
if not Assigned(ImageGraph.Picture.Graphic) or ImageGrap.Picture.Graphic.Empty then
  ImageGraph.Picture.Graphic := TBitmap.Create;

ImageGraph.Picture.Bitmap.Height := ImageGraph.Height;
ImageGraph.Picture.Bitmap.Width := ImageGraph.Width; // FAILS HERE: The parameter is incorrect
ImageGraph.Canvas.Brush.Color := clWhite;

Same for ImageLeft

if these lines are in a private method then use fImageGraph

how did you define "DrawTelemetry"

type
  TTelemetryPanel = class(TPanel)
  private
  protected
  public
    procedure DrawTelemetry; virtual;
  end;

can you call DrawTelemetry directly ?
or is DrawTelemetry called from the method Paint ?

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial