Sie sind auf Seite 1von 16

Custom Component Development in Delphi

Custom Component Development in Delphi Everything about creating custom components in Delphi. The ultimate source.

Everything about creating custom components in Delphi. The ultimate source.

That's why you love Delphi!

I think we can all agree: components are essential elements of the Delphi environment. One of the most important features of Delphi is that we can use Delphi to create our own components. We can derive a new component from any existing component, but the following are the most common ways to create components: modifying existing controls, creating windowed controls, creating graphic controls, subclassing Windows controls and creating nonvisual

components. Visual or not, with or without property editor, from scratch

you name it.

Developing Delphi components isn't a simple task, it involves quite a bit of knowledge of the VCL. However, developing custom components is not an impossible task; writing components is just pure programming.

Articles, papers, tutorials What follows is a list of articles that deal with custom component development in Delphi.

Fullscreen Accessing protected members of a component Many Delphi components have useful properties and methods that are marked invisible ("protected") to a Delphi developer. In this article you will find the workaround to this problem - thus enabling you to access a DBGrid's RowHeights property, for example. Creating Custom Delphi Components - Inside and Out This tutorial will explain component writing to you, which should result in more code reuse. It will go over properties, events and methods, and will also explain how to install components. The final part of this tutorial is about Object-Oriented design. Creating Custom Delphi Components, Part I This first part demonstrates some of the best approaches to building components, and at the

Delphi Components, Part I This first part demonstrates some of the best approaches to building components,
Delphi Components, Part I This first part demonstrates some of the best approaches to building components,
Delphi Components, Part I This first part demonstrates some of the best approaches to building components,

same time provides tips on deciding on the best base class to inherit from, using virtual declarations, the complexities of overriding, and so on.

Creating Custom Delphi Components, Part II Quite often it is necessary to write components that Creating Custom Delphi Components, Part II 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. We will explore various examples covering these very subjects, starting with the most simple. Ads

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

More resources

First, if you want more, consider buying a book on Developing custom components.

Second, why not try locating an existing (with source perhaps) component you are looking for. Third, when you are 100% sure there is no such question on custom component

development you can't answer

you have to do is to ask a question on the Delphi Programming Forum and wait for answers.

there

will be something that you don't know. Everything

If you still need more samples

try the second page

Articles, papers, tutorials Here is a list of articles that deal with custom component development in Delphi.

VCL Component Messages [RTF] Component Messages (CM_) are generated only by the VCL and are not reflected Windows Messages (WM_), as one may assume. In spite of that Component Notifications (CN_) are reflected Windows Messages. The idea behind it is, that Windows often sends messages to a parent window of a control instead of the control itself. The VCL simply converts (reflects) these messages to Component Notifications and then sends it to the control, for which the message originally was meant.

Delphi Component Building. In this article, read about every aspect of Delphi Component building. Design a TTicTacToe component and learn about: how to build our own components for

Delphi, how to add properties, methods and custom events to them, how to wrap them around DLLs, how to install them, how to design a palette bitmap and write on- line help to support the component user.

continue reading below our video

Building SuperComponents in Delphi [download] SuperComponents, also known as aggregate or compound components, are collections of existing sub-components and their relationships combined into a single component. The collections are typically arranged inside a container parent component that manages the visual layout of the sub-components.

Accessing protected members of a component

sub-components. Accessing protected members of a component Many Delphi components have useful properties and methods

Many Delphi components have useful properties and methods that are marked invisible ("protected") to a Delphi developer. In this article you will find the workaround to this problem - thus enabling you to access a DBGrid's RowHeights property, for example.

Have you ever caught yourself in talking to yourself? A discussion like the one below perhaps? "Hmm, that DBNavigator is really cool, but if I could only lay my hands on the buttons and those pictures it displays?", or "I could really use the OnClick event for the DBGrid, but why is it not accessible in the Object Inspector?!", or "If I could just change the height of that title row in the DBGrid".

A little OOP story As you probably know (and those who do not will learn now), in Delphi OOP the protected data of a class is accessible to any method that appears in the same unit as the class. In Delphi class declaration, every member of a class has an attribute called visibility, which is indicated by one of the reserved words private, protected, public, published, or automated. If you are not familiar with the meaning of those keywords, please read at least some of the pages of the "Creating Custom Delphi Components - Inside and Out" article.

Recall the self-dialog above, what if you really need to get your hands on the Height property of the first row (where titles are displayed) of a DBGrid component.

In this article, you'll find out about a technique sometimes called the "Protected Hack" - deriving (subclassing) a component from an existing Delphi component with the only purpose or exposing the protected properties and methods.

Note: Another workaround to this "problem" is to create a new component derived from the component you want to hack and make the properties either public or published. This would end up in installing the new component on the Palette so you can access it from everywhere. However, many times you'll only need to expose only one property or method (presumably limited to a single unit in your code) - why bother with creating a whole new component?

"Protected Hack" The general technique explained here can be used to surface hidden (that is, "protected" in Delphi OOP jargon) properties and methods for Delphi classes (components). If you know that an ancestor could do something (handle an event, access a property, execute a method) this is how to make the descendant do it:

Let's say we need to hack a DBGrid. What we want to access is the RowHeights property.

Make sure you are editing the unit where the DBGrid is declared (for example: DBGrid1 dropped on Form1, so we are editing the Unit1.pas)

Create a noticeably worthless derived class:

THackDBGrid = class(TDBGrid);

Apparently, the class THackDBGrid derived like this does not bring any new functionality to DBGrid.

Though, it does provide the *free* access to all the protected members of the DBGrid component.

To use once protected members, you must typecast the component you refer too to the new (descendant) class.

Now, let's see some Delphi code. Assume you have a Delphi form (Form1) with a DBGrid (DBGrid1) displaying some data. To access the protected RowHeights property of that DBGrid you first hact the DBGrid comonent. Here's the portion of the Unit1.pas unit - where Form1 is declared:

uses Windows, Messages,

, Grids, DBGrids,

;

type THackDBGrid = class(TDBGrid);

type TForm1 = class(TForm) DBGrid1: TDBGrid;

Note the THackDBGrid declaration! Now, to change the height of the title row of the DBGrid1 you simply typecast DBGrid1 to THackDBGrid like:

//makes the Title's row 20 px in height (if displayed) THackDBGrid(DBGrid1).RowHeights[0] := 20;

Ok, that's it. RowHeights?! Yes, the RowHeights property of a TCustomGrid (the TDBGrid derives from) gives the height (in pixels) of all rows in the grid. In TDBGrid this property is protected - in THackDBGrid it is editable!

Note that the next assignemet gives the compile time error: "Undeclared identifier: RowHeights".

DBGrid1.RowHeights[0]:=20;

It's working!

Yep, it is. This is why: the THackDBGrid automatically inherits all the protected members of the TDBGrid (and all public, private, etc. of course), due to the fact that THackDBGrid is in the same unit as the code that accesses the protected property, the protected property is available.

Howcome?

Note: do not think that you can define the THackDBGrid in another unit - the code will no longer compile.

Another approach - no type-casting. If you need to access the protected members of a component but do not want to use type casting, you can declare the new (hacked) class with the same name as the old class:

type TDBGrid = class(DBGrids.TDBGrid);

Now, when accessing any protected member, you do not need to use the THackDBGrid(DBGrid1).Something syntax; Delphi will use the modified component as if it were the old one. Therefore a line like DBGrid1.RowHeights[0]:=20; will compile.

Warning! This is a hack - a very bad OOP technique. There are reasons that components do not expose certain members of their class declaration. Use the technique explained in this article at your own risk.

Note: "a hack" - means that it breaks standard OOP practices. This "hack" works (and will work in future Delphi version) because it relies on a specific Delphi Pascal OOP feature.

Creating Custom Delphi Components - Inside and Out

feature. Creating Custom Delphi Components - Inside and Out Page 1: About components, properties, methods and

Page 1: About components, properties, methods and events

Article submitted by: Alistair Keys

What's This Tutorial About? This tutorial will explain component writing to you, which should result in more code reuse. It will go over properties, events and methods, and will also explain how to install components. The final part of this tutorial is about Object-Oriented design.

What Are Components? Components are simply little bits of an overall system. If you have had any experience with Object-Oriented design, please don't shoot me for such a simplistic explanation - I'll do better, honest ;-). Components can help code reuse - if you find yourself repeating the same code, you can write a component for your task and place it on future projects with two mouse clicks.

Have a look at the Delphi component palette. You will see all sorts of objects - buttons, checkboxes, shapes and so on. If you find you have a recurring task that is getting pretty monotonous, you can create a component to do the job for you. Once you've finished it, you can install it and use it like any other.

Properties Properties are data held by the component. An example here would be a "car" component, which would properties for "PaintColour", "Manufacturer", and so on. You can consider properties to be just variables, although they are more complex than that.

When you are defining properties, you usually specify three things: its data type, how to read the property and how to write the property (if applicable). The first is obvious; if you want the property, you need to know what it is actually representing! The next two aren't quite as obvious.

Accessing properties seems straightforward

accessing Button1's Caption property). This just seems like a simple variable assignment, and that's probably what

you assumed it was. Well, it's not! Delphi performs some trickery and actually does some work behind the scenes. So:

we've all done it (e.g. "Button1.Caption := 'xyz';", where we're

When accessing properties, you could either be using variables directly or calling functions behind the scenes!

The standard property declaration looks like this:

property SomeProperty: Integer read FMyInteger write SetMyInteger;

This defines a property "SomeProperty", of type Integer. Note that properties are not actually variables in themselves, just ways of accessing other variables! Thus, the variable actually accessed with "SomeObject.SomeProperty" will be FMyInteger. Now for the interesting bit: the read and write parts say how to access the data. In this case, when the property is read (e.g. "if SomeObject.SomeProperty = 1") the value is taken directly from the variable, as if the code had said "SomeObject.FMyInteger". However, when the property is set, it is not done directly! The code actually calls a SetMyInteger procedure, which would be of the form:

procedure SetMyInteger(NewValue: Integer);

This gets called instead, as if the code had said "SomeObject.SetMyInteger(23)" instead of "SomeObject.SomeProperty := 23".

Now, the read and write parts can specify direct data access (by putting the variable name) or via procedures/functions (by putting the procedure/function name). To give another example, here's a read-only property that gets its data from a function:

property SomeReadOnlyProperty: Boolean read GetMyValue;

This property cannot be written to, which safeguards the data nicely :-). The GetMyValue function would be of the form: "function GetMyValue: Boolean;" Whenever the property is accessed, it would call this function to retrieve

the value

SomeObject.GetMyValue = True then" behind the scenes.

so the code "if SomeObject.SomeReadOnlyProperty = True then" would get translated into "if

Important note! The variables (e.g. FMyInteger) and procedures/functions (e.g. GetMyValue, SetMyInteger) are not available to the outside world! They are hidden away using "private" or "protected", so any direct calls would result in errors. This is good, as otherwise the entire purpose of read/write specifiers would be defeated. Private, protected and other such keywords will be explained (much) later.

Advantages of Properties You should have noticed why properties are pretty cool, but here's a summary:

They allow you to say how data gets accessed, protecting it

They save you from 50,000 "get/set" lines of code, helping readability

They allow you to check data integrity before changing the variables

The first one is pretty obvious, really. If you declared your variables publicly they could be changed in any old way. However, you can still allow direct access to your variables if you so desire. Properties allow you to change the behind-the-scenes way of getting or setting data without having to rewrite any code that uses the component!

The second point is something that makes you really appreciate Delphi. In other languages (for example C++) you do need to say "someObject.setThisValue(23)" everywhere. This makes your code less readable and just plain sucks! It, in my view, reduces the readability as it detracts from your main intent: you want to change the value, not call the function! Delphi has provided an elegant mechanism to avoid this kind of unnecessary code.

The last point is good for efficiency - if you have a graphical component, for example, you want to reduce the drawing as much as possible. This can be done by a set procedure that checks if the old value is different from the new value. Here's an example:

procedure TSomeComponent.SetBackgroundColour(NewColour: TColor); begin if NewColour <> FBackgroundColour then begin FBackgroundColour := NewColour; Invalidate; // redraws the component end; end;

This means that your component will only redraw itself if it gets a different property value. This technique can be applied elsewhere, with error checks and other such data checking.

Methods Methods are very important! These are procedures or functions, and define the behaviour of your objects. They are defined in the usual way, with one-line prototypes in the component and definitions later on.

Events

Events get defined by you, and are called whenever you want to notify the programmer of something. You can usually ignore these until you get more experienced with components. They boil down to pointers to class procedures, which means slight complications. Events will be covered later, so don't worry too much about them.

Question, Suggestions If you have any questions or comments to this (huge) article, please post them on the Delphi Programming Forum. Discuss!

Creating Custom Delphi Components - Inside and Out

Discuss! Creating Custom Delphi Components - Inside and Out Page 2: New Component Creating a Component

Page 2: New

Component

Creating a Component

Get the source code here: Line.zip (1Kb)

We'll start off at the deep end. We're going to create a simple component, called TLine. It will be a graphical control that will draw a line in one of four directions. It won't do anything fancy, but it will deal with properties, drawing and other useful stuff.

How Do We Start? Every component needs a base class. This class is simply the "Big Daddy" object for it, from which the component takes all properties, events and methods. For example, if you were writing a new type of button you might make the base class "TButton". Your new control would have all the TButton's properties (like caption, etc), all the Button's base class's stuff, and so on.

There are lots of possible base classes. Here's a small selection:

Type of component

Recommended Base Class

Generic, non-visual component

TComponent

Lightweight visual component

TGraphicControl

Visual component that needs focus

TCustomControl

Form-type object

TCustomForm

This is, of course, a small snippet of the possible cases you might need. We're interested in a small visual control, so TGraphicControl is the best base class for us. There's no need for TCustomControl because our component won't need window focus.

We can get started now. Go to File->New and select component. You'll be presented with a dialogue box. Fill it out like this:

The only two things you need to fill out are the "Ancestor type" and "Class

The only two things you need to fill out are the "Ancestor type" and "Class name" boxes. The rest get filled out automatically. Once you've done that, click the OK button and you get transported to the code editor with a skeleton class written out.

First we need to let the compiler know what we'll be using. Each unit (a file, usually containing a class) has a "uses" clause. This lists what other files will be needed to compile the unit. Without this the compiler would have a really hard job so it's up to us to make sure it's correct.

Note:

The following section about adding Graphics to the uses clause is relevant for Delphi 6 (and possibly Delphi 5). Delphi 4 adds Graphics automatically so if you start a new component and the uses clause has "graphics" in it then you don't need to do the next part.

You usually don't notice the "uses" clause as it's filled out with a large number of units by default (such as classes, sysutils, etc.). These units include most of the functionality you require. However, sometimes you have to add your own units (which usually listed in the help files for the appropriate class/procedure/function/type). We'll be needing the type TColor, which represents a colour. If you look this up in the help file you'll see it's within the 'Graphics' unit. Let's add that now before we start. Go to the very top of the file and find the uses part. It will look like this:

// <-- name of file without .pas unit Line;

interface

uses Windows, Messages, SysUtils, Classes, Controls

You can see that each unit needed is simply separated by a comma. We'll add Graphics to the uses unit. Make this change:

uses Windows, Messages, SysUtils, Classes, Controls, Graphics; //(note added unit)

Question, Suggestions

If you have any questions or comments to this (huge) article, please post them on the Delphi Programming Forum. Discuss!

Creating Custom Delphi Components - Inside and Out

Discuss! Creating Custom Delphi Components - Inside and Out Page 3: Adding variables to components Adding

Page 3: Adding variables to components

Adding Some Variables We need to customise this skeleton code to suit our purposes so let's get busy. The first thing to do is to declare a new type. Change the bit that says:

type TLine = class(TGraphicControl)

to read:

type TLineDirection = (drLeftRight, drUpDown, drTopLeftBottomRight, drTopRightBottomLeft);

TLine = class(TGraphicControl)

That should be fairly self-explanatory. We declared a new type called TLineDirection, which we can use when drawing to figure out where to draw the line from/to. Now we add in a few variables (called member variables) into the class itself. We need to store:

Line width

Line colour

Direction

This is where the whole idea of customisation comes in. If you want to, you could add in any variables you think

are necessary

you could add in code to draw dotted lines, for example. However, we'll stick with the basics for

now.

One thing you should have spotted is that we don't actually need to store the line width and colour, as they are properties of the canvas's pen. This is very handy. However, we will need to add in a variable for the direction, as well as get and set functions. Change the private section of the component to look like this:

private { Private declarations } FLineDir: TLineDirection;

function GetLineWidth: Integer; function GetLineColour: TColor; procedure SetLineWidth(const NewWidth: Integer); procedure SetLineColour(const NewColour: TColor); procedure SetLineDir(const NewDir: TLineDirection);

Even though we haven't got variables for the line width and colour, we still need functions to set and retrieve the values from the component's canvas. This is because these three values will be properties of TLine, and properties want you to say how they will read/write, remember? Note we don't need a get function for FLineDir because we can just let the property read its value directly from the variable.

The "F" before LineDir is a bit of notation. It stands for "field", and just means the variable belongs to the class. This makes it a bit easier when writing your component to avoid mixing up local variables with class members.

Right, we've declared the functions so I suppose we'd better implement them. Bung this code in after the implementation section (look for the "implementation" keyword in your file and add this immediately after it):

function TLine.GetLineWidth: Integer; begin Result := Canvas.Pen.Width; end;

function TLine.GetLineColour: TColor; begin Result := Canvas.Pen.Color; end;

procedure TLine.SetLineWidth(const NewWidth: Integer); begin if NewWidth <> Canvas.Pen.Width then begin Canvas.Pen.Width := NewWidth; Invalidate; // redraws the component end; end;

procedure TLine.SetLineColour(const NewColour: TColor); begin if NewColour <> Canvas.Pen.Color then begin Canvas.Pen.Color := NewColour; Invalidate; end; end;

procedure TLine.SetLineDir(const NewDir: TLineDirection); begin if NewDir <> FLineDir then begin FLineDir := NewDir; Invalidate; end; end;

The get functions are very self-explanatory. They just nab the values from the Canvas and pass them along. However, the set functions are slightly more complex than just setting the variables.

When the set function gets called, we only want to change the appropriate value if necessary. After all, since it's a visual control any unnecessary changes will be apparent to the user (e.g. setting the line direction to the same value again shouldn't cause a redraw). Each of the set functions checks if the new value is different to the current one. If, and only if, it is then we need to change the value and cause a redraw.

Creating Custom Delphi Components - Inside and Out

the value and cause a redraw. Creating Custom Delphi Components - Inside and Out Page 4:

Page 4: Adding propeties to components

Adding Properties The next step is to add properties to the component. We've laid the groundwork so it's simply a matter of bunging them in, like so:

published

{ Published Declarations }

property Direction: TLineDirection read FLineDir write SetLineDir; property LineColour: TColor read GetLineColour write SetLineColour; property LineWidth: Integer read GetLineWidth write SetLineWidth;

There should be no great surprises in there as you've seen similar property declarations in the previous tutorial part. Now, believe it or not, we've very nearly finished the component!

A quick note about "published": any properties in this section will be available in the Object Inspector at design- time. This is, of course, what we want. If you don't want the properties published (if, for example, you only create the component at run-time) then you can place properties in the "public" section. Properties there will be available to outside code, just like published properties, but will not appear in the Object Inspector. If you see "run-time" properties in the help files, it means they're public.

The next part is pretty fundamental to TLine - its Paint procedure. We need to draw the component, so it's time to add in some code for that. Since our component has TGraphicControl as a base class it gains a Paint procedure. We just need to modify this to draw our code and we're almost there. Add in this code to the component's "Protected" section:

protected

{ Protected declarations }

procedure Paint; override;

The override part is a fancy bit, and means our procedure will get called instead of the base class's Paint procedure. We can write the good stuff now, namely the drawing procedure. Add this code in after the implementation part:

procedure TLine.Paint; var start: Integer; begin inherited;

case FLineDir of drLeftRight:

begin start := (Height - Canvas.Pen.Width) div 2; Canvas.MoveTo(0, start); Canvas.LineTo(Width, Start); end; drUpDown:

begin start := (Width - Canvas.Pen.Width) div 2; Canvas.MoveTo(start, 0); Canvas.LineTo(start, Height); end; drTopLeftBottomRight:

begin Canvas.MoveTo(0, 0); Canvas.LineTo(Width, Height);

end;

drTopRightBottomLeft:

begin Canvas.MoveTo(Width, 0); Canvas.LineTo(0, Height); end; end; end;

The only thing you shouldn't understand is the "inherited" bit. Because the Paint procedure belongs to the base class and we're overriding it, we don't want to miss out on important bits the base class does. The base class here might need to do things like set up the canvas to draw on, get device contexts, allocate resources, or whatever. If we don't let the base class do its thing by calling it via "inherited" we might just find our code blows up. Best not to let that happen, eh?

And that, my friend, is enough for a working component. Save the file and go to the Component->Install Component menu, select your file and say OK when it asks if you want to rebuild your library. If all goes well it should tell you that TLine has been registered. You can find it on the Samples palette page and try messing around with it.

on the Samples palette page and try messing around with it. Question, Suggestions If you have

Question, Suggestions If you have any questions or comments to this (huge) article, please post them on the Delphi Programming Forum. Discuss!

Creating Custom Delphi Components - Inside and Out

Discuss! Creating Custom Delphi Components - Inside and Out Page 5: On Constructors Constructors and Destructors

Page 5: On Constructors

Constructors and Destructors The TLine component you just created showed the basics of component writing. However, there are two major issues to cover - constructors and destructors.

Suppose you use dynamic memory in your component. Without any constructors and destructors this would be very error-prone. You'd end up with code that looked like this:

var SomeObject: TSomething;

begin SomeObject := TSomething.Create; SomeObject.Init; // yuck!

//

use the object now

SomeObject.Squish; // yuck!

SomeObject.Free;

end;

You should be able spot why this would be bad - what if you forget to call Init or Squish? You would end up with an exception or memory leak (bad news) and would look like a fool. Well, luckily, constructors and destructors can help here. Oh, carefully forget to notice that I actually used constructors and destructors in the above example ;-). It's kinda hard in Delphi to avoid them.

Constructors Constructors get called whenever you create an object. Their job is to set up the internals of the object (variables, pointers, dynamic memory, etc.) as appropriate. The constructor is used to ensure you have a valid object - it should do no more or less than this. If you find after calling a constructor you still need to call some Init function then you haven't written an appropriate constructor, and should change it.

All objects is Delphi have a standard constructor ("Create"), which they get from TObject. This can be used to create the object, like so:

SomeObject := TThisClass.Create;

where TThisClass is SomeObject's type. You must do this with classes before using them or you will get an exception. When you use the constructor the object gets space allocated for it and can be used. What if you want to change this constructor? Well, you can do this quite easily.

Every constructor can get declared like a procedure, but with "constructor" replacing "procedure" in the declaration. Since every object has a "create" constructor available, why not modify this to suit your purposes? Here's an example:

type TSomething = class(TObject) public { Public declarations } constructor Create; // etc. end;

implementation

// and the actual constructor definition constructor TSomething.Create; begin inherited; // do whatever you need (allocate memory, initialise variables, etc.) end;

The above is the simplest constructor you might think about. There's only one thing that needs discussing - "inherited".

Inheritance is a concept in object-oriented design where a class can be a base for other classes. An example might be a "creature" class, which you could use as a base for "cat" and "dog" classes. The cat and dog would get data and behaviour from the "creature" base class, such as moving, having legs, fur, and so on, and would change this to suit their own needs (such as adding "woof" behaviour for dogs). The first class from which others derive is called the "base class" (or "super-class") and the ones that inherit from it are called "derived classes" (or "sub-classes").

Since every class is a sub-class of TObject, they automatically get its properties, methods, events, etc. (a slight exaggeration, as you'll see later). This includes the standard constructors and destructors ("Create" and "Destroy"). Since we have added our own code for the TSomething constructor the other code won't get executed - if you

create a TSomething then TSomething.Create will get called, not TObject.Create. This is bad, as the base class might be doing clever/important things. Using the "inherited" keyword lets you call the base class's same method. This works for any constructor/destructor/procedure/function ("method").

Note that constructors can have any name, and any parameters. You're not just limited to "Create" and "Destroy", so another potential constructor might look like this:

type TMyClass = class(TSomething) public constructor InitWithStuff(const x: String); end;

implementation

constructor TMyClass.InitWithStuff(const x: String); begin inherited Create; // do something with your parameter "x" end;

I'll first of all point out the slight change to "inherited". By default, inherited wants to use a method in the base class with the same name and parameters. If there isn't one, you can specify the method manually, as I've done here. You can also pass in parameters - you could, for example, do:

inherited SomeProcedure(x,y,z);

Now then, the above code makes a sub-class of TSomething, called TMyClass. It now has another constructor called "InitWithStuff". This is NOT available in TSomething, as it has only been introduced in this new class. Note now that TMyClass has two constructors, not just one! You could create a TMyClass like this:

someObject := TMyClass.InitWithStuff('hello');

As you'd expect, this uses the constructor "InitWithStuff" we've just added to this new class. However, remember that TMyClass still has the Create constructor. This constructor didn't magically disappear when we created the new class - it's a method of TSomething (from TObject), which means that it's a method of this new derived TMyClass as well. This means it's syntactically correct to create a TMyClass like this:

someObject := TMyClass.Create;

However, this isn't such a good idea. If an object gives you a constructor you should use it! Because we are bypassing TMyClass's constructor (it really wants us to use InitWithStuff) and are instead using the base class's version (TSomething.Create) we could be creating problems (excuse the bad pun :-p). The object we want might be missing out on some vital work work it needs because we're not using the thing provided. This leads to an important tip:

It's usually best to use the same name for constructors for every derived class

You can have two constructors (or more) in one class. This means one potential way to get around the problem might be this:

TMyClass = class(TSomething) public constructor Create; constructor InitWithStuff(const x: String); end;

implementation

constructor TMyClass.Create; begin raise Exception.Create('You must use InitWithStuff to create a TMyClass'); end;

constructor TMyClass.InitWithStuff(const x: String); begin inherited Create; // do whatever stuff you need now end;

This solution works, but it's a little silly. It prevents anyone from using Create as a constructor for TMyClass (or any classes that are derived from it and use "inherited") because they'll end up with an exception. However, it's easier just to name your object constructors consistently from base to sub classes (usually you can just stick with "Create", as it's a standard name).

Understanding, Using and Enhancing Delphi VCL Components

Tutorials and articles on using Delphi Visual Component Library (VCL) controls and components more efficiently at design and run time.

TColorButton - button with color properties

and run time. TColorButton - button with color properties Full source code of the TColorButton Delphi

Full source code of the TColorButton Delphi component, an extension to the standard TButton control, with font color, background color and mouse over color properties.

TButton.Color? Have you ever asked yourself a question like: "How can I set the background color of a TButton?" Well, you can't! What's more you cannot change the background color a TButton, TBitBtn and TSpeedButton.

The background color of a TButton is controlled by Windows, not by Delphi. TButton is a simple wrapper around the standard Windows button and Windows does not allow it to be colored except by choosing the colors in the Control Panel. Note: to change the default button color system-wide, you need to open the Control Panel; in the Appearances tab of the Display properties applet edit the color of the "3D Objects" item (badly, this will change the color of some other Windows elements).

Since Windows insists on doing the background coloring with clBtnFace, the only way to change the background color is to draw the button yourself. In other words, if you want a button where you decide about the color, you will have to make an owner-drawn button component.

TColorButton

TColorButton To overcome the lack of color-related properties of the standard TButton control, I've created the

To overcome the lack of color-related properties of the standard TButton control, I've created the TColorButton custom Delphi component. The TColorButton adds three new properties to the standard TButton:

BackColor - specifies the background color of the button.

ForeColor - specifies the color of the button text. Note that this "overrides" the Font.Color property.

HoverColor - specifies the color used to paint the button's background when the mouse hovers over the button.

background when the mouse hovers over the button. Here's how to set color-related properties of the
background when the mouse hovers over the button. Here's how to set color-related properties of the

Here's how to set color-related properties of the TColorButton at run time:

ColorButton1.BackColor := clOlive; //background ColorButton1.ForeColor := clYelow; //text ColorButton1.HoverColor := clNavy; //mouse over

Installing into a Component palette First, download the component. The TColorButton comes as a single unit file (.pas extension). You'll need to add the component into an existing package. Here's "How to Install Custom Component in Delphi (into Existing Package)"

Questions? Comments? Extensions? Exceptions?! That's it. If you find this component practical and if you extend it by adding more properties, please send your source and make it available to other developers. As always if there are any questions or comments please post them on the Delphi Programming Forum.