Introduction to component writing

See also

Borland C++Builder is not just a development environment for visually creating applications with components. It also includes everything you need to create the components for building applications in the same environment, using the same C++ language.

If you have already developed components with Delphi, you can add them to the C++Builder Component palette. You can write C++Builder components in either C++ or Object Pascal.

The Component Writer's Guide and its accompanying Help file (DCCWG.HLP) describe everything you need to know to write components for C++Builder applications. The printed manual and the Help file contain the same information in different forms.

This material has two purposes:

To teach you how to create working components

To ensure that the components you write are well-behaved parts of the C++Builder environment

Whether you're writing components for your own applications or for commercial distribution, this book will guide you to writing components that fit in well with any C++Builder application.


See also

What's different about writing components?

What is a component?

Creating a component (summary)

Overview of component creation


What is a component?

See also

Components are the building blocks of C++Builder applications. Although most components represent visible parts of a user interface, components can also represent nonvisual elements in a program, such as timers and databases.

There are three different levels at which to think about components:

The functional definition of "component"

The technical definition of "component"

The component writer's definition of "component"


See also

What's different about writing components?

Creating a component (summary)


The functional definition of "component"

See also

From the end user's perspective, a component is something to choose from the palette and use in an application by manipulating it in the Forms Designer or in code. From the component writer's perspective, however, a component is an object in code. Although there are few real restrictions on what you can do when writing a component, it's good to keep in mind what the end user expects when using the components you write.

Before you attempt to write components, we strongly recommend that you become familiar with the existing components in C++Builder so you can make your components familiar to users. Your goal should be to make your components "feel" as much like other components as possible.


See also

The technical definition of "component"

The component writer's definition of "component"


The technical definition of "component"

See also

At the simplest level, a component is any object descended from the type TComponent. TComponent defines the most basic behavior that all components must have, such as the ability to appear on the Component palette and operate in the Forms Designer.

But beyond that simple definition are several larger issues. For example, although TComponent defines the basic behavior needed to operate the C++Builder environment, it can't know how to handle all the specific additions you make to your components. You'll have to specify those yourself.

Although it's not difficult to create well-behaved components, it does require that you pay close attention to the standards and conventions spelled out in this book.


See also

The functional definition of "component"

The component writer's definition of "component"


The component writer's definition of "component"

See also

At a very practical level, a component is any element that can "plug into" the C++Builder development environment. It can represent almost any level of complexity, from a simple addition to one of the standard components to a vast, complex interface to another hardware or software system. In short, a component can do or be anything you can create in code, as long as it fits into the component framework.

The definition of a component, then, is essentially an interface specification. This manual spells out the framework onto which you build your specialized code to make it work in C++Builder.

Defining the limits of "component" is therefore like defining the limits of programming. We can't tell you every kind of component you can create, any more than we can tell you all the programs you can write in a given language. What we can do is tell you how to write your code so that it fits well in the C++Builder environment.


See also

The functional definition of "component"

The technical definition of "component"


What's different about writing components?

See also

There are three important differences between the task of creating a component for use in C++Builder and the more common task of creating an application that uses components:

Component writing is nonvisual

Component writing requires deeper knowledge of objects

Component writing follows more conventions


See also

What is a component?

Creating a component (summary)


Component writing is nonvisual

See also

The most obvious difference between writing components and building applications with C++Builder is that component writing is done strictly in code. Because the visual design of C++Builder applications requires completed components, creating those components requires writing C++ or Object Pascal code.

Although you can't use the same visual tools for creating components, you can use all the programming features of the C++Builder development environment, including the Code editor, and integrated debugger.


See also

Component writing requires deeper knowledge of objects

Component writing follows more conventions


Component writing requires deeper knowledge of objects

See also

Other than the non-visual programming, the biggest difference between creating components and using them is that when you create a new component you need to derive a new object type from an existing one, adding new properties and methods. Component users, on the other hand, use existing components and customize their behavior at design time by changing properties and specifying responses to events.

When deriving new objects, you have access to parts of the ancestor objects unavailable to end users of those same objects. These parts intended only for component writers are collectively called the protected interface to the objects. Descendant objects also need to call on their ancestor objects for a lot of their implementation, so component writers need to be familiar with that aspect of object-oriented programming.


See also

Component writing is nonvisual

Component writing follows more conventions


Component writing follows more conventions

See also

Writing a component is a more traditional programming task than visual application creation, and there are more conventions you need to follow than when you use existing components. Probably the most important thing to do before you start writing components of your own is to really use the components that come with C++Builder, to get a feeling for the obvious things like naming conventions, but also for the kinds of abilities component users will expect when they use your components.

The most important thing that component users expect of components is that they should be able to do almost anything to those components at any time. Writing components that fulfill that expectation is not difficult, but it requires some forethought and adherence to conventions.


See also

Component writing is nonvisual

Component writing requires deeper knowledge of objects


Creating a component (summary)

See also

In brief, the process of creating your own component consists of these steps:

Create a unit for the new component.

Derive a component type from an existing component type.

Add properties, methods, and events as needed.

Register your component with C++Builder.

Create a Help file for your component and its properties, methods, and events.

All these steps are covered in detail in this. When you finish, the complete component includes these files:

An .OBJ file

A header file

For C and C++ code, the header is a .H file.

For Pascal code, the compiler generates a .HPP interface file.

A palette bitmap (.RES file or .DCR file)

If the component uses a form, a .DFM file

Although only the .OBJ and the header file are required, the others can make your components more useful.


See also

What's different about writing components?

What is a component?

Typeface or symbol	Meaning

Monospace type	Monospaced text represents text as it appears onscreen or in C++ code. It also represents anything you must type.

[ ]	Square brackets in text or syntax listings enclose optional items. Text of this sort should not be typed verbatim.

Italics	Italicized words in text represent C++ identifiers, such as variable or type names. Italics are also used to emphasize certain words, such as new terms.

Keycaps	This typeface indicates a key on your keyboard. For example, "Press Esc to exit a menu."


Overview of component creation

See also

This set of topics provides a broad overview of component architecture, the philosophy of component design, and the process of writing components for C++Builder applications.

The main topics discussed are

The Visual Component Library

Components and objects

How do you create components?

What goes in a component?

Creating a new component

Testing uninstalled components

Installing a component on the Component palette

All this material assumes you have some familiarity with using C++Builder and its standard components.


See also

OOP for component writers

Creating properties

Creating events

Creating methods

Using graphics in components

Handling messages

Registering components


The Visual Component Library

See also

C++Builder's components are all part of an object hierarchy called the Visual Component Library (VCL). The following figure shows the relationship of the objects that make up VCL.

Note that the type TComponent is the shared ancestor of every component in the VCL. TComponent provides the minimal properties and events necessary for a component to work in C++Builder. The various branches of the library provide other, more specialized capabilities.

When you create a component, you add to the VCL by deriving a new object from one of the existing object types in the hierarchy.


See also

Components and objects

How do you create components?

What goes in a component?

Creating a new component

Testing uninstalled components


Components and objects

See also

Because components are objects, component writers work with objects at a different level than component users do. Creating new components requires that you derive new types of objects. OOP for component writers describes in detail the kinds of object-oriented tasks component writers need to use.

Briefly, there are two main differences between creating components and using components. When creating components,

You have access to parts of the object that are inaccessible to end users

You add new parts (such as properties) to your components

Because of these differences, you need to be aware of more conventions, and you need to think in terms of how end users will use the components you write.


See also

How do you create components?

What goes in a component?

Creating a new component

Testing uninstalled components


How do you create components?

See also

A component can be almost any program element you want to manipulate at design time. Creating a new component means deriving a new component object type from an existing type. You can derive a new component from any existing component, but the following are the most common ways to create new components:

Modifying existing controls

Creating original controls

Creating graphic controls

Subclassing Windows controls

Creating nonvisual components

The following table summarizes the different kinds of components and the object types you use as starting points for each.

To do this	Start with this type

Modify an existing component	Any existing component, such as TButton or TListBox, or an abstract component type, such as TCustomListBox.

Create an original control	TCustomControl

Create a graphic control	TGraphicControl

Create a non-visual component	TComponent

You can also derive other objects that are not components, but you cannot manipulate them in a form. C++Builder includes a number of that kind of object, such as TINIFile or TFont.


See also

The Visual Component Library

Components and objects

What goes in a component?

Creating a new component

Testing uninstalled components


Modifying existing controls

See also

The simplest way to create a component is to start from an existing, working component and customize it. You can derive a new component from any of the components provided with C++Builder. For instance, you might want to change the default property values of one of the standard controls.

There are certain controls, such as list boxes and grids, that have a number of variations on a basic theme. In those cases, C++Builder provides an abstract control type (with the word "custom" in its name, such as TCustomGrid) from which to derive customized versions.

For example, you might want to create a special kind of list box that does not have some of the properties of the standard TListBox type. You can't remove a property from an ancestor type, so you need to derive your component from something higher in the hierarchy than TListBox. Rather than forcing you to go clear back to an abstract control type and reinvent all the list box functions, the Visual Component Library (VCL) provides TCustomListBox, which implements all the properties needed for a list box, but does not publish all of them.

When deriving a component from one of the abstract types such as TCustomListBox, you publish those properties you want to make available in your component and leave the rest protected.


See also

Creating nonvisual components

Creating original controls

Creating graphic controls

Subclassing Windows controls


Creating original controls

See also

A windowed control is an item that's visible at runtime, usually one the user can interact with. These windowed controls all descend from the object type TWinControl. The key aspect of a standard control is that it has a window handle, embodied in a property called Handle. The window handle means that Windows "knows about" the control, so that

The control can receive the input focus.

You can pass the handle to Windows API functions (Windows needs a handle to identify which window to operate on).

While you could create an original control (one that's not related to any existing control) using TWinControl as your starting point, C++Builder provides the TCustomControl component for just this purpose. A TCustomControl component is a specialized windowed control that makes it easier to draw complex visual images.

If your control doesn't need to receive input focus, you can make it a graphic control, which saves system resources.

All the components that represent standard windows controls, such as push buttons, list boxes, and edit boxes, descend from TWinControl except TLabel, as label controls never receive the input focus.


See also

Creating nonvisual components

Modifying existing controls

Creating graphic controls

Subclassing Windows controls


Creating graphic controls

See also

Graphic controls are very similar to custom controls, but they don't carry the overhead of being Windows controls. That is, Windows doesn't know about graphic controls. They have no window handles, and therefore consume no system resources. The main restriction on graphic controls is that they can't receive the input focus.

C++Builder supports the creation of custom controls through the TGraphicControl component. TGraphicControl is an abstract component derived from TControl. Although you can derive controls from TControl, you should derive them from TGraphicControl, because TGraphicControl provides a canvas to paint on and handles WM_PAINT messages. All you need to do is override the Paint method.


See also

Creating nonvisual components

Creating original controls

Modifying existing controls

Subclassing Windows controls


Subclassing Windows controls

See also

Windows has a concept called a window class that is somewhat similar to the object-oriented programming concept of object or class. A window class is a set of information shared between different instances of the same sort of window or control in Windows.

When you create a new kind of control (usually called a custom control) in traditional Windows programming, you define a new window class and register it with Windows. You can also base a new window class on an existing class, which is called subclassing.

In traditional Windows programming, if you wanted to create a custom control, you had to write it in a dynamic-link library (DLL), much like the standard Windows controls, and provide an interface to it.

Using C++Builder, you can create a component "wrapper" around any existing Windows class. So if you already have a library of custom controls that you want to use in your C++Builder applications, you can create C++Builder components that let you use your existing controls and derive new controls from them just as you would any other component.


See also

Modifying existing controls

Creating original controls

Creating graphic controls

Creating nonvisual components


Creating nonvisual components

See also

The abstract TComponent class is the base type for all components. The only components you create directly from TComponent are nonvisual components. Most of the components you write will probably be various kinds of visual controls.

TComponent defines all the properties and methods essential for a component to participate in the Form Designer. Any component you derive from TComponent , therefore, already has design capability built into it.

Nonvisual components are fairly rare. You mostly use them as an interface for nonvisual program elements (much as C++Builder uses them for database elements) and as placeholders for dialog boxes (such as the file dialog boxes).


See also

Creating original controls

Modifying existing controls

Creating graphic controls

Subclassing Windows controls


What goes in a component?

See also

There are few restrictions on what you can put in the components you write. There are certain conventions you should follow, however, if you want to make your components easy and reliable for the people who use them.

This section discusses the philosophies underlying the design of components, including the following topics:

Removing dependencies

Properties and events and methods

Graphics encapsulation

Registration


See also

The Visual Component Library

Components and objects

How do you create components?

Creating a new component

Testing uninstalled components


Removing dependencies

See also	Example

Perhaps the most important philosophy behind the creation of C++Builder's components is the necessity of removing dependencies. One of the things that makes components so easy for end users to incorporate into their applications is the fact that there are generally no restrictions on what they can do at any given point in their code.

The very nature of components suggests that different users will incorporate them into applications in varying combinations, orders, and environments. You should design your components so that they function in any context, without requiring any preconditions.


See also

Properties and events and methods

Graphics encapsulation

Registration


An example of removing dependencies

An excellent example of removing dependencies in components is the Handle property of windowed controls. If you've written Windows applications before, you know that one of the most difficult and error-prone aspects of getting a program running is making sure that you don't access a window or control until you've created it by calling the CreateWindow API function. Calling API functions with invalid handles causes a multitude of problems.

C++Builder components protect users from worrying about window handles and whether they are valid by ensuring that a valid handle is always available when needed. That is, by using a property for the window handle, the component can check whether the window has been created, and therefore whether there is a valid window handle. If the handle isn't already valid, the property creates the window and returns the handle. Thus, any time a user's code accesses the Handle property, it is assured of getting a valid handle.

By removing the background tasks such as creating the window, components allow developers to focus on what they really want to do. If a developer needs to pass a window handle to an API function, it shouldn't be necessary to first check to make sure there's a valid handle and, if necessary, create the window. With component-based programming, the programmer can write assuming that things will work, instead of constantly checking for things that might go wrong.

Although it might take a little more time to create components that don't have dependencies, it's generally time well spent. Not only does it keep users of your components from having to repeatedly perform the same tasks, but it also reduces your documentation and support burdens, since you don't have to provide and explain numerous warnings or resolve the problems users might have with your components.


Properties and events and methods

See also

Outside of the visible image the component user manipulates in the form at design time, the most obvious attributes of a component are its properties, events, and methods. Each of these is sufficiently important that it has its own section in this file, but this section will explain a little of the philosophy of implementing them.

Properties

Properties give the component user the illusion of setting or reading the value of a variable in the component while allowing the component writer to hide the underlying data structure or to implement side effects of accessing the value.

There are several advantages to the component writer in using properties:

Properties are available at design time.

This allows the component user to set and change initial values of properties without having to write code.

Properties can check values or formats as the user assigns them.

Validating user input prevents errors caused by invalid values.

The component can construct appropriate values on demand.

Perhaps the most common type of error programmers make is to reference a variable that hasn't had an initial value assigned. By making the value a property, you can ensure that the value read from the property is always valid.

Creating properties explains how to add properties to your components.

Events

Events are connections between occurrences determined by the component writer (such as mouse actions and keystrokes) and code written by component users ("event handlers"). In essence, an event is the component writer's way of providing a hook for the component user to specify what code to execute when a particular occurrence happens.

It is events, therefore, that allow component users to be component users instead of component writers. The most common reason for subclassing in traditional Windows applications is that users want to specify a different response to, for example, a Windows message. But in C++Builder, component users can specify handlers for predefined events without subclassing, so they don't need to derive their own components.

Creating events explains how to add events for standard Windows occurrences or events you define yourself.

Methods

Methods are functions built into a component. Component users use methods to direct a component to perform a specific action or return a certain value not covered by a property. Methods are also useful for updating several related properties with a single call.

Because they require execution of code, methods are only available at runtime.

Creating methods explains how to add methods to your components.


See also

Removing dependencies

Graphics encapsulation

Registration


Graphics encapsulation

See also

C++Builder takes most of the drudgery out of Windows graphics by encapsulating the various graphic tools into a canvas. The canvas represents the drawing surface of a window or control, and contains other objects, such as a pen, a brush, and a font. A canvas is much like a Windows device context, but it takes care of all the bookkeeping for you.

If you've ever written a graphic Windows application, you're familiar with the kinds of requirements Windows' graphics device interface (GDI) imposes on you, such as limits on the number of device contexts available, and restoring graphic objects to their initial state before destroying them.

When working with graphics in C++Builder, you need not concern yourself with any of those things. To draw on a form or component, you access the Canvas property. If you want to customize a pen or brush, you set the color or style. When you finish, C++Builder takes care of disposing of the resources. In fact, it caches resources, so if your application frequently uses the same kinds of resources, it will probably save a lot of creating and recreating.

Of course, you still have full access to the Windows GDI, but you'll often find that your code is much simpler and runs faster if you use the canvas built into C++Builder components. C++Builder's graphics features are detailed in Using graphics in components.


See also

Removing dependencies

Properties and events and methods

Registration


Registration Overview
Registration

See also

Before your components can operate in C++Builder at design time, you have to register them with C++Builder. Registration tells C++Builder where you want your component to appear on the Component palette. There are also some customizations you can make to the way C++Builder stores your components in the form file. Registration is explained in Registering components.


See also

Removing dependencies

Properties and events and methods

Graphics encapsulation


Creating a new component

See also

There are several steps you perform whenever you create a new component. All the examples given that create new components assume you know how to perform these steps.

You can create a new component two ways:

Using the Component Expert

Creating a component manually

Once you do either of those, you have at least a minimally functional component ready to install on the Component palette.After installing, you can add your new component to a form and test it in both design time and runtime. You can then add more features to the component, update the palette, and continue testing.


See also

The Visual Component Library

Components and objects

How do you create components?

What goes in a component?

Testing uninstalled components


Using the Component Expert

See also

You can use the Component Expert to create a new component. Using the Component Expert simplifies the initial stages of creating a new component, as must specify only these things:

The name of the new component

The ancestor type

The Component palette page you want it to appear on

The Component Expert performs the same tasks you would do when creating a component manually, namely

Creating a unit

Deriving the component

Declaring a new constructor

Registering the component

The Component Expert can't add components to an existing unit (consisting of a .CPP file and an associated header file). You must add components to the unit manually.

To open the Component Expert, choose File|New Component.

After you fill in the fields in the Component Expert, choose OK. C++Builder creates a new unit consisting of a .CPP file and an associated header file.

The .CPP file appears in the Code editor. It contains a constructor for the component and the Register function that registers the component, informing C++Builder which component to add to the component library and on which page of the Component palette it should appear. The file also contains an include statement that specifies the header file that was created. For example,

#include <vcl\vcl.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

__fastcall TNewComponent::TNewComponent(TComponent* AOwner): TComponent(AOwner)

{

}

namespace Unit1 {

void __fastcall Register()

{

  TComponentClass classes[1] = {__classid(TNewComponent)};

  RegisterComponents("Samples", classes, 0);

}

}

To open the header file in the Code editor, place your cursor on the header file name and click your right mouse button to display the context menu. Choose Open File at Cursor on the menu.

The header file contains the new class declaration, including a constructor declaration, and several include statements to support the new class. For example,

#ifndef NewcompH

#define NewcompH

//---------------------------------------------------------------------------

#include <vcl\sysutils.hpp>

#include <vcl\controls.hpp>

#include <vcl\classes.hpp>

#include <vcl\forms.hpp>

//---------------------------------------------------------------------------

class TNewComponent : public TComponent

{

private:

protected:

public:

  virtual __fastcall TNewComponent(TComponent* AOwner);

__published:

};

//---------------------------------------------------------------------------

#endif

You should save the .CPP file right away, giving it a meaningful name. When you do, the header file name changes to the same name as the .CPP file except it has an .H file extension instead of a .CPP file extension.


See also

Creating a component manually


Creating a component manually

See also

The easiest way to create a new component is to use the Component Expert. You can, however, perform the same steps manually.

To create a component manually, follow these steps:

Create a unit

Derive the component

Declare a new constructor

Register the component


See also

Using the Component Expert


Creating a unit

See also

An C++Builder unit is comprised of a .CPP file and an .H file combination that is compiled into an .OBJ file. C++Builder uses units for a number of purposes. Every form has its own unit, and most components (or logical groups of components) have their own units as well.

When you create a component, you either create a new unit for the component, or add the new component to an existing unit.

To create a unit for a component, follow these steps:

Choose File|New.

Select Unit in the New Items dialog box, and choose OK.

C++Builder creates .CPP file and a header file and displays the .CPP file in the Code editor. Save the file with a meaningful name.

To open the header file, place your cursor on the name of the header file in the Code editor and double click it.

To add a component to an existing unit, choose File|Open to choose the source code for an existing unit.

Note:

When adding a component to an existing unit, make sure that unit already contains only component code. Adding component code to a unit that contains, for example, a form, causes errors in the Component palette.

Once you have either a new or existing unit for your component, you can derive the component object.


See also

Deriving the component

Registering the component


Deriving the component

See also

Every component is an object descended from TComponent, from one of its more specialized descendants, such as TControl or TGraphicControl, or from an existing component type. How do you create components? describes which class to derive from for different kinds of components.

Deriving new objects is explained in more detail in Creating new objects.

To derive a component object, add a class declaration to the header file.

To create the simplest component type, a non-visual component descended directly from TComponent, add the following class declaration to your header file:

class TNewComponent : public TComponent

{

};

You should also add the necessary include statements that specify the .HPP files needed for the new component. These are the most common include statements you need:

#include <sysutils.hpp>

#include <controls.hpp>

#include <classes.hpp>

#include <forms.hpp>

You can now register TNewComponent. Note that the new component does nothing different from TComponent yet. You created a framework on which you'll build your new component, however.


Declaring a new constructor

Each new component must have a constructor that overrides the constructor of the class from which it was derived. When you write the constructor for your new component, it must always

Be declared as a virtual method

Call the inherited constructor

Within the class declaration, declare a virtual constructor in the public section of the class.  You can learn more about the public section in Controlling access.

For example,

class TNewComponent : public TComponent

{

public:

  virtual __fastcall TNewComponent(TComponent* AOwner);

};

In the .CPP file, implement the constructor:

__fastcall TNewComponent::TNewComponent(TComponent* AOwner): TComponent(AOwner)

{

}

Within the constructor you can add the code you want to execute when the component is created.


See also

Creating a new unit

Registering the component


Registering the component

See also	Example

Registering a component is a simple process that tells C++Builder which components to add to its component library, and on which pages of the Component palette the components should appear. Registering components describes the registration process and its nuances in much more detail.

To register a component,

Add a function named Register to the unit's .CPP file, placing it within a namespace. The namespace is the name of the file the component is in with all lowercase letters except the first letter.

For example, this code exists within a Newcomp namespace, whereas Newcomp is the name of the .CPP file:

namespace Newcomp {

  void __fastcall Register()

  {

  }

}

Within the Register function, declare an open array of type TComponentClass that holds the array of components you are registering. The syntax should look like this:

TComponentClass classes[1] = {__classid(TNewComponent));

In this case, the array of classes contains just one component, but you can add all the components you want to register to the array.

Within the Register function, call RegisterComponents for each component you want to register.

RegisterComponents is a function that takes three parameters: the name of a Component palette page, the array of component classes, and the size of the component classes. If you're adding a component to an existing registration, you can either add the new component to the set in the existing statement, or add a new statement that calls RegisterComponents.


Example

To register a component named TNewComponent and place it on the Samples page of the Component palette, add the following Register function to the .CPP file of the unit that contains TNewComponent's declaration:

namespace Newcomp {

  void __fastcall Register()

  {

   TComponentClass classes[1] = {__classid(TNewComponent)};

   RegisterComponents("Samples", classes, 0);

  }

}

Once you register a component, you can test the component, and finally install the component onto the Component palette.


See also

Creating a new unit

Declaring a new constructor

Deriving the component


Testing uninstalled components

See also	Example

You can test the runtime behavior of a component before you install it on the Component palette. This is particularly useful for debugging newly-created components, but you can use the same technique for testing any component, regardless of whether the component appears on the Component palette.

In essence, you can test an uninstalled component by emulating the actions performed by C++Builder when a user places a component from the Component palette on a form.

To test an uninstalled component, do the following:

Include the .H file of the component unit in the header file of a form unit.

Add an object data member to the form to represent the component.

This is one of the main differences between the way you add components and the way C++Builder does it. You add the object data member to the public part at the bottom of the form's type declaration. C++Builder would add it above, in the part of the type declaration that it manages.

You should never add data members to the C++Builder-managed part of the form's type declaration. The items in that part of the type declaration correspond to the items stored in the form file. Adding the names of components that do not exist on the form can render your form file invalid.

Attach a handler to the form's OnCreate event.

Construct the component in the form's OnCreate handler.

When you call the component's constructor, you must pass a parameter specifying the owner of the component (the component responsible for destroying the component when the time comes). You nearly always pass this as the owner. In a method, this a reference to the object that contains the method. In this case, in the form's OnCreate handler, this refers to the form.

Assign the Parent property.

Setting the Parent property is always the first thing to do after constructing a control. The parent is the component that visually contains the control, which is most often the form, but might be a group box or panel. Normally, you'll set Parent to this, that is, the form. Always set Parent before setting other properties of the control.

Warning:

If your component is not a control (that is, if TControl is not one of its ancestors), skip this step. If you accidentally set the form's Parent property to this instead of the component's, you can cause Windows to crash.

Set any other component properties as desired.


Example

Suppose you want to test a new component of type TNewComponent in a unit named NewComp. Create a new project, then follow the steps to end up with a form unit that looks like this:

#ifndef TestFormH

#define TestFormH

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include "NewComp.h"                             // 1. Add NewComp to the form header file

//---------------------------------------------------------------------------

class TForm1 : public TForm

{

__published:

private:

public:

    TNewComponent* NewComponent1;                      // 2. Add an object data member

    virtual __fastcall TForm1(TComponent* Owner);      // 3. Attach a handler to OnCreate

};

//---------------------------------------------------------------------------

extern TForm1 *Form1;

//---------------------------------------------------------------------------

#endif

This is the .CPP file of the form unit:

#include <vcl.h>

#pragma hdrstop

#include "TestForm.h"

//---------------------------------------------------------------------------

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

  : TForm(Owner)

{

  NewComponent1 = new TNewComponent(this);                   // 4. Construct the component

  NewComponent->Parent = this;         // 5. Set Parent property if component is a control

  NewComponent1->Left = 12;                           // 6. Set other properties as needed

}


Installing a component on the Component palette

See also

When you install a component on the Component palette, the Visual Component Library is rebuilt. Any time VCL is rebuilt, either by installing a component, or by executing the Component|Rebuild Library command, C++Builder creates a temporary library source file. The name of the library source file is the name of the library as a .CPP file. For VCL, the name of the file is CMPLIB32.CPP.

To save the library source file that is generated, choose Options|Environment|Library|Save Library Source Code.

Now when you rebuild VCL, a CMPLIB32.CPP file is created and remains so that you can browse through it.


See also

Adding a component

Modifying how the Visual Component Library is built

Where to place your component


Adding a component

You can add either a C++ or Pascal component to the component library and have it appear on the Component palette.

To add components to the component library,

Choose Component|Install.

The Install Components dialog box appears.

Choose Add to open the Add Module dialog box.

In the Add Module dialog box, type the name of the unit you want to add, or choose Browse to specify a search path.

Note that you can't specify a literal path in the Add Module dialog box. The path you choose in the Add Module Browse dialog box adds the directory path to the search path listed in the Install Components dialog box.

Choose OK to close the Add Module dialog box.

The name(s) of the component unit(s) you have specified appear at the bottom of the Installed Units list. If you select the unit name, the class names for units already residing in the library are displayed in the Component classes list. Class names for newly added units are not shown.

Choose OK to close the Install Components dialog box and rebuild the library.

Note that even if you've made no changes to the unit list, C++Builder rebuilds the library. If you have unsaved forms open, you're prompted to save them. Once the library is rebuilt, the components you've installed are reflected in the Component palette.

Note:

Newly installed components initially appear on the page of the Component palette that was specified by the component writer in the component source code. You can move the components to a different page after they've been installed on the palette. For more information, see the online Help topics Palette (Tools|Options) or Customizing the Component Palette.


Modifying how the Visual Component Library is built

When you install one or more components on the Component palette, all of VCL is rebuilt. To rebuild VCL, C++Builder follows the build process specified in the default COMBLIB32.POF file, which is a make file.

If you want to customize how VCL is built, modify the COMPLIB32.OPT file and specify the changes you want in the build process.


Where to place your component

Before you use the newly installed component, move all the component's files to the C++Builder\LIB\OBJ directory. This includes:

All binary files (.DFM, .RES, .DCR)

All source files (.CPP, .PAS)

All .OBJ and .LIB files

All header files (.H and .HPP)


See also

The Visual Component Library

Components and objects

How do you create components?

What goes in a component?

Creating a new component

 TObject

 TPersistent

 TPrinter

 TStream

 Exception

 TList

 TComponent

 TCanvas

 TPicture

 TStrings

 TGraphic

 TGraphicsObject

 TControl

 TCommonDialog

 TGlobalComponent

 TMenu

 TMenuItem

 TScreen

 TTimer

 TWinControl

 TGraphicControl

 TCustomEdit

 TCustomListBox

 TScrollBar

 TCustomControl

 TCustomComboBox

 TScrollingWinControl

 TButtonControl

 TForm

 TApplication


OOP for component writers

See also

Working with C++Builder, you've encountered the idea that an object contains both data and code, and that you can manipulate objects both at design time and runtime. In that sense, you've become a component user.

When you create new kinds of components, you deal with objects in ways that end users never need to. Before you start creating components, you need to be familiar with these topics related to object-oriented programming (OOP) in general:

Creating new objects

Ancestors and descendants

Controlling access

Dispatching methods

Objects and pointers


See also

Overview of component creation

OOP for component writers

Creating events

Creating methods

Using graphics in components

Handling messages

Registering components


Creating new objects

See also

The primary difference between component users and component writers is that users manipulate instances of objects, and writers create new types of objects. This concept is fundamental to object-oriented programming, and an understanding of the distinction is extremely important if you plan to create your own components.

The concept of types and instances is not unique to objects. Programmers continually work with types and instances, but they don't generally use that terminology. "Type" is a very common idea in C++ programs, and as a programmer you generally create variables of a type. Those variables are instances of the type.

Object types are generally more complex than simple types such as Integer, but by assigning different values to instances of the same type, a user can perform quite different tasks.

For example, it's quite common for a user to create a form containing two buttons, one labeled OK and one labeled Cancel. Each is an instance of type TButton, but by assigning different values to the Text, Default, and Cancel properties and assigning different handlers to the OnClick events, the user makes the two instances do very different things.


See also

Deriving new types

Declaring a new component type


Deriving new types

See also

The purpose of defining object types is to provide a basis for useful instances. That is, the goal is to create an object that you or other users can use in different applications in different circumstances, or at least in different parts of the same application.

There are two reasons to derive new types:

Changing type defaults to avoid repetition

Adding new capabilities to a type

In either case, the goal is to create reusable objects. If you plan ahead and design your objects with future reuse in mind, you can save a lot of later work. Give your object types usable default values, but make them customizable.


See also

Declaring a new component type


Changing type defaults to avoid repetition

In all programming tasks, needless repetition is something to avoid. If you find yourself rewriting the same lines of code over and over, you should either place the code in a subroutine or function, or build a library of routines you'll use in many programs.

The same reasoning holds for components. If you frequently find yourself changing the same properties or making the same method calls, you should probably create a new component type that does those things by default.

For example, it's possible that each time you create an application, you find yourself adding a dialog box form to perform a particular function. Although it's not difficult to recreate the dialog box each time, it's also not necessary. You can design the dialog box once, set its properties, and then install the result onto the Component palette as a reusable component. Not only can this reduce the repetitive nature of the task, it also encourages standardization and reduces the chance of error in recreating the dialog box.


Adding new capabilities to a type

The other reason for creating a new kind of component is that you want to add capabilities not already found in the existing components. When you do that, you can either derive from an existing component type (for example, creating a specialized kind of list box) or from an abstract, base type, such as TComponent or TControl.

As a general rule, derive your new component from the type that contains the closest subset of the features you want. You can add capabilities to an object, but you can't take them away, so if an existing component type contains properties that you don't want to include in yours, you should derive from that component's ancestor.

For example, if you want to add some capability to a list box, you would derive your new component from TListBox. However, if you want to add some new capability but exclude some existing capabilities of the standard list box, you need to derive your new list box from TCustomListBox, the ancestor of TListBox. Next, recreate or make visible the list box capabilities you want to include. Finally, add your new features.


Declaring a new component type

See also	Example

When you decide that you need to derive a new type of component, you then need to decide what type to derive your new type from. As with adding new capabilities to an existing type, the essential rule to follow is this: Derive from the type that contains as much as possible that you want in your component, but which contains nothing that you don't want in your component.

C++Builder provides a number of abstract component types specifically designed for component writers to use as bases for deriving new component types. topic shows the different types you can start from when you create your own components.

To declare a new component type, add a type declaration to the component's unit.


Example

Here is the declaration of a simple graphical component:

class TSampleShape : public TGraphicControl

{

};

A finished component declaration includes property, data member, and method declarations before the final }, but an empty declaration is also valid, and provides a starting point for the addition of component features.


See also

Deriving new types


Ancestors and descendants

See also

From a component user's standpoint, an object is a self-contained entity consisting of properties, methods and events. Component users don't need to know or care about such issues as which object a given component descends from. But these issues are extremely important to you as a component writer.

Component users can take for granted that every component has properties named Top and Left that determine where the component appears on the form that owns it. To them, it does not matter that all components inherit those properties from a common ancestor, TComponent. When you create a component, however, you must know which object to derive from so as to inherit the appropriate parts. You also must know everything your component inherits, so you can take advantage of inherited features without recreating them.

From the definition of object types, you know that when you define an object type, you derive it from an existing object type. The type you derive from is called the immediate ancestor of your new object type. The immediate ancestor of the immediate ancestor is called an ancestor of the new type, as are all of its ancestors. The new type is called a descendant of its ancestors.

If you do not specify an ancestor object type, C++Builder derives your object from the default ancestor object type, TObject. Ultimately, the standard type TObject is an ancestor of all objects in the Visual Component Library.


See also

Object hierarchies


Object hierarchies

All the ancestor-descendant relationships in an application result in a hierarchy of objects. The most important thing to remember about object hierarchies is that each "generation" of descendant objects contains more than its ancestors. That is, an object inherits everything that its ancestor contains, then adds new data and methods or redefines existing methods.

However, an object cannot remove anything it inherits. For example, if an object has a particular property, all descendants of that object, direct or indirect, will also have that property.

The general rule for choosing which object to derive from is simple: Pick the object that contains as much as possible of what you want to include in your new object, but which does not include anything you do not want in the new object. You can always add things to your objects, but you cannot take things out.


Controlling access

There are four levels of access control on the parts of objects. Access control lets you specify which code can access which parts of the object. By specifying levels of access, you define the interface to your components. If you plan the interface carefully, you improve both the usability and reusability of your components.

Unless you specify otherwise, the data members, methods, and properties you add to your objects are published meaning that any code that has access to the object as a whole also has access to those parts of the object, and the compiler generates runtime type information for those items.

The following table shows the levels of access, in order from most restrictive to most accessible:

Protection	Used for

private	Hiding implementation details

protected	Defining the developer's interface

public	Defining the runtime interface

__published	Defining the design-time interface

__automated	For OLE automation

All protections operate at the level of units. That is, if a part of an object is accessible (or inaccessible) in one part of a unit, it is also accessible (or inaccessible) everywhere else in the unit. If you want to give special protection to an object or part of an object, you need to put it in its own unit.


Hiding implementation details

See also	Example

Declaring part of an object as private makes that part invisible to code outside the unit in which you declare the object type. Within the unit that contains the declaration, code can access the part as if it were public.

Private parts of object types are mostly useful for hiding details of implementation from users of the object. Because users of the object can't access the private parts, you can change the internal implementation of the object without affecting user code.


Example

Here is an example shown in two parts that illustrates how declaring a data member as private prevents users from accessing information.

The first part is a form unit made up of a header file and a .CPP file that assigns a value to private data member in the form's OnCreate event handler. Because the event handler is declared within the HideInfo unit, the unit compiles without error.

#ifndef HideInfoH

#define HideInfoH

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

//---------------------------------------------------------------------------

class TSecretForm : public TForm

{

__published:    // IDE-managed Components

    void __fastcall FormCreate(TObject *Sender);

private:

    int FSecretCode;                                  // declare a private data member

public:         // User declarations

    virtual __fastcall TSecretForm(TComponent* Owner);

};

//---------------------------------------------------------------------------

extern TSecretForm *SecretForm;

//---------------------------------------------------------------------------

#endif

This is the accompanying .CPP file:

#include <vcl.h>

#pragma hdrstop

#include "HideInfo.h"

//---------------------------------------------------------------------------

#pragma resource "*.dfm"

TSecretForm *SecretForm;

//---------------------------------------------------------------------------

__fastcall TSecretForm::TSecretForm(TComponent* Owner)

  : TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TSecretForm::FormCreate(TObject *Sender)

{

    FSecretCode = 42;                             // this compiles correctly

}

The second part of this example is another form unit that attempts to assign a value to the FSecretCode data member in the SecretForm form. This is the header file for the unit:

#ifndef TestHideH

#define TestHideH

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

//---------------------------------------------------------------------------

class TTestForm : public TForm

{

__published:    // IDE-managed Components

    void __fastcall FormCreate(TObject *Sender);

public:         // User declarations

    virtual __fastcall TTestForm(TComponent* Owner);

};

//---------------------------------------------------------------------------

extern TTestForm *TestForm;

//---------------------------------------------------------------------------

#endif

This is the accompanying .CPP file. Because the OnCreate event handler attempts to assign a value to a data member private to the SecretForm form, the compilation fails with the error message 'TScretForm::FSecretCode' is not accessible.

#include <vcl.h>

#pragma hdrstop

#include "TestHide.h"

#include "HideInfo.h"

//---------------------------------------------------------------------------

#pragma resource "*.dfm"

TTestForm *TestForm;

//---------------------------------------------------------------------------

__fastcall TTestForm::TTestForm(TComponent* Owner)

  : TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TTestForm::FormCreate(TObject *Sender)

{

  SecretForm->FSecretCode = 13;                 //compiler stops here with error message

}

Although a program using the HideInfo unit can use objects of type TSecretForm, it can't access the FSecretCode data member in any of those objects.


See also

Defining the developer's interface

Defining the runtime interface

Defining the design-time interface


Defining the developer's interface

See also

Declaring part of an object as protected makes that part invisible to code outside the unit in which you declare the object type, much like parts declared private. With protected parts, however, units that contain object types derived from the object type can access the protected parts.

You can use protected declarations to define a developer's interface to the object. That is, users of the object don't have access to the protected parts, but developers (such as component writers) do. In general, that means you can make interfaces available that allow component writers to change the way an object works without making those details visible to end users.


See also

Hiding implementation details

Defining the runtime interface

Defining the design-time interface


Defining the runtime interface

See also	Example

Declaring part of an object as public makes that part visible to any code that has access to the object as a whole. That is, the public part has no special restrictions on it. If you don't specify any access control (private, protected, or public) on a data member, method, or property, that part is published.

Public parts of objects are available at runtime to all code, so the public parts of an object define that object's runtime interface. The runtime interface is useful for items that aren't meaningful or appropriate at design time, such as properties that depend on actual runtime information or which are read-only. Methods that you intend for users of your components to call should also be declared as part of the runtime interface.

Note that read-only properties can't operate at design time, so they should appear in the public declaration section.


Example

Here is an example that shows two read-only properties declared as part of a component's runtime interface:

class TSampleComponent : public TComponent

{

private:

  int FTempCelsius;                                  // implementation details are private

  int GetTempFahrenheit();

public:

  ...

  __property int TempCelsius = {read=FTempCelsius};          // properties are public

  __property int TempFahrenheit = {read=GetTempFahrenheit};

};

This is the GetTempFahrenheit method in the .CPP file:

int TSampleComponent::GetTempFahrenheit()

{

   return FTempCelsius * (9 / 5) + 32;

}

Because the user can't change the value of the properties, the properties should not appear in the Object Inspector, and, therefore, they should not be part of the design-time interface.


See also

Hiding implementation details

Defining the developer's interface

Defining the design-time interface


Defining the design-time interface

See also	Example

Declaring part of an object as published makes that part public and also generates runtime type information for the part. Among other things, runtime type information ensures that the Object Inspector can access properties and events.

Because only published parts show up in the Object Inspector, the published parts of an object define that object's design-time interface. The design-time interface should include any aspects of the object that a user might want to customize at design time, but must exclude any properties that depend on specific information about the runtime environment.

Note:

Read-only properties cannot be part of the design-time interface because the user cannot alter them. Read-only properties should be public.


Example

Here is an example of a published property. Because it is published, it appears in the Object Inspector at design time.

class TSampleComponent : public TComponent

{

private:

  int FTemperature;

  ...

__published:

  __property int Temperature = {read=FTemperature, write=FTemperature};

};

Temperature, the property in this example, is available at design time, so users of the component can adjust the value.


See also

Hiding implementation details

Defining the developer's interface

Defining the runtime interface


Dispatching methods

Dispatching is the term used to describe how your application determines what code to execute when making a method call. When you write code that calls an object method, it looks like any other procedure or function call. However, objects have three different ways of dispatching methods.

The two types of method dispatch are

Static

Virtual


Static methods

See also	Example

All object methods are static unless you specify otherwise when you declare them. Static methods work just like regular method calls. The compiler determines the exact address of the method and links the method at compile time.

Dispatching methods is very quick. Because the compiler can determine the exact address of the method, it links the method directly. Virtual methods, by contrast, use indirect means to look up the address of their methods at runtime, which takes somewhat longer.

A static method is that it doesn't change at all when inherited by another type. That is, if you declare an object type that includes a static method, then derive a new object type from it, the descendant object shares exactly the same method at the same address. Static methods, therefore, always do exactly the same thing, no matter what the actual type of the object.

You can't override static methods. Declaring a method in a descendant type with the same name as a static method in the object's ancestor replaces the ancestor's method.


Example

In the following code, the first component declares two static methods. The second declares two static methods with the same names that replace the methods in the first.

class TFirstComponent : public TComponent

{

public:

  void __fastcall Move();

  void __fastcall Flash();

};

class TSecondComponent : public TFirstComponent

{

public:

  void __fastcall Move();     // different from inherited method, despite same declaration

  int __fastcall Flash(int HowOften);                  // this is also different

};


See also

Virtual methods


Virtual methods

See also

Calling a virtual method is just like calling any other method, but the mechanism for dispatch is a little more complex because it is also more flexible. Virtual methods enable you to redefine methods in descendant objects, but still call the methods the same way. That is, the address of the method isn't determined at compile time. Instead, the object looks up the address of the method at runtime.

To declare a new virtual method, preface the method declaration with the virtual keyword.

The virtual keyword in a method declaration creates an entry in the object's virtual method table, or VMT. The VMT holds the addresses of all the virtual methods in an object type.

When you derive a new object from an existing object type, the new type gets its own VMT, which includes all the entries from its ancestor's VMT, plus any additional virtual methods declared in the new object. In addition, the descendant object can override of its inherited virtual methods.

Note:

The constructor for a component must always be virtual.


See also

Static methods

Overriding methods


Overriding methods

See also	Example

Overriding a method means extending or refining it, rather than replacing it. That is, a descendant object type can redeclare and reimplement any of the methods declared in its ancestors. You can't override static methods, because declaring a static method with the same name as an inherited static method replaces the inherited method completely.

To override a method in a descendant object type, simply redeclare the method in the derived object, ensuring that the number and type of arguments are the same.

Overriding a method causes a compilation error if:

The method does not exist in the ancestor object.

The ancestor's method of that name is static.

The declarations are not otherwise identical (number and type of arguments differ).


Example

The following code shows the declaration of two simple components. The first declares two methods, each with a different kind of dispatching. The other, derived from the first, replaces the static method and overrides the virtual method.

class TFirstComponent : public TComponent

{

public:

  void Move();

  virtual void Flash();

};

class TSecondComponent : public TFirstComponent

{

public:

  void Move();    // declares new method "hiding" Move  in TFirstComponent

  void Flash();                      // overrides Flash in TFirstComponent

};


See also

Virtual methods


Objects and pointers

One thing to be aware of when writing components that you don't need to consider when using existing components is that every object (and therefore every component) is really a pointer. The compiler automatically dereferences the object pointers for you, so in most cases, you never need to think about objects being pointers.

This becomes important, however, when you pass objects as parameters.

In general, you should pass objects by value rather than by reference. The reason is that objects are already pointers, which are references. Passing an object by reference, then, would be passing a reference to the reference.


Creating properties

See also

Properties are the most distinctive parts of components, largely because component users can see and manipulate them at design time and get immediate feedback as the components react in real time. Properties are also important because, if you design them well, they make your components easier for others to use and easier for you to maintain.

In order to best make use of properties in your components, you should understand the following:

Why create properties?

Types of properties

Publishing inherited properties

Defining component properties

Creating array properties

Writing property editors


See also

Overview of component creation

OOP for component writers

Creating events

Creating methods

Using graphics in components

Handling messages

Registering components


Why create properties?

See also

Properties provide significant advantages, both for you as a component writer and for the users of your components. The most obvious advantage is that properties can appear in the Object Inspector at design time. That simplifies your programming job, because instead of handling several parameters to construct an object, you just read the values assigned by the user.

From the component user's standpoint, properties look like variables. Users can set or read the values of properties much as if those properties were object data members. About the only thing they cannot do with a property that they would with a variable is pass it as an argument to a method by reference.

From the component writer's standpoint, however, properties provide much more power than simple object data members because

Users can set properties at design time.

This is very important, because unlike methods, which are only available at runtime, properties let users customize components before running an application. In general, your components should not contain a lot of methods; most of them can probably be encapsulated into properties.

Unlike an object data member, a property can hide implementation details from users.

For example, the data might be stored internally in an encrypted form, but when setting or reading the value of the property, the data would appear unencrypted. Although the value of a property might be a simple number, the component might look up the value from a database or perform complex calculations to arrive at that value.

Properties allow side effects to outwardly simple assignments.

What appears to be a simple assignment involving an object data member is really a call to a method, and that method could do almost anything.

A simple example is the Top property of all components. Assigning a new value to Top doesn't just change some stored value; it causes the component to relocate and repaint itself. The effects of property setting need not be limited to an individual component. For example, setting the Down property of a speed-button component to true causes the speed button to set the Down properties of all other speed buttons in its group to false.

The implementation methods for a property can be virtual, meaning that what looks like a single property to a component user might do different things in different components.


See also

Types of properties

Publishing inherited properties

Defining component properties

Creating array properties

Writing property editors


Types of properties

See also

A property can be of any type that a function can return (since the implementation of the property can use a function). The most important aspect of choosing types for your properties is that different types appear differently in the Object Inspector. The Object Inspector uses the type of the property to determine what choices appear to the user. You can specify a different property editor when you register your components, as explained in "Writing property editors" in this chapter Writing property editors.

Property type	Object Inspector treatment

Simple	Numeric, character, and string properties appear in the Object Inspector as numbers, characters, and strings, respectively. The user can type and edit the value of the property directly.

Enumerated	Properties of enumerated types (including Boolean) display the value as defined in the source code. The user can cycle through the possible values by double-clicking the value column. There is also a drop-down list that shows all possible values of the enumerated type.

Set	Properties of set types appear in the Object Inspector looking like a set. By expanding the set, the user can treat each element of the set as a Boolean value: true if the element is included in the set or false if it's not included.

Object	Properties that are themselves objects often have their own property editors. However, if the object that is a property also has published properties, the Object Inspector allows the user to expand the list of object properties and edit them individually. Object properties must descend from TPersistent.

Array	Array properties must have their own property editors. The Object Inspector has no built-in support for editing array properties.


See also

Why create properties?

Publishing inherited properties

Defining component properties

Creating array properties

Writing property editors


Publishing inherited properties

See also	Example

All components inherit properties from their ancestor types. When you derive a new component from an existing component type, your new component inherits all the properties in the ancestor type. If you derive instead from one of the abstract types, many of the inherited properties are either protected or public, but not published.

If you need more information about levels of protection such as protected, private, and published, see.

To make a protected or public property available to users of your components, you must redeclare the property as published.

Redeclaring means adding the declaration of an inherited property to the declaration of a descendant object type.


Example

If you derive a component from TWinControl, it inherits a Ctl3D property, but that property is protected, so users of the component cannot access Ctl3D at design time or runtime. By redeclaring Ctl3D in your new component, you can change the level of protection to either public or published.

The following code shows a redeclaration of Ctl3D as published, making it available at design time:

class TSampleComponent : public TWinControl

{

__published:

  __property Ctl3D;

};

Note that redeclarations can only make a property less restricted, not more restricted. Thus, you can make a protected property public, but you cannot "hide" a public property by redeclaring it as protected.

When you redeclare a property, you specify only the property name, not the type and other information described in You can also declare new default values when redeclaring a property, or specify whether to store the property.


See also

Why create properties?

Types of properties

Defining component properties

Creating array properties

Writing property editors


Defining component properties

See also

This section focuses on how to declare properties in C++Builder components and the conventions used by the standard components.

Specific topics include

The property declaration

Internal data storage

Direct access

Access methods

Default property values


See also

Why create properties?

Types of properties

Publishing inherited properties

Creating array properties

Writing property editors


The property declaration

See also	Example

Declaring a property and its implementation is easy. You add the property declaration to the declaration of your component object type.

To declare a property, you specify three things:

The name of the property

The type of the property

Methods to read and/or set the value of the property

At a minimum, a component's properties should be declared in a public part of the component's object-type declaration, making it easy to set and read the properties from outside the component at runtime.

To make the property editable at design time, declare the property in a published part of the component's object type declaration. Published properties automatically appear in the Object Inspector. Public properties that aren't published are available only at runtime.


Example

Here is a typical property declaration:

class TYourComponent : public TComponent

{

private:

   int FCount;                                               // data member for storage

   int __fastcall GetCount();                                // read method

   void __fastcall SetCount( int ACount );                   // write method

public:

   __property int Count = {read=GetCount, write=SetCount};   // property declaration

  ...

};


See also

Internal data storage

Direct access

Access methods

Default property values


Internal data storage (properties)
Internal data storage

See also

There are no restrictions on how you store the data for a property. In general, however, C++Builder's components follow these conventions:

Property data is stored in object data members.

Identifiers for properties' object data members start with the letter F, and incorporate the name of the property. For example, the raw data for the Width property defined in TControl is stored in an object data member called FWidth.

Object data members for property data should be declared as private. This ensures that the component that declares the property has access to them, but component users and descendant components don't.

Descendant components should use the inherited property itself, not direct access to the internal data storage, to manipulate a property.

The underlying principle behind these conventions is that only the implementation methods for a property should access the data behind that property. If a method or another property needs to change that data, it should do so through the property, not by direct access to the stored data. This ensures that the implementation of an inherited property can change without invalidating descendant components.


See also

The property declaration

Direct access

Access methods

Default property values


Direct access

See also	Example

The simplest way to make property data available is direct access. That is, the read and write parts of the property declaration specify that assigning or reading the property value goes directly to the internal storage data member without calling an access method. Direct access is useful when the property has no side effects, but you want to make it available in the Object Inspector.

It is common to have direct access for the read part of a property declaration but use an access method for the write part, usually to update the status of the component based on the new property value.


Example

The following component-type declaration shows a property that uses direct access for both the read and write parts:

class TSampleComponent : public TComponent

{

private:                                        // internal storage is private

  Boolean FReadOnly;                            // declare data member to hold value

  ...

__published:                                    // make property available at design time

  __property Boolean ReadOnly = {read=FReadOnly, write=FReadOnly};

};


See also

The property declaration

Internal data storage

Access methods


Acces methods (properties)
Access methods

See also

The syntax for property declarations allows the read and write parts of a property declaration to specify access methods instead of an object data member. Regardless of how a particular property implements its read and write parts, however, that implementation should be private, and descendant components should use the inherited property for access. This ensures that use of a property is not affected by changes in the underlying implementation.

Making access methods private also ensures that component users don't accidentally call those methods, inadvertently modifying a property.

The read method

The read method for a property is a function that takes no parameters, and returns a value of the same type as the property. By convention, the function's name is "Get" followed by the name of the property. For example, the read method for a property named Count would be named GetCount.

The only exception to the "no parameters" rule is for array properties, which pass their indexes as parameters.

The read method manipulates the internal storage data as needed to produce the value of the property in the appropriate type.

If you don't declare a read method, the property is write-only. Write-only properties are very rare, and generally not very useful.

The write method

The write method for a property is always a procedure that takes a single parameter, of the same type as the property. The parameter can be passed by reference or by value, and can have any name you choose. By convention, the procedure's name is "Set" followed by the name of the property. For example, the write method for a property named Count would be named SetCount.

The value passed in the parameter is used to set the new value of the property, so the write method needs to perform any manipulation needed to put the appropriate values in the internal storage.

If you don't declare a write method, the property is read-only.

It's common to test whether the new value actually differs from the current value before setting the value. For example, here's a simple write method for an integer property called Count that stores its current value in a data member called FCount:

void __fastcall TMyComponent::SetCount( int Value )

{

  if ( Value != FCount ) {

    FCount = Value;

    Update();

    }

}


See also

The property declaration

Internal data storage

Direct access

Default property values


Default property values

See also	Example

When you declare a property, you can optionally declare a default value for the property. The default value for a component's property is the value set for that property in the component's constructor. For example, when you place a component from the Component palette on a form, C++Builder creates the component by calling the component's constructor, which determines the initial values of the component's properties.

C++Builder uses the declared default value to determine whether to store a property in a form file. For more information on storing properties and the importance of default values, see. If you do not specify a default value for a property, C++Builder always stores the property.

To declare a default value for a property, append an equal sign after the property name and a set of curly braces that holds the default keyword and the default value. For example,

__property Boolean IsTrue = {default=true};

Note:

Declaring a default value in the property declaration does not actually set the property to that value. It is your responsibility as the component writer to ensure that the component's constructor actually sets the property to that value.

Specifying no default value

When redeclaring a property, you can specify that the property has no default value, even if the inherited property specified one.

To designate a property as having no default value, append an equal sign after the property name and a set of curly braces that holds the nodefault keyword. For example,

__property int NewInteger = {nodefault};

When you declare a property for the first time, there is no need to specify nodefault because the absence of a declared default value means the same thing.


Example

Here is the declaration of a component that includes a single Boolean property named IsTrue with a default value of true, including the constructor that sets the default value.

class TSampleComponent : public TComponent

{

private:

  Boolean FIsTrue;

public:

  virtual __fastcall TSampleComponent( TComponent* AOwner );

__published:

  __property Boolean IsTrue = {read=FIsTrue, write=FIsTrue, default=true};

};

__fastcall TSampleComponent::TSampleComponent ( TComponent* AOwner )

  : TComponent ( AOwner )

{

   FIsTrue = true;

}

Note that if the default value for IsTrue had been false, you would not need to set it explicitly in the constructor, because all objects (and therefore, components) always initialize all their data members to zero, and a "zeroed" Boolean value is false.


See also

The property declaration

Internal data storage

Direct access

Access methods


Creating array properties

See also	Example

Some properties lend themselves to being indexed, much like arrays. That is, they have multiple values that correspond to some kind of index value. An example in the standard components is the Lines property of the memo component. Lines is an indexed list of the strings that make up the text of the memo, which you can treat as an array of strings. In this case, the array property gives the user natural access to a particular element (a string) in a larger set of data (the memo text).

Array properties work just like other properties, and you declare them in largely the same way. The only differences in declaring array properties are as follows:

The declaration for the property includes one or more indexes with specified types. Indexes can be of any type.

The read and write parts of the property declaration, if specified, must be methods. They cannot be object data members.

The access methods for reading and writing the property values take additional parameters that correspond to the index or indexes. The parameters must be in the same order and of the same type as the indexes specified in the property declaration.

Although they seem quite similar, there are a few important distinctions between array properties and arrays. Unlike the index of an array, the index type for an array property does not have to be an integer type. You can index a property on a string, for example. In addition, you can only reference individual elements of an array property, not the entire range of the property.


Example

Here's the declaration of a property that returns a string based on an integer index:

class TDemoComponent : public TComponent

{

private:

    AnsiString __fastcall GetNumberSize(int Index);

public:

    __property AnsiString NumberSize[int Index] = {read=GetNumberSize};

  ...

};

This is the GetNumberSize method in the .CPP file:

AnsiString __fastcall TDemoComponent::GetNumberSize(int Index)

{

  AnsiString Result;

  switch (Index)

  {

    case 0:

      Result = "Zero";

      break;

    case 100:

      Result = "Medium";

      break;

    case 1000:

      Result = "Large";

      break;

      default: Result = "Unknow size";

    }

    return Result;

 }


See also

Why create properties?

Types of properties

Publishing inherited properties

Defining component properties

Writing property editors


Creating events

See also

Events are very important parts of components, although the component writer doesn't usually need to do much with them. An event is a link between an occurrence in the system (such as a user action or a change in focus) that a component might need to respond to and a piece of code that responds to that occurrence. The responding code is an event handler, and is nearly always written by the component user.

By using events, application developers can customize the behavior of components without having to change the objects themselves. As a component writer, you use events to enable application developers to customize the behavior of your components.

Events for the most common user actions (such as mouse actions) are built into all the standard C++Builder components, but you can also define new events and give them their own events. To create events in a component, you need to understand the following:

What are events?

Implementing the standard events

Defining your own events

C++Builder implements events as properties, so you should already be familiar with Creating properties before you attempt to create or change a component's events.

lasdielksdfjielskduke


See also

Overview of component creation

OOP for component writers

Creating properties

Using graphics in components

Using graphics in components

Handling messages

Registering components


What are events?

See also

Loosely defined, an event is a mechanism that links an occurrence to some code. More specifically, an event is a closure, a pointer to a specific method in a specific object instance.

From the component user's perspective, an event is just a name related to a system event, such as OnClick, that the user can assign a specific method to call. For example, a push button called Button1 has an OnClick method. By default, C++Builder generates an event handler called Button1Click in the form that contains the button and assigns it to OnClick. When a click event occurs on the button, the button calls the method assigned to OnClick, in this case, Button1Click.

The component user sees the event as a way of specifying what user-written code the application should call when a specific event occurs.

From the component writer's perspective, there's a lot more to an event. The most important thing to remember, however, is that you're providing a link, a place where the component's user can attach code in response to certain kinds of occurrences. Your components provide outlets where the user can "plug in" specific code.

In order to write an event, you need to understand the following:

Events are closures

Events are properties

Event-handler types

Event handlers are optional


See also

Implementing the standard events

Defining your own events


Events are closures

See also	Example

C++Builder uses closures to implement events. A closure is a special pointer type that points to a specific method in a specific object instance. As a component writer, you can treat the closure as a placeholder: your code detects that an event occurs, so you call the method (if any) specified by the user for that event.

Closures maintain a hidden pointer to an object instance. When the user assigns a handler to a component's event, the assignment is not just to a method with a particular name, but rather to a specific method of a specific object instance. That instance is usually the form that contains the component, but it need not be.


Example

All controls inherit a dynamic method called Click for handling click events:

DYNAMIC void __fastcall Click(void);

The implementation of Click calls the user's click-event handler, if one exists. If the user has assigned a handler to a control's OnClick event, clicking the control results in that method being called. If no handler is assigned, nothing happens.


See also

Events are properties

Event-handler types

Event handlers are optional


Events are properties

See also

Components use properties to implement their events. Unlike most other properties, events don't use methods to implement their read and write parts. Instead, event properties use a private object data member of the same type as the property.

By convention, the field's name is the same as the name of the property, but preceded by the letter F. For example, the OnClick method's pointer is stored in a field called FOnClick of type TNotifyEvent, and the declaration of the OnClick event property looks like this:

class TControl : public TComponent

{

private:

    TNotifyEvent FOnClick;

  ...

protected:

    __property TNotifyEvent OnClick = {read=FOnClick, write=FOnClick};

  ...

};

As with any other property, you can set or change the value of an event at runtime. The main advantage to having events be properties, however, is that component users can assign handlers to events at design time, using the Object Inspector.


See also

Events are closures

Event-handler types

Event handlers are optional


Event-handler types

See also

Because an event is a pointer to an event handler, the type of the event property must be a closure type. Similarly, any code to be used as an event handler must be an appropriately typed method of an object.

To be compatible with an event of a given type, an event-handler method must have the same number and type of parameters, in the same order, passed in the same way.

C++Builder defines method types for all its standard events. When you create your own events, you can use an existing type if that's appropriate, or define one of your own.

Event handlers have a return type of void

Event handers must have a return type of void only. Even though the handler can return only void, you can still get information back from the user's code by passing arguments by reference. When you do this, make sure you assign a valide value to the argument before calling the handler so you don't require the usr's code to change the value.

An example of passing arguments by reference to an event handler is the key-pressed event, of type TKeyPressEvent. TKeyPressEvent defines two arguments, one to indicate which object generated the event, and one to indicate which key was pressed:

typedef void __fastcall (__closure *TKeyPressEvent)(TObject *Sender, Char &Key);

Normally, the Key parameter contains the character pressed by the user. Under certain circumstances, however, the user of the component might want to change the character. One example might be to force all characters to uppercase in an edit control. In that case, the user could define the following handler for keystrokes:

void __fastcall TForm1::Edit1KeyPress(TObject *Sender, Char &Key)

{

  Key = UpCase(Key);

}

You can also use arguments passed by reference to let the user override the default handling.


See also

Events are closures

Events are properties

Event handlers are optional


Event handlers are optional

See also

The most important thing to remember when creating events for your components is that users of your components might not attach handlers to the events. That means that your component shouldn't fail or generate errors simply because a user of the component failed to attach a handler to a particular event.

The mechanics of calling handlers and dealing with events that have no attached handler are explained in Calling the event, but the principle has important implications for the design of your components and their events.

The optional nature of event handlers has two aspects:

Component users are not required to handle events.

Events happen almost constantly in a Windows application. Just by moving the mouse pointer across a component makes Windows send numerous mouse-move messages to the component, which the component translates into OnMouseMove events. In most cases, however, users of components don't care to handle the mouse move events, and this does not cause a problem. The component does not depend on the mouse events being handled.

Similarly, the components you create should not be dependent on users handling the events they generate.

Component users can write any code they want in an event handler.

In general, there are no restrictions on the code a user can write in an event handler. The components in the C++Builder component library all have events written in such a way that they minimize the chances of user-written code generating unexpected errors. Obviously, you can't protect against logic errors in user code, but you can, for example, ensure that all data structures are initialized before calling events so that users don't try to access invalid information.


See also

Events are closures

Events are properties

Event-handler types


Implementing the standard events

See also

All the controls that come with C++Builder inherit events for all of the most common Windows events. Collectively, these are called the standard events. Although all these events are built into the standard controls, by default theyare protected, meaning end users can't attach handlers to them. When you create a control, you can choose to make events visible to users of your control.

There are three things you need to consider when incorporating the standard events into your controls:

What are the standard events?

Making events visible

Changing the standard event handling


See also

What are events?

Defining your own events


What are the standard events?

See also

There are two categories of standard events: those defined for all controls and those defined only for the standard windows controls.

Standard events for all controls

The most basic events are defined in the object type TControl. All controls, whether windowed or graphical or custom, inherit these events. The following table lists all the events available in all controls:

OnClick	OnDragDrop	OnEndDrag	OnMouseMove
OnDblClick	OnDragOver	OnMouseDown	OnMouseUp
All the standard events have corresponding protected dynamic methods declared in TControl, with names that correspond to the event names, but without the preceding "On." For example, OnClick events call a method named Click.

Standard events for standard controls

In addition to the events common to all controls, standard controls (those that descend from TWinControl) have the following events:

OnEnter	OnKeyDown	OnKeyPress
OnKeyUp	OnExit
As with the standard events in TControl, the windowed-control events have corresponding methods.


See also

Changing the standard event handling

Making events visible


Making events visible

See also	Example

The declarations of the standard events are protected as are the methods that correspond to them. If you want to make those events accessible to users either at runtime or design time, you need to redeclare the event property as either public or published.

Redeclaring a property without specifying its implementation keeps the same implementation methods, but changes the protection level. You can, therefore, take an event that's defined in TControl but not made visible to users, and promote it to a level so the user can see and use it.


Example

If you create a component that needs to surface the OnClick event at design time, you add the following to the component's type declaration:

class TMyControl : public TCustomControl

{

  ...

__published:

    __property OnClick;             // Makes OnClick available in the Object Inspector

};


See also

What are the standard events?

Changing the standard event handling


Changing the standard event handling

See also	Example

If you want to change the way your custom component responds to a certain kind of event, you might be tempted to write some code and assign it to the event. As a component user, that's exactly what you would do. When you're creating components you can't do that, however, because you must keep the event available for the users of the component.

This is precisely the reason for the protected implementation methods associated with each of the standard events. By overriding the implementation method, you can modify the internal event handling, and by calling the inherited method you can maintain the standard handling, including the event for the user's code.

The order in which you call the inherited method is significant. As a general rule, you call the inherited method first, allowing the user's event-handler code to execute before your customizations (and in some cases, to keep from executing the customizations). There might be times when you want to execute your code before calling the inherited method, however. For example, if the inherited code is somehow dependent on the status of the component and your code changes that status, you should make the changes and then allow the user's code to respond to the changed status.


Example

Suppose you're writing a component and you want to modify the way your new component responds to clicks. Instead of assigning a handler to the OnClick event as a component user would do, you override the protected method Click:

void __fastcall TMyControl::Click()

{

     TWinControl::Click();        // perform standard handling, including calling handler

    // your customizations go here

}


See also

What are the standard events?

Making events visible


Defining your own events

See also

Defining entirely new events is a relatively rare thing. Usually you refine the handling of existing events. There are times, however, when a component introduces behavior that is entirely different from any other, so you'll need to define an event for it.

There are four steps involved in defining an event:

Triggering the event

Defining the handler type

Declaring the event

Calling the event


See also

What are events?

Implementing the standard events


Triggering the event

See also	Example

You need to know what triggers the event. For some events, the answer is obvious. For example, a mouse-down event occurs when the user presses the left button on the mouse and Windows sends a WM_LBUTTONDOWN message to the application. Upon receiving that message, a component calls its MouseDown method, which in turn calls any code the user has attached to the OnMouseDown event.

But some events are less clearly tied to specific external events. A scroll bar, for example, has an OnChange event, triggered by numerous kinds of occurrences, including keystrokes, mouse clicks, or changes in other controls. When defining your events, you must ensure that all the appropriate occurrences call the proper events.

Two kinds of events

There are two kinds of occurrences you might need to provide events for: user interactions and state changes. User-interaction events are nearly always triggered by a message from Windows, indicating that the user did something your component might need to respond to. State-change events might also be related to messages from Windows (focus changes or being enabled, for example), but they can also occur through changes in properties or other code. You have total control over the triggering of events you define. You should be consistent and complete so that users of your components know how to use the events.


See also

Defining the handler type

Declaring the event

Calling the event


Defining the handler type

See also

Once you determine when the event occurs, you must define how you want the event handled. This means determining the type of the event handler. In most cases, handlers for the events you define yourself are either simple notifications or event-specific types. It's also possible to get information back from the handler.

Simple notifications

A notification event is one that only tells you that the particular event happened, with no specific information about when or where. Notifications use the type TNotifyEvent, which carries only one parameter, the sender of the event. All a handler for a notification "knows" about the event is what kind of event it was, and what component the event happened to. For example, click events are notifications. When you write a handler for a click event, all you know is that a click occurred and which component was clicked.

Notification is a one-way process. There is no mechanism to provide feedback or prevent further handling of a notification.

Event-specific handlers

In some cases, it's not enough to know just what event happened and what component it happened to. For example, if the event is a key-press event, it's likely that the handler will want to know which key the user pressed. In these cases, you need handler types that include parameters with any necessary information about the event.

If your event was generated in response to a message, it's likely that the parameters you pass to the event handler come directly from the message parameters.

Returning information from the handler

Because all event handlers return void only, the only way to pass information back from a handler is through a parameter passed by reference. Your components can use such information to determine how or whether to process an event after the user's handler executes.

For example, all the key events (OnKeyDown, OnKeyUp, and OnKeyPress) pass by reference the value of the key pressed in a parameter named Key. The event handler can change Key so that the application sees a different key as being involved in the event. This is a way to, for instance, force typed characters to uppercase.


See also

Triggering the event

Declaring the event

Calling the event


Declaring the event

See also

Once you've determined the type of your event handler, you're ready to declare the closure and the property for the event. Be sure to give the event a meaningful and descriptive name so that users can understand what the event does. Try to be consistent with names of similar properties in other components.

Event names start with "On"

The names of most events in C++Builder begin with "On." This is just a convention; the compiler doesn't enforce it. The Object Inspector determines that a property is an event by looking at the type of the property: all closure properties are assumed to be events and appear on the Events page.

Component users expect to find events in the alphabetical list of names starting with "On." Using other kinds of names is likely to confuse them.


See also

Triggering the event

Defining the handler type

Calling the event


Calling the event

See also

Usually it's best to centralize calls to an event. That is, create a virtual method in your component that calls the user's event handler (if the user assigns one) and provides any default handling.

Putting all the event calls in one place ensures that someone deriving a new component from your component can customize event handling by overriding that one method, rather than searching through your code looking for places you call the event.

There are two other considerations when calling the event:

Empty handlers must be valid

Users can override default handling


See also

Triggering the event

Defining the handler type

Declaring the event


Empty handlers must be valid

See also	Example

You should never create a situation in which an empty event handler causes an error. That is, the proper functioning of your component should not depend on a particular response from the user's event-handler code. In fact, an empty handler should produce the same result as no handler at all.

Components should never require the user to use them in a particular way. An important aspect of that principle is that component users expect no restrictions on what they can do in an event handler.


Example

Because an empty handler should behave the same as no handler, the code for calling the user's handler should look like this:

if (OnClick)

  OnClick(this);

// perform default handling }

You should never have something like this:

if (OnClick)

  OnClick(this);

else

  // perform default handling


See also

Users can override default handling


Users can override default handling

See also	Example

For some kinds of events, the user might want to replace the default handling or even suppress all responses. To enable users to do that, you need to an argument by reference to the handler and check for a certain value when the handler returns.

Note that this is in keeping with the notion that empty handlers should have the same effect as no handler at all: because an empty handler won't change the values of arguments passed by reference, the default handling always takes place after calling the empty handler.


Example

When handling key-press events the user can suppress the component's default handling of the keystroke by setting the Key parameter to a null character. The logic for supporting that looks like this:

if (OnKeyPress)

  OnKeyPress(this, &Key);

if (Key != NULL)

  //perform default handling

The actual code is a little different from this because it's dealing with Windows messages, but the logic is the same. By default, the component calls any user-assigned handler, then performs its standard handling. If the user's handler sets Key to a null character, the component skips the default handling.


See also

Empty handlers must be valid


Creating methods

See also

Component methods are no different from any other object's methods. That is, they are member functions built into the structure of a component object. Although there are essentially no restrictions on what you can do with the methods of a component, C++Builder does use some standards you should follow.

The guidelines to follow when writing methods for your components include

Avoiding interdependencies

Naming methods

Protecting methods

Making methods virtual

Declaring methods

As a general rule, minimize the number of methods users need to call to use your components. A lot of the features you might be inclined to implement as methods are probably better encapsulated into properties. Doing so provides an interface that suits the C++Builder environment, and also lets users access them at design time.


See also

Overview of component creation

OOP for component writers

Creating properties

Creating events

Using graphics in components

Handling messages

Registering components


Avoiding interdependencies

See also

At all times when writing components, minimize the preconditions imposed on the component user. To the greatest extent possible, component users should able to do anything they want to a component, whenever they want to do it. There will be times when you can't accommodate that, but your goal should be to come as close as possible.

Although it's impossible to list all the possible kinds of interdependencies you want to avoid, this list gives you an idea of the kinds of things to avoid:

Methods that the user must call to use the component

Methods that must execute in a particular order

Methods that put the component into a state or mode where certain events or methods could be invalid

The best way to handle these situations is to ensure that you provide ways out of them. For example, if calling a method puts your component into a state where calling another method might be invalid, then write that other method in such a way that if the user calls it when the component is in a bad state, the method corrects that state before executing its main code. At a minimum, you should throw an exception in cases when a user calls a method that is invalid.

In other words, if you create a situation where parts of your code depend on each other, the burden should be on you to be sure that using the code in incorrect ways does not cause the user problems. A warning message, for example, is preferable to crashing if the user doesn't accommodate your interdependencies.


See also

Naming methods

Protecting methods

Making methods virtual

Declaring methods


Naming methods

See also

C++Builder imposes no restrictions on what you name methods or their parameters. There are a few conventions that make methods easier for users of your components, however. Keep in mind that the nature of a component architecture dictates that many different kinds of people might use your components.

If you're accustomed to writing code that only you or a small group of programmers uses, you might not think too much about how you name things. It is a good idea to make your method names clear because people unfamiliar with your code (and even unfamiliar with coding) might have to use your components.

Here are some suggestions for making clear method names:

Make names descriptive.

A name like PasteFromClipboard is much more informative than simply Paste or PFC.

Function names should reflect the nature of what they return.

Although it might be obvious to you as a programmer that a function named X returns the horizontal position of something, a name like GetHorizontalPosition is more universally understandable.

If a function return type is void, the function name should be active.

Use active verbs in your procedure names. For example, ReadFileNames is much more helpful than DoFiles.

As a final consideration, make sure the method really needs to be a method. A good guideline is that method names have verbs in them. If you find that you create a lot of methods that do not have verbs in their names, consider whether those methods ought to be properties.


See also

Avoiding interdependencies

Protecting methods

Making methods virtual

Declaring methods


Protecting methods

See also

All parts of objects, including data members, methods, and properties, can have various levels of protection, as explained in. Choosing the appropriate level of protection for methods is quite straightforward.

As a general rule, methods you write in your components are either public or protected. The exception to that rule is methods that implement properties, which should always be private. Otherwise, you rarely need to make a method private, unless it is truly specific to that particular type of component, to the point that even components derived from it should not have access to it.

Note:

There is generally no reason for declaring a method (other than an event handler) as published. Doing so looks to the end user exactly as if the method were public.

Methods that should be public

Methods that should be protected

Methods that should be private


See also

Avoiding interdependencies

Naming methods

Making methods virtual

Declaring methods


Methods that should be public

See also

Any methods that users of your components need to be able to call must be declared as public. Keep in mind that most method calls occur in event handlers, so methods should avoid unduly tying up system resources or putting Windows in a state where it can't respond to the user.

Note:

Constructors and destructors should always be public.


See also

Methods that should be protected

Methods that should be private


Methods that should be protected

See also

Any methods that are implementation methods for the component should be protected so that users can't call them at the wrong time. If you have methods that a user's code should not call, but the methods are called in descendant objects, declare the methods as protected.

For example, suppose you have a method that relies on having certain data set up for it beforehand. If you make that method public, there's a chance a user will call it before setting up the data. On the other hand, by making it protected, you ensure that the user can't call it directly. You can then set up other, public methods that ensure that data setup occurs before calling the protected method.


See also

Methods that should be public

Methods that should be private


Methods that should be private

See also

Property-implementation methods should always be private. You definitely don't want users calling methods that manipulate the data for a property. They should only access that information by accessing the property itself. You can ensure that by making the property public and its implementation methods private.

If descendant objects need to override the implementation of a method, they can do so, but instead of overriding the implementation methods, they must access the inherited property value through the property itself.


See also

Methods that should be public

Methods that should be protected


Making methods virtual

See also

Virtual methods in C++Builder components are no different from virtual methods in other objects. You make methods virtual when you want different types to be able to execute different code in response to the same method call.

If you create components intended to be used directly by end users, you can probably make all your methods static. On the other hand, if you create components of a more abstract nature, which other component writers will use as the starting point for their own components, consider making the added methods virtual. That way, components derived from your components can override the inherited virtual methods.


See also

Avoiding interdependencies

Naming methods

Protecting methods

Declaring methods


Declaring methods

See also	Example

Declaring a method in a component is no different from declaring any object method.

To declare a new method in a component, you do two things:

Add the declaration to the component's object-type declaration in the unit's header file

Write the code that implements the method in the .CPP file of the unit


Example

The following code shows a component that defines two new methods: one protected method and one public virtual method:

class TSampleComponent : public TControl

{

protected:

    void __fastcall MakeBigger();

public:

    virtual int __fastcall CalculateArea();

};

This is the code in the .CPP file of the unit that implements the methods:

void __fastcall TSampleComponent::MakeBigger()

{

  Height = Height + 5;

  Width = Width + 5;

}

int __fastcall TSampleComponent::CalculateArea()

{

   return Width * Height;

}


See also

Avoiding interdependencies

Naming methods

Protecting methods

Making methods virtual


Using graphics in components

See also

Windows provides a powerful Graphics Device Interface (GDI) for drawing device-independent graphics. Unfortunately, GDI imposes a lot of extra requirements on the programmer, such as managing graphic resources. As a result, you spend a lot of time doing things other than what you really want to do: creating graphics.

C++Builder takes care of all the GDI drudgery for you, allowing you to spend your time doing productive work instead of searching for lost handles or unreleased resources. C++Builder tackles the tedious tasks so you can focus on the productive and creative ones.

Note that, as with any part of the Windows API, you can call GDI functions directly from your C++Builder application if you want to. However, you will probably find that using C++Builder's encapsulation of the graphic functions is a much more productive way to create graphics.

There are several important topics dealing with graphics in C++Builder:

Overview of C++Builder graphics

Using the canvas

Working with pictures

Offscreen bitmaps

Responding to changes


See also

Overview of component creation

OOP for component writers

Creating properties

Creating events

Creating methods

Handling messages

Registering components


Overview of C++Builder graphics

See also	Example

C++Builder encapsulates the Windows GDI at several levels. The most important to you as a component writer is the way components display their images on the screen. When calling GDI functions directly, you need to have a handle to a device context, into which you have selected various drawing tools such as pens and brushes and fonts. After rendering your graphic images, you must then restore the device context to its original state before disposing of it.

Instead of forcing you to deal with graphics at that detailed level, C++Builder provides a simple yet complete interface: your component's Canvas property. The canvas takes care of making sure it has a valid device context, and releases the context when you're not using it. Similarly, the canvas has its own properties representing the current pen, brush, and font.

The canvas manages all those resources for you, so you need not concern yourself with creating, selecting, and releasing things such as pen handles. You just tell the canvas what kind of pen it should use, and it takes care of the rest.

One of the benefits of letting C++Builder manage graphic resources is that it can cache resources for later use, which can greatly speed up repetitive operations. For example, if you have a program that repeatedly creates, uses, and disposes of a particular kind of pen tool, you need to repeat those steps each time you use it. Because C++Builder caches graphic resources, chances are good that a tool you use repeatedly is still in the cache, so instead of having to recreate a tool, C++Builder reuses an existing one.


Example

As an example of how much simpler C++Builder's graphics code can be, here are two samples of code. The first uses standard GDI functions to draw a yellow ellipse outlined in blue on a window in an application written with ObjectWindows. The second uses a canvas to draw the same ellipse in an application written with C++Builder.

void TMyWindow::Paint(TDC& PaintDC, bool erase, TRect& rect)

{

    HPEN PenHandle, OlPenHandle;

    HBRUSH BrushHandle, OldBrushHandle;

    PenHandle = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

    OldPenHandle = SelectObject(PaintDC, PenHandle);

    BrushHandle = CreateSolidBrush(RGB(255, 255, 0));

    OldBrushHandle = SelectObject(PaintDC, BrushHandle);

    Ellipse(10, 10, 50, 50);

    SelectObject(OldBrushHandle);

    DeleteObject(BrushHandle);

    SelectObject(OldPenHandle);

    DeleteObject(PenHandle);

)

void __fastcall TForm1::FormPaint(TObject *Sender)

{

  Canvas->Pen->Color = clBlue;

  Canvas->Brush->Color = clYellow;

  Canvas->Ellipse(10, 20, 50, 50);

}


See also

Using the canvas

Working with pictures

Offscreen bitmaps

Responding to changes


Using the canvas

See also

The canvas object encapsulates Windows graphics at several levels, ranging from high-level functions for drawing individual lines, shapes, and text to intermediate-level properties for manipulating the drawing capabilities of the canvas to low-level access to the Windows GDI.

The following table summarizes the capabilities of the canvas.

Level	Operation	Tools

High	Drawing lines and shapes	Methods such as MoveTo, LineTo, Rectangle, and Ellipse

Displaying and measuring text	TextOut, TextHeight, TextWidth, and TextRect methods

Filling areas	FillRect and FloodFill methods

Intermediate	Customizing text and graphics	Pen, Brush, and Font properties

Manipulating pixels	Pixels property

Copying and merging images	Draw, StretchDraw, BrushCopy, and CopyRect methods; CopyMode property

Low	Calling Windows GDI functions	Handle property


See also

Overview of C++Builder graphics

Working with pictures

Offscreen bitmaps

Responding to changes


Working with pictures

See also

Most of the graphics work you do in C++Builder is limited to drawing directly on the canvases of components and forms. C++Builder also provides for handling standalone graphic images, however, such as bitmaps, metafiles, and icons, including automatic management of palettes.

There are three important aspects to working with pictures in C++Builder:

Picture or graphic or canvas?

Graphics in files

Handling palettes


See also

Overview of C++Builder graphics

Using the canvas

Offscreen bitmaps

Responding to changes


Picture or graphic or canvas?

See also

There are three kinds of objects in C++Builder that deal with graphics:

A canvas, which represents a bitmapped drawing surface on a form, graphic control, printer, or bitmap. A canvas is always a property of something else, never a standalone object.

A graphic, which represents a graphic image of the sort usually found in a file or resource, such as a bitmap, icon, or metafile. C++Builder defines object types TBitmap, TIcon, and TMetafile, all descended from a generic TGraphic. You can also define your own graphic objects. By defining a minimal standard interface for all graphics, TGraphic provides a simple mechanism for applications to use different kinds of graphics easily.

A picture, which is a container for a graphic, meaning it could contain any of the graphic object types. That is, an item of type TPicture can contain a bitmap, an icon, a metafile, or a user-defined graphic type, and an application can access them all in the same way through the picture object. For example, the image control has a property called Picture, of type TPicture, enabling the control to display images from many kinds of graphics.

Keep in mind that a picture object always has a graphic, and a graphic might have a canvas (the only standard graphic that has a canvas is TBitmap). Normally, when dealing with a picture, you work only with the parts of the graphic object exposed through TPicture. If you need access to the specifics of the graphic object itself, you can refer to the picture's Graphic property.


See also

Graphics in files

Handling palettes


Graphics in files

See also	Example

All pictures and graphics in C++Builder can load their images from files and store them back again (or into different files). You can load or store the image of a picture at any time.

To load an image into a picture from a file, call the picture's LoadFromFile method.

To save an image from a picture into a file, call the picture's SaveToFile method.

LoadFromFile and SaveToFile each take the name of a file as the only parameter. LoadFromFile uses the extension of the file name to determine what kind of graphic object it will create and load. SaveToFile saves whatever type of file is appropriate for the type of graphic object being saved.


Example

To load a bitmap into an image control's picture pass the name of a bitmap file to the picture's LoadFromFile method:

void __fastcall TForm1::FormCreate(TObject *Sender)

{

   Image1->Picture->LoadFromFile("c:\\windows\\athena.bmp");

}

The picture recognized .BMP as the standard extension for bitmap files, so it creates its graphic as a TBitmap, then calls that graphic's LoadFromFile method. Because the graphic is a bitmap, it loads the image from the file as a bitmap.


See also

Picture or graphic or canvas?

Handling palettes


Handling palettes

See also

When running on a palette-based device, C++Builder controls automatically support palette realization. That is, if you have a control that has a palette, you can use two methods inherited from TControl to control how Windows accommodates that palette.

Palette support for controls has these two aspects:

Specifying a palette for a control

Responding to palette changes

Most controls have no need for a palette, but controls that contain graphic images (such as the image control) might need to interact with Windows and the screen device driver to ensure the proper appearance of the control. Windows refers to this process as realizing palettes.

Realizing palettes is the process of ensuring that the frontmost window uses its full palette, and that windows in the background use as much of their palettes as possible, then map any other colors to the closest available colors in the "real" palette. As windows move in front of one another, Windows continually realizes the palettes.

Note:

C++Builder itself provides no specific support for creating or maintaining palettes, other than in bitmaps. If you have a palette handle, however, C++Builder controls can manage it for you.


See also

Picture or graphic or canvas?

Graphics in files


Specifying a palette for a control

See also

If you have a palette you want to apply to a control, you can tell your application to use that palette.

To specify a palette for a control, override the control's GetPalette method to return the handle of the palette.

Specifying the palette for a control does these things for your application:

It tells the application that your control's palette needs to be realized.

It designates the palette to use for realization.


See also

Responding to palette changes


Responding to palette changes

See also

If your control specifies a palette by overriding GetPalette, C++Builder automatically takes care of responding to palette messages from Windows. The method that handles the palette messages is PaletteChanged. For normal operation, you should never need to alter the default behavior of PaletteChanged.

The primary role of PaletteChanged is to determine whether to realize the control's palette in the foreground or the background. Windows handles this realization of palettes by making the topmost window have a foreground palette, with other windows resolved in background palettes. C++Builder goes one step farther, in that it also realizes palettes for controls within a window in tab order. The only time you might need to override this default behavior is if you want a control that is not first in tab order to have the foreground palette.


See also

Specifying a palette for a control


Offscreen bitmaps

See also

When drawing complex graphic images, a common technique in Windows programming is to create an offscreen bitmap, draw the image on the bitmap, and then copy the complete image from the bitmap to the final destination onscreen. Using an offscreen image reduces flicker caused by repeated drawing directly to the screen.

The bitmap object in C++Builder to represent bitmapped images in resources and files can also work as an offscreen image.

There are two main aspects to working with offscreen bitmaps:

Creating and managing offscreen bitmaps

Copying bitmapped images


See also

Overview of C++Builder graphics

Using the canvas

Working with pictures

Responding to changes


Creating and managing offscreen bitmaps

See also

When creating complex graphic images, you should generally avoid drawing them directly on a canvas that appears onscreen. Instead of drawing on the canvas for a form or control, you can construct a bitmap object, draw on its canvas, and then copy its completed image to the onscreen canvas. The most common use of an offscreen bitmap is in the Paint method of a graphic control.

For an example of painting a complex image on an offscreen bitmap, see the source code for the Gauge control from the Samples page of the Component palette. The gauge draws its different shapes and text on an offscreen bitmap before copying them to the screen. Source code for the gauge is in the file GAUGES.PAS in the SOURCE\SAMPLES subdirectory.


See also

Copying bitmapped images


Copying bitmapped images

See also

C++Builder provides four different ways to copy images from one canvas to another. Depending on the effect you want to create, you call different methods.

The following table summarizes the image-copying methods in canvas objects.

To create this effect	Call this method

Copy an entire graphic	Draw

Copy and resize a graphic	StretchDraw

Copy part of a canvas	CopyRect

Copy a bitmap with raster operations	BrushCopy


See also

Creating and managing offscreen bitmaps


Responding to changes

See also	Example

All graphic objects, including canvases and their owned objects (pens, brushes, and fonts) have events built into them for responding to changes in the object. By using these events, you can make your components (or the applications that use them) respond to changes by redrawing their images.

Responding to changes in graphic objects is particularly important if you publish those objects as part of the design-time interface of your components. The only way to ensure that the design-time appearance of the component matches the properties set in the Object Inspector is to respond to changes in the objects.

To respond to changes in a graphic object, assign a method to the object's OnChange event.


Example

The shape component publishes properties representing the pen and brush it uses to draw its shape. The component's constructor assigns a method to the OnChange event of each, causing the component to refresh its image if either the pen or brush changes. Here is the code as it is implemented using the Object Pascal language:

type
  TShape = class(TGraphicControl)
  public
    procedure StyleChanged(Sender: TObject);
  end;

...

implementation

...

constructor TShape.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);	{ always call the inherited constructor! }

  Width := 65;

  Height := 65;

  FPen := TPen.Create;	{ construct the pen }

  FPen.OnChange := StyleChanged;	{ assign method to OnChange event }

  FBrush := TBrush.Create;	{ construct the brush }

  FBrush.OnChange := StyleChanged;	{ assign method to OnChange event }
end;

procedure TShape.StyleChanged(Sender: TObject);
begin
  Invalidate();	{ erase and repaint the component }
end;

FPen->OnChange = StyleChanged();

FBrush->OnChange = StyleChanged();


See also

Overview of C++Builder graphics

Using the canvas

Working with pictures

Offscreen bitmaps