Examples Delphi

Title: Custom Containers Pack (CCPACK 5)
Question: Review of this freeware expert that helps you visually build composite components
Answer:
CUSTOM CONTAINERS PACK (CCPACK 5)
What is Custom Containers Pack?
CCPack 5 is a freeware package that allows you to visually combine, extend and inherit VCL containers. The package was developed by Sergey Orlik, Product Manager of Inprise Moscow office (Russia, C.I.S. and Baltic States).
CCPack 5 works with Delphi/C++Builder 5, and is the evolution of two existing Delphi/C++Builder 3,4 add-ins: Custom Forms Pack (CFPack) and Composite Components Pack (CCPack 4).
One of the common uses of CCPack 5 is to create components made of various components:
* CCPack Introduction movie (~337K)
Downloads
* Custom Containers Pack (CCPack 5) for Delphi/C++Builder 5 (~695K)
* CCPack 4.5 for Delphi/C++Builder 3 and 4 (~591K)
* CFPack 4.3 for Delphi/C++Builder 4 (~129K)
* CFPack 1.01 for Delphi/C++Builder 3 (old and non-modified version) (~45K)
Full source code is provided and you can modify it without restriction for any non-commercial projects. Let the author know if you want to use this software in your commercial projects by e-mail to sorlik@inprise.ru stating the tool's name in the subject line.
A sample composite component
After you have installed CCPack, you're ready for the first example.
Close all Delphi projects. In the "File" menu choose "New...", select "Custom Container" (or "Composite Control" in Delphi 3/4) in the "New items" dialog, and click "OK". In the "New Container" dialog select "TFrame", write "TFileComposite" in the "New class name" field and click "Finish".
A form appears. Its surface is the surface of your new Delphi component. Set the following properties in the Object Inspector:
Width = 281
Height = 164
This will be the default size of the component. Drop a Panel onto the form, and set its properties:
Align = alLeft
Width = 130
BevelOuter = bvNone
Caption =
Constraints.MinWidth = 110
Drop a Splitter to the right to the panel. It will align automatically to the side of the panel. Drop a DriveComboBox and a DirectoryListBox on the panel and set their properties:
DriveComboBox:
Left = 0
Top = 0
Width = 130
Height = 19
Anchors = [akLeft, akTop, akRight]
DirectoryListBox:
Left = 0
Top = 19
Width = 130
Height = 145
Anchors = [akLeft, akTop, akRight, akBottom]
Click on the right side of the form, and drop a FileListBox:
Align = alClient
TabOrder = 0
With this we have completed the visual interface of our composite component. Now it's time to add some code to "link" the components. Double click the DriveComboBox and in the Change event handler write:
procedure TFileComposite.DriveComboBox1Change(Sender: TObject);
begin
DirectoryListBox1.Drive := DriveComboBox1.Drive;
end;
Double click the DirectoryListBox and in the Change event handler write:
procedure TFileComposite.DirectoryListBox1Change(Sender: TObject);
begin
FileListBox1.Directory := DirectoryListBox1.Directory;
end;
With this we have completed the basic behavior of our composite component, which for the programming interface will inherit the methods and properties from TFrame (the base class we chose when we created the component). Let's add a couple of public properties: FileName and Directory. In the declaration of the class add:
type
TFileComposite = class(TFrame)
:
:
protected
{ Protected declarations }
function GetFileName: string;
procedure SetFileName(FileName: string);
function GetDirectory: string;
procedure SetDirectory(Directory: string);
public
{ Public declarations }
property FileName: string read GetFileName write SetFileName;
property Directory: string read GetDirectory write SetDirectory;
:
:
The implementation is quite simple. Basically we get and set the FileName of the FileListBox and the Directory property of the DirectoryListBox:
function TFileComposite.GetFileName: string;
begin
Result := FileListBox1.FileName;
end;
procedure TFileComposite.SetFileName(FileName: string);
begin
FileListBox1.FileName := FileName;
end;
function TFileComposite.GetDirectory: string;
begin
Result := DirectoryListBox1.Directory;
end;
procedure TFileComposite.SetDirectory(Directory: string);
begin
DirectoryListBox1.Directory := Directory;
end;
Now let's add three events: Change, Click and DblClick. In the declaration of the class add:
type
TFileComposite = class(TFrame)
:
:
private
{ Private declarations }
FOnChange: TNotifyEvent;
FOnClick: TNotifyEvent;
FOnDblClick: TNotifyEvent;
protected
:
public
:
published
{ Published declarations }
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnClick: TNotifyEvent read FOnClick write FOnClick;
property OnDblClick: TNotifyEvent read FOnDblClick write
FOnDblClick;
end;
As you might be guessing, these events will be triggered by the Change, Click and DblClick events of the FileListBox, so generate the corresponding event handlers and write the following:
procedure TFileComposite.FileListBox1Change(Sender: TObject);
begin
if Assigned(FOnChange) then FOnChange(Self);
end;
procedure TFileComposite.FileListBox1Click(Sender: TObject);
begin
if Assigned(FOnClick) then FOnClick(Self);
end;
procedure TFileComposite.FileListBox1DblClick(Sender: TObject);
begin
if Assigned(FOnDblClick) then FOnDblClick(Self);
end;
If you wonder about the Assigned function, please allow me to explain. FOnChange is a field of type TNotifyEvent, and this means that it can hold the address of a procedure of object that takes a "Sender: TObject" parameter... or it can be Nil, so we should make sure that FOnChange isn't Nil before making the call "FOnChange(Self)". However, the following won't work:
if FOnChange nil then ...
The reason is that referring FOnChange is taken by the compiler as an invocation of the procedure it points to. Since it's a procedure, it doesn't return a value type-compatible with a pointer (so we can't compare it with Nil), but before realizing this, the compiler will find that we forgot the parameter (Sender) in the call to FOnChange... Our intention is not to call the procedure FOnChange points to, but to know whether the value of FOnChange isn't Nil. This is the purpose of the built-in Assigned function used above.
For the purpose of the example, this is it. You can install this unit and then use the component from the Components Palette, or you can include the unit in a test project and create the component by code like we did in the test application to save you from having to install a useless component.
As you can see, with CCPack someone with little experience in component writing can build composite components quickly and easily.
More information
You can find more information about CCPack, and find other components at Sergey Orlik's web site.