1. Technology
Send to a Friend via Email
RTL reference|Glossary|Tips/Tricks|FREE App/VCL|Best'O'Net|Books|Link To

Creating Custom Delphi Components, Part II
Page 1: Component references
More of this Feature
Page 2: Sets
Page 3: Binary properties
Page 4: Collections
Page 5: Sub-properties

Download Demo Projects
Join the Discussion
"Post your questions, concerns, views and comments to this article..."
Discuss!
Related Resources
Custom VCL development
Third party VCL
VCL using

Article submitted by: Peter Morris
"This article originally appeared in Delphi Developer. Copyright Pinnacle Publishing, Inc. All rights reserved."

This article is part two of a three part article on components. Part one covered the basic creating of components, part two will cover how to write advanced properties, how to write custom streaming for those properties, and sub-properties. The final part will cover property / component editors, how to write dedicated editors for your component / property, and how to write "hidden" components.

Quite often it is necessary to write components that perform more advanced functions. These components often need to either reference other components, have custom property data formats, or have a property that owns a list of values rather than a single value. In this part, we will explore various examples covering these very subjects, starting with the most simple.

Component references
Some components need to reference other components. TLabel for instance has a "FocusControl" property. When you include an ampersand in the "Caption" property it underlines the next letter (&Hello becomes Hello), pressing the shortcut key ALT-H on your keyboard will trigger an event in your label. If the "FocusControl" property has been set focus will be passed to the control specified.

To have such a property in your own component is quite simple. All you do is declare a new property, and set the property type to the lowest base class that it may accept (TWinControl will allow any descendent of TWinControl to be used), but, there are implications.

type
  TSimpleExample = class(TComponent)
  private
    FFocusControl : TWinControl;
  protected
    procedure SetFocusControl(const value : TWinControl); 
      virtual;
  public 
  protected
    property FocusControl : TWinControl
      read FFocusControl
      write SetFocusControl;  
  end; 

procedure TSimpleExample.SetFocusControl(const Value : TWinControl);
begin
  FFocusControl := Value;
end;

Take the above example. This is quite a simple example (hence the component name) of how to write a component that references another component. If you have such a property in your component the Object Inspector will show a combobox with a list of components that match the criteria (all components descended from TWinControl).

Our component may do something like

procedure TSimpleExample.DoSomething;
begin
  if (Assigned(FocusControl)) and 
     (FocusControl.Enabled) then 
    FocusControl.Setfocus;
end;

First we check if the property has been assigned, if so we set focus to it, but there are situations when the property is not Nil yet the component it points to is no longer valid. This often happens when a property references a component that has been destroyed.

Luckily Delphi provides us with a solution. Whenever a component is destroyed it notifies its owner (our form) that it is being destroyed. At this point every component owned by the same form is notified of this event too. To trap this event we must override a standard method of TComponent called "Notification".

type
  TSimpleExample = class(TComponent)
  private
    FFocusControl : TWinControl;
  protected
    procedure SetFocusControl(const value : TWinControl); 
      virtual;
  public 
  protected
    procedure Notification(AComponent: TComponent;
      Operation: TOperation); override;
    property FocusControl : TWinControl
      read FFocusControl
      write SetFocusControl;  
  end; 

procedure TSimpleExample.SetFocusControl(const Value : TWinControl);
begin
  FFocusControl := Value;
end;

procedure TSimpleExample.Notification(AComponent : TComponent; 
  Operation : TOperation);
begin
  If (Operation = opRemove) and 
     (AComponent = FocusControl) then 
    FFocusControl := Nil;
end;

Now when our referenced component is destroyed we are notified, at which point we can set our reference to Nil. Note, however, that I said "every component owned by the same form is notified of this event too"

This introduces us with another problem. We are only notified that the component is being destroyed if it is owned by the same form. It is possible to have our property point to components on other forms (or even without an owner at all), and when these components are destroyed we are not notified. Yet again there is a solution.

TComponent introduces a method called "FreeNotification". The purpose of FreeNotification is to tell the component (FocusControl) to keep us in mind when it is destroyed.

An implementation would look like this

type
  TSimpleExample = class(TComponent)
  private
    FFocusControl : TWinControl;
  protected
    procedure SetFocusControl(const value : TWinControl); 
      virtual;
  public 
  protected
    procedure Notification(AComponent: TComponent;
      Operation: TOperation); override;
    property FocusControl : TWinControl
      read FFocusControl
      write SetFocusControl;  
  end; 

procedure TSimpleExample.SetFocusControl(const Value : TWinControl);
begin
  if Assigned(FFocusControl) then 
    FFocusControl.RemoveFreeNotification(Self);

  FFocusControl := Value;

  if Assigned(FFocusControl) then 
    FFocusControl.FreeNotification(Self);
end;

procedure TSimpleExample.Notification(AComponent : TComponent; 
  Operation : TOperation);
begin
  if (Operation = opRemove) and 
     (AComponent = FocusControl) then 
    FFocusControl := Nil;
end;

When setting our FocusControl property we first check if it is already set to a component. If it is already set we need to tell the original component that we no longer need to know when it is destroyed. Once our property has been set to the new value we inform the new component that we require a notification when it is freed. The rest of our code remains the same as the referenced component still calls our Notification method.

Next page > Sets > Page 1, 2, 3, 4, 5

Creating Custom Delphi Components >>
>> Part III.

All graphics (if any) in this feature created by Peter Morris.

More Delphi
· Learn another routine every day - RTL Quick Reference.
· Download free source code applications and components.
· Talk about Delphi Programming, real time.
· Link to the Delphi Programming site from your Web pages.
· Tutorials, articles, tech. tips by date: 2001|2000|1999|1998 or by TOPIC.
· NEXT ARTICLE: Lookup! - DB/15.
Chapter fifteen of the free Delphi Database Course for beginners. See how to use lookup fields in Delphi to achieve faster, better and safer data editing. Also, find how to create a new field for a dataset and discuss some of the key lookup properties. Plus, take a look at how to place a combo box inside a DBGrid.
Stay informed with all new and interesting things about Delphi (for free).
Subscribe to the Newsletter
Name
Email

Got some code to share? Got a question? Need some help?

©2014 About.com. All rights reserved.