Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
500 Users Online NOW
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi



Loremo - the 1.5 liter car coming in 2009




Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (0)


Published Objects in ComponentsComponent available for this articleFormat this article printer-friendly!Bookmark function is only available for registered users!
How to make properties which have subproperties in the Object Inspector
Product:
Delphi all versions
Category:
Component Writing
Skill Level:
Scoring:
Last Update:
02/21/2002
Search Keys:
delphi delphi3000 article borland vcl code-snippet Object Inspector Component subproperties drop-down Analogue Clock Publish published
Times Scored:
3
Visits:
2598
Uploader: duncan parsons
Company: DSP
Reference: N/A
Component Download: http://www.delphi3000.com/article/3039/AnalogueClock.zip
 
Question/Problem/Abstract:
Some properties of a component can 'drop-down' to reveal other properties (such as a Font property reveals various properties within itself). These are objects within the component, and a simple demonstration of how to add you own new 'drop-down' properties is given here. (You can also get a Static Analogue Clock Component too!!!)
Answer:



Please Note: I will only include here pertinent aspects of what is being explained. I will not flesh out all the examples for the sake of clarity.
-------------------------------------------------------------------------
To include an object within a component is a fairly simple matter, simply declare a field, and make a property public.

--
interface

type
  TMyComp=class(TComponent)
  private
    fFont:TFont;
  public
    property Font:TFont read fFont write fFont;
    constructor create(AOwner:TComponent);override;
    destructor destroy;override;
  end;

implementation

constructor TMyComp.create(AOwner:TComponent);
begin
     inherited create(AOwner);
     fFont:=TFont.Create; //create the Object into the field reference,
                          //  so it will not raise an exception
end;

destructor TMyComp.destroy;
begin
     fFont.free; //free the field to avoid memory leaks, etc.
     inherited;
end;

--
NB: When creating Objects, ALWAYS remember to free them, unless a help file tells you overwise (happens very rarely, eg exception handlers). Notice that what is created in the constructor is explicitly freed in the destructor.
--

This creates a fairly useless component admittedly, but it is an example after all! When accessing the Font property, it can be referenced in code using:

begin
     with MyComp1.Font do
          begin
               Color:=clBlue;
               Size:=10;
          end;
end;


This is all well and good, but what about the Object Inspector?
If we move the property from public to published, the Font property is now available, with the plus sign to 'drop-down' as required.

This is a step in the right direction.

However, this is not the whole story. What if we were devising a component which could logically take completely new objects as properties. For instance an analogue clock face - three similar objects would be obvious.. the hour, minute and second hands! Each is the same, save for customisable features, such as colour, thickness, etc.

So - let us construst our AnalogueHand object:

type
  TAnalogueHand=class
    Colour:TColor;
    Thickness:integer;
  end;

Here is an object, descended from TObject, which has the properties we require.

Let us put it into a Clock face component:

type
  TAnalogueClock = class(TGraphicControl)
  private
    fHourHand,fMinuteHand,FSecHand:TAnalogueHand;
  protected
    procedure SetHand(index:integer;value:TAnalogueHand);
  public
    constructor create(AOwner:TComponent);override;
    destructor  destroy;override;
  published
    property HourHand:TAnalogueHand   index 0 read fHourHand   write SetHand;
    property MinuteHand:TAnalogueHand index 1 read fMinuteHand write SetHand;
    property SecHand:TAnalogueHand    index 2 read fSecHand    write SetHand;
  end;

..

In the constructor, each field must be created separately, and freed on destruction:

constructor TAnalogueClock.create(AOwner:TComponent);
begin
     inherited create(AOwner);
     //Set up the Hand Objects
     fHourHand:=TAnalogueHand.create;
     with fHourHand do
          begin
               colour:=clBlue;
               Thickness:=2;
          end;
     fMinuteHand:=TAnalogueHand.create;
     with fMinuteHand do
          begin
               colour:=clRed;
               Thickness:=2;
          end;
     fSecHand:=TAnalogueHand.create;
     with fSecHand do
          begin
               colour:=clRed;
               Thickness:=1;
          end;
end;

destructor  TAnalogueClock.destroy;
begin
     fSecHand.free;
     fMinuteHand.free;
     fHourHand.free;
     inherited;
end;

procedure TAnalogueClock.SetHand(index:integer;value:TAnalogueHand);
begin
     case index of
          0 : fHourHand:=Value;
          1 : fMinuteHand:=Value;
          2 : fSecHand:=Value;
     end;
     invalidate;
end;
--
Notice that the Hands are written to all using the same procedure, SetHand, each with a different index to refer to it.
--

If we install this, we end up with our object, but the object inspector gives an Access Violation if we try to view the properties - not what we wanted!

The reason being that to descend our Hand Object from TObject is the wrong ancestor.. For objects which are of a temporary nature, this is fine, but to allow properties to exist abit longer, to have their properties stored in a persistent fashion (put very simply!) - we must descend from TPersistent.

So, our new hand declaration looks like:

--
type
  TAnalogueHand=class(TPersistent)
    Colour:TColor;
    Thickness:integer;
  end;
--

Rebuild, and the Access Violation has gone - hooray!! But, there are no subproperties!! An inspection of the Hand object could provide a clue.. With a standard component, for a property to appear in the object inspector, it must be published:

--
type
  TAnalogueHand=class(TPersistent)
  private
    fColour:TColor;
    fThickness:integer;
  published
    property Colour:TColor read fColour write fColour;
    property Thickness:integer read fThickness write fThickness;
  end;
--

Rebuild again - and we have subproperties within properties, droppong down without Access Violations, etc.

At runtime the new subproperties can be accessed by:

with AnalagueClock1.HourHand do
    begin
         Colour:=clOlive;
         Thickness:=4;
    end;

AnalagueClock1.SecHand.Colour:=clFuchsia;

--

This has been a quick and simple overview to providing subproperties in a component. More complicated user defined objects can be created, which may have further subproperties (try publishing a TCanvas Object, and see how many layers you get..).

In summary:
i.   descend your new object from TPersistant (if it is COMPLETELY new - as in
       the example);
ii.  ensure that any methods declared in the object are written (such as
       constructors, setting procedures, functions, etc). - I've forgotten this
       a few times!!
iii. use the standard of fields and published properties (and any public as
       required). The published properties will appear as subproperties.
iv.  ensure that when the new object is contained within a component that it is
       explicitly created and freed at the appropriate times.

This worked example appears in an expanded form in the component attached to this article. I had a requirement for a Clock face, but I needed it to be static - for inputting. All the Clock faces I found were very nice, but the darn things moved!! So I created my own static analogue clock face.

I make no apology for using British English within the component! Light diffractions have a 'U' (coloUr), and the free floating state contrary to digital has a 'UE' suffix (analogUE). If you don't like it - you have the source!!





Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment













 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
M. Shkolnik
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)