Programming in Delphi
Programming in Delphi
Programming in Delphi
Introduction
The Delphi language was formerly known as Object Pascal, and is an object-oriented version of the venerable Pascal language, combined by Borland with a Visual Basic-
like RAD tool that lets you write fast GUI applications with no run-time, a very rich set of components (VCLs) that can be statically compiled into the EXE, and an
encapsulation of most of the Windows API for easier access to the underlying OS. If this reminds you of .Net, it's no chance since both Delphi and the .Net framework
were designed by the same person, Anders Hejlsberg. For more infos, read Delphi history – from Pascal to Diamondback (Delphi 2005) by Zarko Gajic.
As of April 2005, Delphi is available as Delphi 2005, a.k.a. Delphi 9, to write Win32 or .Net applications, but you might be able to still get your hands on Delphi 7 (to write
Win32, and Linux applications by using Kylix and the Qt widgets-based CLX component library instead of the Windows-only VCL widgets), or Delphi 8 (to get you started
writing .Net applications; D7 has a command-line version of the Delphi CLI compiler, but it was really meant as a learning tool.) Note that D8 comes with Delphi 7.1.
Delphi 2005 supports the 1.1 .Net framework.
Setup
If you just want to get started and learn Delphi, the $99 Personal edition of Delphi 7 is all you need is love. If you prefer to start developing for .Net, try Delphi 9, a.k.a.
Delphi 2005. In October 2006, Borland relaunched its Turbo brand, and offers two versions: Explorer, which are free but doesn't allow installing third-party components,
and Professional, which aren't. Turbo Delphi Win32 is Delphi 2006 (a.k.a. Borland Developer Studio) with just the Delphi for Windows32 personality.
FWIW, the main extras offered by the Enterprise version of Delphi 7 are IntraWeb from AToZed (Framework + component set for building web apps in a RAD manner),
Rave Visual Designer (Visual reporting tool), BizSnap (to create web services,) and Model Maker (UML stuff.)
IDE
1. Create shortcut on desktop, with Start In = where you save your projects
2. Install the latest Update and hot-fixes
3. Get rid of news: Tools > Env't Options > Delphi Direct: Uncheck "Automatically poll network".
4. Combine Object TreeView, Object Inspector, Project Manager
5. Remove useless toolbars
6. Hide line numbers and gutter
7. Save desktop
8. Install CnWizards
9. Install GExperts
10. Install memory-related add-on's: FastMM, madExcept ("replaces Delphi's exception handling with a much more intelligent solution"), MemProof ("FREE heap
memory and resource 'leak' debugger for Borland's 32-bit family of compilers")
11. Install third-party components
12. DOESN'T WORK (D2007) Disable Welcome Page (HKEY_CURRENT_USER\Software\Borland\BDS\5.0\Known IDE Packages\Delphi\$(BDS)\Bin\startpageide100.bpl)
13. (D2007) Install DDevExtensions to get TAB/Shift-TAB indenting
14. (D2007) Remove Welcome Page (set HKEY_CURRENT_USER\Software\Borland\BDS\<version #>\Known IDE Packages\Delphi\$(BDS)\Bin\startpageide100.bpl to
empty string)
15. (D2007) Set the default directory to save new projects by editing HKEY_CURRENT_USER\Software\Borland\BDS\5.0\Globals\DefaultProjectsDirectory
To add bookmarks to source code so you can jump to locations, press CTRL-SHIFT, and any number between 0 and 9.
To jump to that location, hit CTRL and the number of the bookmark (doesn't work in D7 with default settings). Or you can use CnWizards, and hit CTRL-SHIFT-B to get a
list of bookmarks.
If you'd rather use the familiar TAB button to indent a whole block, install Two Desk's Castalia add-in to the IDE, or the free CnWizards (a.k.a. CnPack IDE Wizards).
If you are running Delphi Pro and above, check out GExperts or CnWizards. If you are using the Personal or Standard edition, looks like the only way is to use the { and }
syntax, with no menu or keyboard shortcut available.
Some are open-source, some are just freeware, and yet others are commercial:
DevExpress (Bunch of component packs, a bit on the expensive side; includes the free but documentation-free Express ForumLibrary with components such as
dxfOutlookBar, dxfClock, dxfTimer, etc., and the Code Rush IDE)
TMS Software
Raize
LMD Innovative (including LMD-Tools SE, the freeware version of LMD-Tools)
ABF Software (The abfComponents contains about 20 components and is free for non-commercial use, while the ABC VCL contains 60 components and costs $49
($99 with source code))
ProVCL Extensions Library
JEDI VCL (open-source collection of 500 components; documentation needs some polishing...)
RXLib (stalled in 2002, but supposed to now be part of the JVCL; French resources here)
Turbopower (open-sourced in 2003 after the company folded, but projects stalled since then; TurboPower products on SourceForge.net)
Vladimir Gaitanoff's VG VCL Library and VG Library II
TWebBrowser (ActiveX control to access IE's engine?)
Internet: ICS, Indy, Synapse
www.fredshack.com/docs/delphi.html 1/43
31/07/2023, 08:34 Programming in Delphi
Sites to check for Delphi components
(French) Developpez
Torry.net
Delphi @ About.com
Barabash's Sofware
GLOBUS VCL Extensions Library (GVCL)
DelphiPages
DelphiSource
CodeGear > CodeCentral > Delphi > Components
Delphi2007+ lets you add "ReportMemoryLeaksOnShutdown := True;" to a project's DPR file. There are alternatives: Memory Sleuth NuMega, etc.
Delphi in a nutshell
Note: In the Delphi literature, depending on the context, "package" refers to either a DPK master file and PAS/DCU source files, or the resulting, compiled BPL file which
contains all the DCU files.
a bunch of (more or less) independent source files (*.PAS) that you will add to your project and that will be statically compiled into the EXE,
a bunch of compiled unit files (*.DCU) that you add to your project via the Uses section and will be compiled statically into the EXE,
a bunch of source files (referenced by a .DPK master list file, ) to be compiled into a single package file (.BPL),
a bunch of compiled files (.DCU) and a BPK master file that you can use to build a design-time component and add it to the IDE, or as
a package file (.BPL) already compiled for you.
Typically, commercial components are provided as binary files, but some can also be bought with source files.
Individual components (ie. PAS or DCU files) can be added to an existing package, or to a brand new package through either File > Open (select a DPK file, click on Add,
and compile) or Component > Install Component (when adding to an existing package, the default file is DCLUSR.DPK).
A package file has the extension BPL, and is just a Borland-specific version of a DLL with added functions like GetPackageInfoTable(), ie. routines that live in a file
separate from the caller EXE, and that can be loaded dynamically when needed. Use the Bin\TDUMP.EXE command-line Borland utility to display information containted in
a BPL file.
Once installed, packages are listed in the Registry under HKEY_CURRENT_USER\Software\Borland\Delphi\<version>\Known Packages . For Delphi to find components,
they must be located in known directories through the Tools > Environment Options > Library.
Components meant to be used in the IDE can only be installed as a package, ie. a DPK master file along with one or more PAS files to be compiled into DCUs and
aggregated in a single BPL file that will be registered into the IDE.
Note that design-time packages and run-time packages are two different beasts: The former adds itself to a palette in the IDE and provides an interface to access its
properties, routines, and events; The latter is used by applications that were compiled with run-time packages, ie. dynamic linking. Some BPLs are both design-time and
run-time, so I guess they have a switch somewhere in the code that lets me act differently depending on the context.
if the component offers a design-time interface, this requires installing a BPL in the IDE
compiling this component statically requires compiling some DCUs into the EXE; compiling this component for dynamic loading means reading headers and
symbol information from a DCP file, and providing the run-time BPL (which, in the end, is just an aggregation of all the DCUs that make up this component.)
Depending on the "Build with runtime packages" checkbox in Project > Options > Packages, the compiler will either (if disabled) include all the DCU files into the EXE, or
(if enabled) use an external BPL file, that you'll have to distribute in addition to the EXE. In other words, this is where you decide whether to link third-party components
statically into the EXE, or dynamically by loading BPLs at run-time.
If the packages don't change often, it might be a good idea to use dynamic linking, so that you only need to distribute the EXE for updates. On the other hand, dynamic
run-time packages contain all the routines, even those that your EXE doesn't use, while, when using statically-linked packages, the IDE will only include stuff that your
EXE actually use. In the end, a statically-linked EXE can turn out to be smaller that a bare EXE and external BPLs.
Finally, if resource files are used (RES or DCR), Delphi will need those to compile a package successfully. Bitmaps for the components that will appear in the palette are
saved in the DCR files.
The source files, either source (.PAS) or compiled (.DCU) aren't needed to use a component; They are only needed if you want to compile the component yourself.
Important: As DCUs are version-dependent, a package can only be installed in the same version of the IDE that was used to compile it. That's the reason why some
components are distributed as source code that you must compile yourself into a package before adding it to the IDE. The alternative for commercial components is to
generate multiple versions of the package, one for each version of the IDE that they wish to support.
Moving a design package to another host requires copying the following files: BPL, DCP, possibly DCR resources files, hitting the Component > Install Packages menu,
and clicking on Add.
www.fredshack.com/docs/delphi.html 2/43
31/07/2023, 08:34 Programming in Delphi
In addition to individual packages, it is possible to create a package collection (DPC) to make it easier to distribute the different files that make up a package. A DPC will
contain DCP, DCU, and BPL files. This type of file requires a Package Collection Editor (PCE), which is a source file used to define a DPC file. A DPC file is created through
Tools > Package Collection Editor.
More information:
Questions
If the independent DCUs and the ones aggregated in a run-time BPL are identical, why don't commercial components just come as a bunch of DCUs that
developers who want to use dynamic linking will compile themselves into a BPL?
When using a design-time package, I am provided with a BPL that will be added to the palette. In addition, DCU files are required to allow for static linking. On
the other hand, when using a run-time package, the package designer must provide a DCP since it is required to let the compiler know how to link to the BPL file
for dynamic loading. Correct?
When creating a package that is both a design- and run-time package, are there two different BPL files, or is there some kind of switch in the file that lets the
compiler use the same file in two different contexts? From reading DsgnIntf.dcu not found, it seems that for a while, Borland didn't force component developers to
write two versions, one for the IDE and one as a run-time package. Or are design-time BPLs and run-time BPLs two totally different beasts?
How can I tell if a BPL is design-time or run-time? Because the IDE will complain if I try to a run-time package to the list of design-time packages?
DCU Delphi Compiled Unit Compiled version of .PAS files; Similar to .OBJ file in C
DFM Delphi Form Describes a form, and what it contains
DPR Delphi Project EXE project master file
Used for EXEs built with run-time BPLs to let the compiler know how to link to
DCP Delphi Compiled Package the BPL at run-time; Doesn't include compiled code, which is stored in DCU or
BPL files
BPL Borland Package Library Delphi-specific DLL, ie library loaded at run-time
Project master file when developing a package; equivalent to .DPR for EXE
DPK Delphi Package ???
projects
DPC Delphi Package Collection ?
DPKW Like DPK
BPG Borland Project Group Used to keep track of projects when opening more than one project in the IDE
BPK ? ?
BPI ? ?
CFG Compiler Configuration Compiler settings; Similar to DOF
DOF Delphi Options File? Project options
Menus of interest
New and Open: To create blank files or projects, start from templates (regular windows, dialogs, MDI/SDI, etc.), or open existing files and projects, including
packages (to install components)
View: Project Manager (to list all the units that make up a project), Object Inspector (to view parameters of a unit), Object Tree View (To list widgets contained in
a form), Desktops (to save, and apply a desktop definition, so that windows are displayed in a way you like), Toggle Form Unit (also accessible through F12)
Project : to manage files and projects, import a type library for COM objects, add stuff to the source control, compile and/or run a project
www.fredshack.com/docs/delphi.html 3/43
31/07/2023, 08:34 Programming in Delphi
Components: To create or install components (.PAS files), and install packages. Install Component: Into existing package (Unit file name .PAS or .DCU + Package
file name = dclusr.dpk) or Into new package
Getting started
A typical Delphi GUI program is a set of units (*.PAS) which contain source code, and are listed in a project (.DPR file), while the forms (windows) are described in files
with the DFM extension, ie. DPR = PAS + DFM.
//Name of the unit, which can then be referenced in other source files (a unit name must be unique within a project)
unit Unit1;
//List of public stuff, eg. variables that can be accessed from other source files
interface
uses { List of units goes here }
{ Interface section goes here }
//Actual code of this source file
implementation
uses { List of units goes here }
{ Implementation section goes here }
initialization
{ Initialization section goes here }
finalization
{ Finalization section goes here }
//A source file must end with "end."
end.
Open your favorite editor, save the file as console.pas, and copy/paste the following code:
program Console;
{$APPTYPE CONSOLE}
var MyMessage: string;
begin
MyMessage := 'Hello world!';
Writeln(MyMessage);
end.
Open a DOS box, compile the program with "dcc32.exe console", and run the compiled as with "console.exe".
In the empty form that shows up when starting Delphi, add a label and a pushbutton, double-click on the button, and add the following code to the Button1Click()
routine:
Hit F9 to run the application, and click on the pushbutton to see the text of the label change.
With D7 at least, Delphi's MessageDlg doesn't let you select a default button, which is unfortunate for critical choices. You'll have to use Win32's MessageBox() instead:
Dynamic objects
When you add a control on a form at design-time, Delphi takes care of creating and freeing the object, but those tasks are your responsibility when creating objects
dynamically, at run-time.
The important point is freeing the object from memory, or your application will leak memory.
www.fredshack.com/docs/delphi.html 4/43
31/07/2023, 08:34 Programming in Delphi
There are three ways to handle this:
Declare a variable, call the class' Create() method, and end with Free(), preferably in a try/finally structure:
var
MyObj : TObj;
begin
with TObj.Create(nil) do
try
//Do stuff
finally
Free;
end;
A second way is to use the With structure, and set the instance's owner as a form, so that, even if you forgot to call Free, Delphi will free the object from memory when
it kills the parent form (Actually, you should NOT call Free, and let the owner free the instance from memory):
var
MyObj : TObj;
begin
with TObj.Create(Self) do begin
//Do stuff
end;
Note that the time to dynamically create components with owners is much slower than that to create components without owners.
A third way is to use the With structure with Nil as the parent, but in this case, Free() must be called explicitely:
with TObj.Create(nil) do
try
//Do stuff
finally
Free;
end;
end;
Since D2006, Delphi includes a way to check for memory leaks in the IDE once the application has terminated. To enable this, just add the following line in the Project's
DPR file (via Project > View Source):
begin
ReportMemoryLeaksOnShutdown :=true;
Application.Initialize;
A faster way:
www.fredshack.com/docs/delphi.html 5/43
31/07/2023, 08:34 Programming in Delphi
function LoadFile(const FileName: TFileName): string;
begin
with TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite) do begin
try
SetLength(Result, Size);
Read(Pointer(Result)^, Size);
except
Result := ''; // Deallocates memory
Free;
raise;
end;
Free;
end;
end;
FileContents := LoadFile('rss.xml');
ExtractFileDir() in a DataModule?
Application is declared in the forms unit. As an alternative you can change "Application.ExeName" to "ParamStr(0)".
Here's how to read each line of a tab-delimited text file, and save this into an SQLite database:
var
myFile : TextFile;
letter : char;
text : string;
begin
AssignFile(myFile, 'Test.txt');
ReWrite(myFile);
WriteLn(myFile, 'Hello, world!');
CloseFile(myFile);
end;
Alternatively:
www.fredshack.com/docs/delphi.html 6/43
31/07/2023, 08:34 Programming in Delphi
Free;
end;
end;
Here's how to set the cursor back to the beginning of a text file, ie. not a binary file that uses records:
var
dummy : TextFile;
begin
AssignFile(dummy, 'dummy.txt');
ReWrite(dummy);
WriteLn(dummy, '123');
ReWrite(dummy);
WriteLn(dummy, '345');
CloseFile(dummy);
var
test : TFileStream;
status : String;
begin
status := 'test';
test := TFileStream.Create('test.txt',fmCreate);
test.Write(Pointer(status)^,Length(status));
test.Seek(0, soFromBeginning);
test.Free;
At design-time, the best way to add radio buttons to a form is by first adding a radiogroup object, and modify its Items property to add radio buttons.
ShowMessage(Radiogroup1.Items.Strings[RadioGroup1.ItemIndex]);
RadioGroup1.ItemIndex:=-1;
In addition to indexes, a TStringList array can use names so as to build name=value items. Here are some examples:
var
indexclassifications : TStringList;
i : Integer;
begin
indexclassifications := TStringList.Create;
indexclassifications.Add('unix=good');
indexclassifications[0] := 'windows=bad';
for i := 0 to indexclassifications.Count-1 do begin
ShowMessage(indexclassifications[i]);
ShowMessage(indexclassifications.Names[i]);
ShowMessage(indexclassifications.ValueFromIndex[i]);
ShowMessage(indexclassifications.Values[indexclassifications.Names[i]]);
end;
indexclassifications.Free;
www.fredshack.com/docs/delphi.html 7/43
31/07/2023, 08:34 Programming in Delphi
An alternative is Ciaran McCreesh's Hash Library.
Adding items
ListBox1.Items.Add('Hello');
ListBox1.Items.Insert(3,'Hello');
Selecting a directory
Here's how to display a dialog box so the user can choose a directory:
Closing an application
Two possibilites, using either Sys.Close() or Application.Terminate(), but the latter doesn't trigger the onClose or onCloseQuer events:
//If app already ran, make the button Close the app
If (Button1.Caption = 'Close') then begin
Close;
Exit;
end;
PINGing a server
www.fredshack.com/docs/delphi.html 8/43
31/07/2023, 08:34 Programming in Delphi
end;
procedure TForm1.Ping1EchoReply(Sender, Icmp: TObject; Status: Integer);
begin
if Status <> 0 then
{ Success }
Label1.Caption := 'Server ' + Ping1.HostIP + ' alive @ ' + TimeToStr(Time)
else
{ Failure }
Label1.Caption := 'Server ' + Ping1.HostIP + ' dead @ ' + TimeToStr(Time) +
#13#10 + Ping1.ErrorString + '. Status = ' + IntToStr(Ping1.Reply.Status);
end;
Here's how to do it using Indy 9 (? The one that ships with Delphi 7):
ShowMessage(MyObj.ClassName);
Casting an object
var
StartTime,StopTime : TDateTime;
begin
StartTime := Now;
ListBox1.Items.Add (TimeToStr (StartTime));
[...]
StopTime := Now;
ListBox1.Items.Add('After doing stuff ' + FormatDateTime ('hh:nn:ss', StopTime - StartTime));
More information:
TreeView1.LoadFromFile('myTABBEDfile.txt');
www.fredshack.com/docs/delphi.html 9/43
31/07/2023, 08:34 Programming in Delphi
(stolen from D7's help file)
Arrays
Delphi supports static and dynamic arrays. To make things a bit confusing, it uses the same syntax "array of" to declare dynamic arrays, and so-called "open arrays", ie.
arrays (either static or dynamic) passed as parameters to a routine.
Dynamic arrays are really a one-dimensional array that holds pointers to other arrays, and each cell can point to arrays of different dimensions:
As a result, Delphi cannot provide VisualBasic's UBound(MyArray,x) where x is either 1, 2, or 3, and High(MyArray) returns the upper bound of the array. If one of the
cells in the array uses a different dimension from the other cells, you'll have to call High(MyArray[thiscell]) to get is upper bound.
Here's an example:
type
TDigits = array of array of Integer;
procedure MyFunc(A: TDigits);
begin
//4
ShowMessage(IntToStr(High(A)));
//9
ShowMessage(IntToStr(High(A[0])));
//6
ShowMessage(IntToStr(High(A[2])));
end;
[...]
var
MyArray : TDigits;
begin
SetLength(MyArray,5,10); //5 rows, 10 columns each
SetLength(MyArray[2],7); //We can use a different dimension for one cell
MyFunc(MyArray);
www.fredshack.com/docs/delphi.html 10/43
31/07/2023, 08:34 Programming in Delphi
end;
Static arrays:
Dynamic arrays:
To deallocate a dynamic array, assign nil to a variable that references the array or pass the variable to Finalize; either of these methods disposes of the array, provided
there are no other references to it. Dynamic arrays are automatically released when their reference-count drops to zero."
"If X and Y are variables of the same dynamic-array type, X := Y points X to the same array as Y.
Unlike strings and static arrays, COPY-ON-WRITE is not employed for dynamic arrays, so they are not automatically copied before they are written to. In contrast, to
make an independent copy of a dynamic array, you must use the global Copy function."
"In some (???) function and procedure declarations, array parameters are represented as array of baseType, without any index types specified. For example,
This indicates that the function operates on all arrays of the specified base type, regardless of their size, how they are indexed, or whether they are allocated statically or
dynamically. See Open array parameters."
If you need to pass an array to a routine, you cannot set its size directly, ie.
...or use open arrays. Open array parameters allow arrays of different sizes to be passed to the same procedure or function:
To read:
Open array parameters and array of const ("Usually, you can pass open arrays as const parameters. Open array parameters that are not passed as const will
entirely be copied into local storage of the routine. The array is simply passed by reference, but if it is not declared const, the hidden start code of the routine will
allocate room on the stack and copy the entire array to that local storage, using the reference as source address. For large arrays, this can be very inefficient. So
if you don't need to modify items in the array locally, make the open array parameter const.")
Delphi Basics - Arrays
Understanding and Using Array data types in Delphi
var
myhash : TStringList;
Index : Integer;
begin
myhash := TStringList.Create;
myhash.Add('mykey=myvalue');
myhash.Add('mykey2=myvalue2');
ShowMessage(myhash.Values['mykey']);
for Index := 0 to myhash.Count-1 do begin
ListBox1.Items.Add(myhash.Names[Index] + '=' + myhash.ValueFromIndex[Index]);
end;
www.fredshack.com/docs/delphi.html 11/43
31/07/2023, 08:34 Programming in Delphi
myhash.Free;
end;
Alternative:
"https://svn.openxp.de/openxp/trunk/xplib/hashes.pas
Usage of it is really simple! Just add 'hashes' (filename of .pas file) to uses clause and then somewhere in code write:
var
hash : TStringHash;
begin
hash := TStringHash.Create;
try
hash['one'] := 'viens';
hash['two'] := 'divi';
ShowMessage(hash['one']);
ShowMessage(hash['two']);
finally
hash.Free;
end;
"
BDE
Note: IBX's IBTable, IBQuery/IBUpdateSQL, and IBStoredProc are intended for compatibility with older BDE components. For new applications, you should generally use
the IBDataSet component, which allows you to work with a live result set obtained by executing a select query. It basically merges IBQuery with IBUpdateSQL in a single
component.
Using an IBQuery that hosts the SQL select statement together with an IBUpdateSQL component that hosts the insert, update, and delete SQL statements is a typical
approach from BDE applications.
ClientDataSet/MyBase (requires the entire table to be loaded in memory to access even a single record)
Multi-tier with DataSnap (formerly known as Middle-tier Distributed Application Services, or MIDAS)
BlackFish SQL
Transactions
Query/Table: Dynamic (created by component) vs. persistent (createad a designtime through Fields editor) fields
Regular SQL vs. parametric queries: When you need slightly different versions of the same SQL query, instead of modifying the text of the query itself each time, you can
write a query with a parameter and change the value of the parameter, eg. "select * from employee where job_country = :country".
Notice that all the data-aware components are unrelated to the data-access technology, provided the data-access component inherits from TDataSet.
DBLookupListBox or DBLookupComboBox. The DBLookupComboBox component can be connected to two data sources at the same time: one source containing the data
and a second containing the display data.
Datasets: You can modify data in the active buffer only after you explicitly declare you want to do so, by giving the Edit command to the dataset. You can also use the
Insert command to create a new blank record and close both operations (insert or edit) by giving a Post command.
To access data from the active record, use the dataset' Field components, which are by default automatically created when a dataset component is created. These field
components are stored in the dataset's Fields array property. You can access these values by number (accessing the array directly) or by name (using the FieldByName
method). Each field can be used to read or modify the current record's data by using its Value property or type-specific properties such as AsDate, AsString, AsInteger,
and so on.
Note: When you set field properties related to data input or output, the changes apply to every record in the table. When you set properties related to the value of the
field, however, you always refer to the current record only.
www.fredshack.com/docs/delphi.html 12/43
31/07/2023, 08:34 Programming in Delphi
Creating the field components each time a dataset is opened is only a default behavior. As an alternative, you can create the field components at design time, using the
Fields Editor.
The VCL includes a number of field class types. Delphi automatically uses one of them depending on the data definition in the database, when you open a table at run
time or when you use the Fields Editor at design time.
Add field (from database) vs. New field (created manually in dataset): Note that fields that are created at design-time with the Fields Editor are the only ones that will be
available at run time (Fields, FieldByName). When a program opens a table at run time, if there are no design-time field components, Delphi creates field objects
corresponding to the table definition. If there are some design-time fields, however, Delphi uses those fields without adding any extra field objects.
A TField component has both a Name property and a FieldName property. The Name property is the usual component name. The FieldName property is either the name
of the column in the database table or the name you define for the calculated field.
Tip: You can also drag the fields from the editor to the form to let the IDE create visual components for you. This is a handy feature that can save you a lot of time when
you're creating database-related forms.
When you operate on a dataset in Delphi, you can work in different states. These states are indicated by a specific State property, which can assume several different
values.
Master/detail
Transactions
Error handling: if ComboName.Text = '' then raise Exception.Create ('Insert the name');
Datamodule
There are two ways to refer to a record in a dataset: Use a TBookmark/TBookmarkStr to save a reference to the current record, or use the Locate method to find a
record that matches given criteria.
To navigate through a dataset, you can use First/while not EOF/Next. Remember to use DisableControls/EnableControls to speed things up when going through a lot of
records. An even better method is to let the SQL server do most of the work.
To make changes to each record, use a "while not EOF" loop that contains a call to dataset.Edit, mycolumn.Value=, dataset.Next (Next means that the change will be
posted).
When is UpdateSQL required? Typically, TQuery and like query components only allow you to specify a Select statement and it then figures out from that how to build
insert, update, and delete statements. But this ability is fairly limited, it does not take much to write a Select statement that it cannot deal with (joins, sub-selects,
unions, etc). In this case, the TQuery is read-only. Corresponding TUpdateSQL components allow you to specify the insert, update, and delete statements corresponding
to such selects.
Dataset.Edit/Post
Other stuff
http://delphi.about.com/od/usedbvcl/a/tdbgrid.htm
http://dn.codegear.com/article/20564
http://forums.delphi-php.net/archive/index.php?t-598.html
http://www.yunqa.de/delphi/doku.php/wiki/sqlite3/sqlite3_get_table
http://www.bergsoft.net/forum/index.php?showtopic=1903&st=0&gopid=9014&
http://bsdn.bergsoft.net/index.php?section=articles&page=qstart
Just like Microsoft development tools, for historical and technical reasons, Delphi provides different ways to connect to a database. You should choose a solution
depending on how big the database is, and whether you have the luxury of choosing a specific database engine or the application must be database-agnostic:
Direct, database-specific connectors (Interbase Express/IBExpress/IBX for Interbase, or FIBPlus/UIB/IBObject for Firebird, MySQL, SQLite, etc.)
BDE (deprecated)
dbExpress (ex-DataSnap Direct), which connects to a DB-specific driver; Lighter, faster than BDE
goDB (ex-ADOExpress)
DataSnap (ex-MIDAS) for n-tier access, or MyBase (ex-Briefcase) for local, XML-based, non-SQL access. Both are based on TClientDataset
Overview
Basically, if you need DB-agnostic solutions, use either ADO or dbExpress. If you don't mind being tied to a given DB engine, use DB-specific solutions like connectors to
SQLite, MySQL, FireBird, etc.
BDE
Historically, the first means offered by Delphi to connect to a database was the IDAPI(Independent Database Application Programming Interface). As it never acquired
the popularity of Microsoft's ODBC, it was turned into BDE (Borland Database Engine).
The BDE uses a collection of DLL's, each one specific to the database that the application wants to connect while presenting a common API to the application:
Data (local or remote) < Database engine (BDE, etc.) < Dataset < Datasource < DB* visual components
Until 1997, BDE was the only way for Delphi applications to connect to database, but it fell in favor because it's a bit heavy to deploy, and doesn't offer good performance
over remote connections
The BDE has a long and glorious history. It originated in Delphi 1 as an engine for accessing Paradox databases and was later part of the ISAPI initiative involving
IBM, Novell, and WordPerfect. Despite a few problems, the BDE is one of the reasons for Delphi's success in the database arena and, having reached version 5, it
is a mature technology.
So why move away from the BDE? Deploying it on rented Internet servers is often impossible because of ISPs' concerns about running system-level services on
their servers. Although the BDE has been updated to support features like the Oracle 8 object-relational model, some of its features are still bound to its Paradox
roots. Another problem is that the BDE includes the entire engine used by Paradox and dBase to access data. There is no way to deploy a thin version of the BDE
excluding Paradox support if you are targeting only SQL servers. (On the other hand some of these problems, such as running SQL Server on an ISP's server,
apply to using ADO as well.)
The BDE also does local caching but won't allow you to interact with it. However, a few Delphi programmers have learned to use the ClientDataSet component to
operate on cached data.
Despite being freely distributed with Borland’s popular line of application development tools, the BDE was unpopular because of complexities in installation and
poor performance. As Delphi became one of the leading application development tools for the Windows platform, individuals and companies proposed alternative
interfaces to the BDE. These “BDE Alternatives” optimized access to the database by directly using the native database driver, providing performance and feature
advantages with respect to the BDE.
The common denominator for database access in Delphi is no longer the BDE. Instead, it's the TDataset class.
TTables = Delphi's desktop database components; Inefficient in a client/server environment.
The reason there is both a TTable and a TQuery component is due to the fact there table-oriented databases like Dbase, Paradox, or Access, and there are set-
oriented databases like Interbase, Oracle, and MSSQL.
Delphi's database architecture has not changed significantly since Delphi 3 introduced the abstract TDataSet class to make custom datasets fully integrated with
the dataset/data-aware architecture, that up to Delphi 2 was tied only to the BDE datasets.
From D3 onwards all BDE functions were removed from TDataset making it independant of any DB format.
What TDataset isn't - TDataset has no:
SQL support
DB session control functions
inherent links to any DB
No index support
No range setting
No master-detail linking
(From D2007 PDF) "TUpdateSQL Lets you use cached updates support with read-only datasets.
Connecting to another dataset. Client datasets can work with data provided by another dataset. A TDataSetProvider component serves as an intermediary between the
client dataset and its source dataset. This dataset provider can reside in the same data module as the client dataset, or it can be part of an application server running on
another machine. If the provider is part of an application server, you also need a special descendant of TCustomConnection to represent the connection to the application
server.
Client datasets provide the most robust way to work with cached updates. By default, other types of datasets post edits directly to the database server. You can reduce
network traffic by using a dataset that caches updates locally and applies them all later in a single transaction. For information on the advantages of using client datasets
to cache updates, see Using a client dataset to cache updates
Client datasets can apply edits directly to a database server when the dataset is read-only. When using dbExpress, this is the only way to edit the data in the dataset (it is
also the only way to navigate freely in the data when using dbExpress). Even when not using dbExpress, the results of some queries and all stored procedures are read-
only. Using a client dataset provides a standard way to make such data editable.
In addition to these specialized client datasets, there is a generic client dataset (TClientDataSet), which does not include an internal dataset and dataset provider.
Although TClientDataSet has no built-in database access mechanism, you can connect it to another, external, dataset from which it fetches data and to which it sends
updates.
Typically, an application checks the dataset state to determine when to perform certain tasks. For example, you might check for the dsEdit or dsInsert state to ascertain
whether you need to post updates.
dbGO/ADO Express
www.fredshack.com/docs/delphi.html 14/43
31/07/2023, 08:34 Programming in Delphi
If you don't mind depending on Microsof's MDAC layer, you can use the ADO page of components
ActiveX Data Objects (ADO) is part of Microsoft's Universal Data Access initiative. It provides a simplified framework for data access based on OLE DB, the real
power horse behind the scene. Programming directly for the OLE DB layer is complicated so Microsoft has provided a simpler solution.
In providing the ADOExpress technology in Delphi, Borland has accepted ADO as a common technology and has also acknowledged Microsoft's Access as a
widespread database engine. Just as the BDE includes some Paradox-related features, ADO includes several features which are more Access-oriented than a
universal data access solution should provide.
dbExpress/DBX/DataSnap Direct
Otherwise, you can use dbExpress, which offers very good performance because it's unidirectional. This means that you'll need to use a ClientDataSet component
(located in the Data Access page) to navigate through a cache and be able to use DB* visual components. Components in the Data Access page can be used with any
data access solution, and include TClientDataset, which can work with data stored on disk or, using the TDataSetProvider component also on this page, with
components from one of the other groups.
Note that in recent version of Delphi, dbExpress' TSQLClientDataset was replaced by TSimpleDataset, which is meant for two-tier architectures. TSimpleDataSet is really
the combination of TDataSetProvider + TClientDataSet. To update the SQL database, use the ClientDataSet's ApplyUpdates(), that you can call in the DB-control's
AfterPost event.
Database > dbExpress driver > TSQLConnection > TSQLDataSet > TSQLDataSetProvider > TClientDataSet > TDataSource > DB* visual components
Realizing the limitations of the BDE, Borland proposed a new type of database interface called dbExpress. This interface was designed to broker access between
Delphi and virtually any relational database through 3rd party drivers. Borland significantly improved the performance of dbExpress with respect to the BDE, but
the implementation was buggy and supported only a limited subset of SQL that hampered functionality.
dbExpress - a.k.a. DataSnap Direct - is Borland's new cross-platform data access layer. Does dbExpress allow access to file based databases such as DBase,
Paradox and FoxPro? No. It currently works with DB2, Interbase, MySQL and Oracle.
Unlike the BDE, dbExpress returns only unidirectional cursors and therefore does no caching. The MIDAS ClientDataset can be used for caching, and scrolling,
indexing, and filtering on the result set.
In 2000, Borland introduced a new SQL driver architecture called "dbExpress." dbExpress is designed to deliver ultra high performance data access and simplify
deployment and configuration of SQL drivers. dbExpress is a pure SQL driver architecture and does not use BDE technology. This new driver architecture replaces
the SQL data access functionality of the "older" BDE SQL Links combination, but does so without the runtime and deployment overhead of the BDE. Developers
have the option of using either InterBase Express (IBX) or dbExpress to access local InterBase tables.
DataSet
ClientDataSet/MyBase
"The ClientDataSet component ships with the Client/Server and Enterprise editions of Delphi and C++ Builder. This component, which can be used in place of other
DataSet components, permits for the reading and writing of single user flat files. The ClientDataSet component relies on a 150K DLL named DBCLIENT.DLL, but does not
make use of the BDE."
Database-specific solutions
If you have the choice of database and don't mind making your application database-specific, you can use some library that connects to the database directly (MySQL,
SQLite, Interbase Express/IBExpress/IBX or FIBPlus/UIB/IBObject for Firebird, etc.)
If you're accessing Microsoft SQL Server or Access databases, you'll probably prefer to use ADO. If you're using Paradox or InterBase, then the BDE is probably
still the best bet -- unless you've boarded the InterBase Express.
Generic client-to-database layers like the BDE, ODBC, dbExpress and ADO hide most of the capabilities of transactional database engines, flattening connectivity
to a generic "lowest common denominator".
Powerful server databases like InterBase/Firebird and Oracle are made to conform to the behaviors of desktop databases like Paradox or dBase. It takes heavy
layering of client and middleware driver code between the user and the database to accomplish this flattening, while disabling essential capabilities of the server
databases' engines. Since everything in InterBase/Firebird happens inside transactions, this approach essentially kills most of the benefits of using client/server for
networking mission-critical applications. IBO cuts right through all this and connects its data access objects directly to the application programming interface (API)
of the InterBase/Firebird engine. From the start IBO freed itself from the restrictions of TDataset and its limiting, local database oriented memory model.
One of IBO's significant benefits is that its native data access architecture is built from TComponent up. This means you you can harness the full power of IBO
without the TDataset architecture that Borland provides. What this means in terms of software investment is that you can use IBO with the standard version of
Delphi - VERY cheap compared to the Professional and Enterprise versions.
The ZeosLib is a set of database components for MySQL, PostgreSQL, Interbase, Firebird, MS SQL, Sybase, Oracle and SQLite for Delphi, FreePascal/Lazarus, Kylix
and C++ Builder."
MyBase
And if you only need a local database (ie. no connection over the network), and the amount of data is small, check out MyBase (ex-MIDAS). It only required midas.dll,
and a ClientDataSet to handle data in RAM
MIDAS/DataSnap
"With MIDAS (Multi-Tier Distributed Application Services), your VCL-based client application receives data over a TCP/IP connection or through the use of sockets. The
data is provided by an application server, which you also write using Delphi. While the application server does make use of the BDE, the client application does not. Client
www.fredshack.com/docs/delphi.html 15/43
31/07/2023, 08:34 Programming in Delphi
applications created using MIDAS are often referred to as thin clients, since they require less configuration and fewer files (specifically, no BDE)."
"MIDAS (DataSnap) is needed with DbExpress, at least if you want to present data in a GUI. MIIDAS is optional with IBX and not really needed with the ADO
components. Think of DbExpress + MIDAS as the "new" BDE."
1. You build the UI with DB-aware components like DBGrid or DBNavigator that share a common datasource
2. The datasource is a conduit to...
3. a dataset, which contains a set of records from a database, read from either a single table or multiple tables through a SQL SELECT:
A BDE dataset uses TTable, TQuery, TStoredProc
An ADO dataset uses TADODataSet, TADOTable, TADOQuery, or TADOStoredProc
A dbExpress dataset uses TSQLDataSet, TSQLTable, TSQLQuery, or TSQLStoredProc
An Interbase dataset uses TIBDataSet, TIBTable, TIBQuery, or TIBStoredProc
Specialized client datasets such as TBDEClientDataSet, TSimpleDataSet, or TIBClientDataSet are also available
4. Each type of dataset uses a different connection component to actually access the DB engine:
A BDE dataset uses the TDataBase object
An ADO dataset uses TADOConnection
An Interbase dataset uses TIBDatabase
A dbExpress dataset use TSQLConnection. As explained above, since dbExpress datasets are always read-only and unidirectional, you can only navigate by
iterating through the records in order, and you can't use the dataset methods that support editing. Also, unidirectional datasets can only supply a single
record at a time
Specialized datasets require an appropriate type of connection
5. Finally, the connection component connects to the actual database, either file- or server-based.
Database components are globally available within your application. In other words, so long as your Database component appears on an auto-created form, or appears
on the main form, it is available to all forms and data modules in the application, without the need for a corresponding uses clause statement.
What is TDataset?
A virtual dataset for accessing a database. Encapsulates the mechanisms for linking a DB to data-aware controls and sending data To/From the DB.
Conceptually data is handled in table form - each row required is buffered internally. Columns are represtented using Fields.
A dataset is the fundamental unit for accessing data is the dataset family of objects. Your application uses datasets for all database access. A dataset
object represents a set of records from a database organized into a logical table. These records may be the records from a single database table, or they
may represent the results of executing a query or stored procedure.
The state - or mode - of a dataset determines what can be done to its data. At runtime, you can examine a dataset's read-only State property to
determine its current state.
To read or write data in a dataset, an application must first open it. You can open a dataset in two ways: Either set the Active property of the dataset to
True, at design time in the Object Inspector or in code at runtime (CustTable.Active := True;), or call the Open method for the dataset at runtime
(CustQuery.Open;).
Since DataSource components are used primarily for managing the interaction between data controls and DataSets, you rarely need to use a DataSource for data access
that is entirely programmatic. In other words, if you have no user interface, you probably do not need a DataSource.
The simplest form of database doesn't use a database engine, and saves data in a file instead through the MyBase (ex-MIDAS) so that client datasets can save and read
themselves to/from a disk; In this case, use the dataset's SaveToFile() and LoadFromFile() methods, or set the FileName property to make it easier.
Table type datasets represent a single table from the database server. Table type datasets include TTable, TADOTable, TSQLTable, and TIBTable
Query-type datasets represent a single SQL command, or query. Query-type datasets include TQuery, TADOQuery, TSQLQuery, and TIBQuery
Stored procedure-type datasets represent a stored procedure on the database server. Stored procedure-type datasets include TStoredProc, TADOStoredProc,
TSQLStoredProc, and TIBStoredProc
In addition, TDataSet has some descendants that fit into more than one category:
TADODataSet and TSQLDataSet have a CommandType property that lets you specify whether they represent a table, query, or stored procedure
TClientDataSet represents the data from another dataset. As such, it can represent a table, query, or stored procedure. TClientDataSet behaves most like a table
type dataset, but it also has some of the features of queries and stored procedures: the management of parameters and the ability to execute without retrieving a
result set
Some other client datasets (like TBDEClientDataSet) have a CommandType property that lets you specify whether they represent a table, query, or stored
procedure. Property and method names are like TClientDataSet, including parameter support, indexes, and the ability to execute without retrieving a result set.
TIBDataSet can represent both queries and stored procedures. In fact, it can represent multiple queries and stored procedures simultaneously, with separate
properties for each.
The ClientDataSet component, which can be used in place of other DataSet components, permits for the reading and writing of single user flat files. The ClientDataSet
component relies on a 150K DLL named DBCLIENT.DLL, but does not make use of the BDE.
It is possible to use a specialized client dataset to connect to a dataset; This type of specialized client datasets is a composite component that includes another dataset
internally to access the data and an internal provider component to package the data from the source dataset and to apply updates back to the database server. You
might want to use a two-part dataset for the following reasons: A client dataset can work reliably with a cache instead of applying changes directly to the database; You
can improve performance by running a client dataset on a client PC and a dataset on a server; datasets like dbExpress' are read-only; TClientDataSet can link to any
source dataset, even those that don't provide a specialized client dataset.
A single connection component can be shared by multiple datasets, or each dataset can use its own connection. Each type of dataset connects to the database server
using its own, TCustomConnection-derived type of connection component, which is designed to work with a single data access mechanism:
www.fredshack.com/docs/delphi.html 16/43
31/07/2023, 08:34 Programming in Delphi
Borland Database Engine (BDE) uses TDatabase
ActiveX Data Objects (ADO) uses TADOConnection
dbExpress uses TSQLConnection
InterBase Express uses TIBDatabase
All database connection components except TIBDatabase let you execute SQL statements on the associated server by calling the Execute method. Although Execute can
return a cursor when the statement is a SELECT statement, this use is not recommended. The preferred method for executing statements that return data is to use a
dataset. The Execute method is very convenient for executing simple SQL statements that do not return any records. All database connection components maintain a list
of all datasets that use them to connect to a database. A connection component uses this list, for example, to close all of the datasets when it closes the database
connection.
GetTableNames()
GetFieldNames()
Datasets offer navigation and search methods like First, Last, Next, Prior, MoveBy, Bof, Eof, Bookmark, Locate, Lookup, Filter.
//The dataset must be closed when you specify or modify the SQL property.
MyQuery.Close;
MyQuery.SQL.Clear;
MyQuery.SQL.Add('SELECT CustNo, OrderNO, SaleDate');
MyQuery.SQL.Add(' FROM Orders');
MyQuery.SQL.Add('ORDER BY SaleDate');
MyQuery.Open;
MyQuery.SQL.LoadFromFile('custquery.sql');
SQLQuery1.ParamByName('Capital').AsString := Edit1.Text;
INSERT INTO Country (Capital) VALUES (:Capital)
Queries that don't return a result set should be run by calling ExecSQL:
CustomerQuery.ExecSQL;
If you are executing the query multiple times, it is a good idea to set the Prepared property to True.
Unlike most datasets, client datasets can also position the cursor at a specific record in the dataset by using the RecNo property. Ordinarily an application uses RecNo to
determine the record number of the current record. Client datasets can, however, set RecNo to a particular record number to make that record the current one.
Persistent fields are the fields added to the dataset at design time using the field editor, saved in dfm file and loaded from the resource at runtime. Called persistent
because they are not recreated everytime the dataset is closed and re opened.
To check
Data module
Fields (dynamic/persistent, calculated, data, lookup, aggregate), controlling user input, ADT + array + dataset + reference fields
If the datasets TTable and TQuery can be used without the BDE (SQLite)... when does their use require the BDE?
Sessions
Master/details
How to do this?
Display a single record vertically, ie. grey header on the left, and data on the right?
Let the user make any change in the data-aware grid, and save changes by just clicking on Save, or cancel through Close/Cancel, while checking that all changes
are OK before validating input?
How to combine ID + label (eg. product ID + description from table Products) in a combo box?
How to provide up/down or left/right arrows to move from either one part of a record to another (when all columns don't find in grid) or from one SELECT to the
other (eg. when viewing all the orders for a given customer using left/right arrows)?
More information
www.fredshack.com/docs/delphi.html 17/43
31/07/2023, 08:34 Programming in Delphi
CodeGear
A ClientDataSet in Every Database Application
Foundations in Database Development with Delphi and C++Builder by Cary Jensen
Migrating BDE Applications to dbExpress
The Future of the Borland Database Engine (BDE) and SQL Links
Navigating and Editing a ClientDataSet
Searching a ClientDataSet
Introduction to ClientDataSets and dbExpress
A ClientDataSet in Every Database Application
Searching a ClientDataSet
Navigating and Editing a ClientDataSet
Delphi.about.com
A Beginner's Guide to Delphi Database Programming (mostly ADO)
A Guide to Using dbExpress in Delphi database applications
Using the TDBGrid component (in Delphi database applications)
A Guide to Using the TClientDataSet in Delphi applications
Adding components to a DBGrid
Adjusting DBGrid column widths automatically
A TreeView of Data
Sorting records in Delphi DBGrid by Column title click
Datasets without databases
SQL in Delphi
Deploying Applications that use ClientDataSets
Tomes of Delphi - Win32 Database Developers' Guide.pdf
Delphi for Win32 VCL Database Development by Bob Swart
http://www.destructor.de/firebird/1.5/embedded.htm
"Borland's Delphi doesn't seem to work with Firebird 1.5. I just get messages like "Connection to database refused."
The Windows client library in Firebird 1.5 and higher is named fbclient.dll and is located in Firebird's \bin directory. Anything Made in Borland expects a client library
named gds32.dll located in the system path. You'll need to generate a special version of the Fb 1.5 Windows client library that is named gds32.dll and contains a version
string recognised by Borland products. If you choose the "compatibility" option during the installation, this library will be generated for you and placed in the \bin
directory, ready for you to copy over to your system directory.
If you didn't take the compatibility option during install, you can generate the special client yourself using the utility program instclient.exe (also in \bin). The doc for it is
in \doc\ README.Win32LibraryInstallation.txt."
Other engines
NexusDB
AidAim Accuracer Database System
Absolute Database
Advantage database (www.advantagedatabase.com -> Sybase)
ElevateSoft
An exception is an alternative way for a function to report the outcome of its operation. Not all functions and packages support exceptions, though. Here's some pseudo-
code:
or
try
MyFunc();
except
ShowMessage('MyFunc failed');
end;
www.fredshack.com/docs/delphi.html 18/43
31/07/2023, 08:34 Programming in Delphi
There are two kinds of exceptions: try..finally blocks, and try..except blocks. Typically, you use try..finally blocks to protect resources, and try..except blocks to handle
exceptions. Try/finally are much more used than try/except, as the former is an easy way to avoid memory leaks by making sure you release any resource dynamically
allocate, regardless of the outcome.
If you just want to run some code that could trigger an exception, use the following:
try
//stuff that could trigger an exception
except
//Handle exception
end;
If you don't want to handle an exception, but make sure to free a resource that you allocated before running the code likely to bomb, use this:
AllocateResource
try
//stuff that could trigger an exception
finally
//Free resource
end;
If you want both to handle an exception and perform some tasks even when things went ok, you'll have to run the following structure with a second try embedded
(Delphi doesn't provide a single try/except/finally structure):
AllocateSomeResources;
try
try
//stuff that could trigger an exception
finally
//perform general actions, such as FreeAndNIL()
end;
except
//handle exception
on E: Exception do begin
MessageDlg(E.Message, mtWarning, [mbOK], 0);
end;
end;
AllocateSomeResources;
try try
//stuff that could trigger an exception
finally
//perform general actions, such as FreeAndNIL()
end; except
//handle exception
on E: Exception do begin
MessageDlg(E.Message, mtWarning, [mbOK], 0);
end;
You might wonder why a resource is allocated before instead of inside a try block. The reason is that, when we call a constructor, we are assured that either the call
succeeds and we get a valid object, or the call fails and all resources are released. This is why we can place a constructor right before a try..finally block - if the
constructor raises an exception, there will be nothing to free.
If you only want to catch an exception but actually have it handled elsewhere (eg. centralizing it), use the Raise() function:
Result := SomeResource.Create;
try
Result.TrySomething;
except
Result.Free;
raise; //Let error bubble up and be handled elsewhere up there
end;
An alternative is to attempt to create an object, and use a Try/Finally to Free the object: In case the object couldn't be created in the first place, Delphi will jump to the
nearest exception handler, and the Finally section is ignored entirely:
Strings1 := TStringList.Create;
try
Strings1.Add('Hello, world!');
finally
Strings1.Free;
end;
From Exception Handling for Fun and Profit (a.k.a. Exception Handling in Delphi) by Nick Hodges: "One of the main purposes of exception handling is to allow you to
remove error-checking code altogether and to separate error handling code from the main logic of your application.
One way to do that is to centrally handle exceptions. TApplication has an event that allows you to do just that – the OnException event. You can use this event to deal
with all exceptions of any type that aren't otherwise handled by your application. You can use this event to log your exceptions, or provide specific handling for specific
www.fredshack.com/docs/delphi.html 19/43
31/07/2023, 08:34 Programming in Delphi
types of exceptions.
With exception handling, you can write your code as if nothing ever goes wrong, and then wrap that code up with try…except blocks if you like to deal with any of the
errors and problems that may occur. This enables your code to run more efficiently, as it isn’t constantly checking parameters and other data to make sure that it is in the
proper form before doing anything with it."
"As noted above, you should never eat exceptions. What you should do instead is to trap only specific exceptions that might reasonably be expected to occur in your
code.
As I mentioned above, I see code that eats exceptions added because the developer (or manager, or someone not thinking very clearly) never wants the user to see any
errors. The way to deal with that is to trap the specific exception that the user is seeing. For instance:
try
SomeCodeThatRaisesAnEConvertError;
except
on E: EConvertError do begin
// Deal with this specific exception here
end;
end;
Furthermore, database exceptions (and some others, like COM errors) generally include an error code, and you may wish to trap only errors with a certain error code and
allow others to surface. You can do this as follows:
try
SomeCodeThatRaisesAnEConvertError;
except
on E: EIBError do begin
if E.ErrorCode = iSomeCodeIWantToCatch then begin
// Deal with this specific exception here
end else begin
raise; // re-raise the exception if it’s not the one I handle
end;
end;
end;
Bottom line: Trap exceptions as far down the class hierarchy as you can and only trap those exceptions that you are planning on handling.
If you are like most of us, when first learning to use exception handling, you are tending to use exception blocks far too much. In most cases you do *not* want to
handle every possible exception at every possible place in your code. You *do* however, want to take advantage of finally blocks as often as you can to guarantee
against memory and resource leaks.
Perhaps you should consider using Application.OnException to avoid the default dialog box showing. This way you won't have to catch the exceptions, but you can still
avoid them being visible to the end user.
Resources
Components
Note
Components come in different shapes, as either a source file (.PAS), a compiled source file (.DCU), a source package that you must compile yourself (.DPK), or a
compiled binary file (.BPL, which requires its corresponding .DCP if you want to use it in design mode instead of just at run-time)
Most grids are inherited from TDatasets, which isn't available in the Personal version of Delphi. If using the Personal version, get a so-called unbound grid
A grid is just that; a spreadsheet also includes some computing capability, ie. Excel in your app
If you get the error "Could not create output file myfile.bpl", make sure that the output directory exists, as Delphi is not smart enough to create it itself
Tabs
As an alternative to showing multiple forms, you can use a tab control and stick a group of controls in each page of the tab.
The PageControl component has [TTabSheet] tabs on one side and multiple pages (similar to panels) covering the rest of its surface. There is one page per tab,
so you can simply place components on each page to obtain the proper effect both at design time and at run time.
The TabControl has only the tab portion but offers no pages to hold the information. In this case, you'll want to use one or more components to mimic the page
change operation, or you can place different forms within the tabs to simulate the pages.
www.fredshack.com/docs/delphi.html 20/43
31/07/2023, 08:34 Programming in Delphi
Every time you need multiple pages that all have the same type of content, instead of replicating the controls in each page, you can use a TabControl and change its
contents when a new tab is selected.
TTabControl is used when displaying the same controls on multiple tabs, eg. editing the properties of different objects through the same key/value vertical grid
TTabSet
TPageControl/TTabSheets/TFrames
Building reports
A report is a form with fields that you fill with data and send to the printer, possibly providing a preview so that the user can see what it'll look like before actually printing
the page.
Report generators let you build forms in two ways: Through a designer at design-time (ie. like drawing forms in the Delphi IDE), or through code at run-time.
FastReports 4 VCL
Closed-source, $79-349
"FastReport®4 VCL is an add-on component that allows your application to generate reports quickly and efficiently. FastReport® provides all the necessary tools
to develop reports, including a visual report designer, a reporting core, and a preview window."
FastScript: powerful multi-language script engine. It is useful for developers who want to add scripting abilities to their projects
FastQueryBuilder: Visual SQL query builder. It allows complex query creation based on several data tables without having to learn the SQL language
User's Manual (to work within the Designer application), Programmer's Manual (to work from the Delphi application), and Developer's Manual (to create custom
objects and function libraries for FastReport) are available here
the developers manual as to how to create custom objets and function libs for fr.
If you don't have the installer, here's how to install FastReport 4 manually:
FastQB
FastScript
ExportPack
Source
Source\ADO
Source\BDE
Source\DBX
3. Compile all the *.bdsproj file in the different directories
4. In addition, all the project files that start with "dcl" are design-time components, so they also need to be installed (Right-click on the project, choose Install, then
close the project)
Note: The Source\FIB\dclfrxFIB11.bdsproj requires the commercial FIBPlus component. Compiling this project will fail otherwise
The Text object can also include tags that will be converted at run-time: "Hello, World! Today is [DATE]."
A Band is used to place a group of objects at a specific location in a page. Use File > New Report to start with a three-band page. Bands are useful to add recurrent
occurences such as headers and footers.
Reports can be scripted (Pascal, C++, Basic, JScript), so you don't have to do this from the application.
Charts can be added through the TfrxChartObject component based on the TeeChart library which comes with Delphi.
FastReport provides extensive support for fetching data from databases, using ADO, BDE, IBX, etc.
If you need, you can add dialog boxes in a report (File > New Dialog), so you can eg. display some warning before printing a report, or prompting the user to provide
some data through an inputbox.
Here's how to build a basic, one-page report at design-time to show a barcode, fill it with data at run-time, display a preview version, and let the user send it to the
printer:
frxReport1.ShowReport();
ReportBuilder
Closed-source, $249-749
http://www.digital-metaphors.com
www.fredshack.com/docs/delphi.html 21/43
31/07/2023, 08:34 Programming in Delphi
QuickReports
Closed-source, £230
http://www.qusoft.com
Rave Reports
Ships with Delphi, but maybe it's a limited version compared to the one available from www.nevrona.com. As of August 2009, the site is not well maintained (nothing in
News, empty page when clicking on Features, etc.).
A Rave project than hold more than one report, and each report can have one or more pages. Leonel Togniolli wrote a four-part series of articles as an Introduction to
Rave Reports. The reports can either be an external file, or embedded in the EXE.
Here's how to create a report using Rave 7.5.2 that ships with Delphi2007, and allow the user to push a button to fill the report with data and send the page to the
printer:
Here's how to add parameters to the project/report/page and set them from the Delphi application:
RvProject1.Open;
RvProject1.SelectReport('ParametrizedReport',False);
RvProject1.SetParam('Name','Leonel');
RvProject1.Execute;
RvProject1.Close;
Post-Initialize Variables are those, like number of pages, that are only available after a report has been pre-processed and is ready to be printed.
It's obviously also possible to have the reporting tool connect to a database, and fill variables with this data.
A section, a.k.a. Mirror, is a collection of components, eg. a header with a title, page number, date and time of print, etc.
Here's the goal. The barcode will be read by an ANL-810 scanner, which supports multiple coding standards including Code 39, Code 32, CIP39, Code Bar (CLSI), EAN-13
UPC-A, EAN-8, Code 128 (EAN 128), etc.
Note that Code 39 doesn't support lower case letters and many other characters. Code 39 is a good barcode to start with, because it's easy and doesn't require any
checksum calculations. If you need characters that can't be provided by Code 39, try Code 128 B. That gives you the entire printable ASCII set. You'll need to generate a
checksum, and you'll need to map the codes to characters if you're using a font - it might be easier to generate as pure graphics. That's why the ActiveX controls are so
popular.
"I suggest Fast Report the best Report tool I have used. I have used QuickReport, Fortes Report, Report Builder and Rave before Fast Report."
"I use Fast Reports to print my barcodes. it has built in barcode support which makes it pretty easy to use"
"ReportBuilder Pro is a very good report generator for adding printing capabilities to your program."
TurboPower SysTools
http://tpsystools.sourceforge.net/
Open-source; Packs a bunch of stuff that has nothing to do with barcodes ("SysTools is a library of utility routines & classes for Borland Delphi, C++Builder,
& environments that support COM. It includes 1-D & 2-D bar codes, sorting, money routines, logging, high-precision math, a run-time math expression
analyzer, & much more.")
www.fredshack.com/docs/delphi.html 22/43
31/07/2023, 08:34 Programming in Delphi
"Turbopower Systools (there is an updated version of Systools floating around in the forums that included D2007 and D2009 support. Check over at Sebastian's
site, he has been been hard at work updating the TurboPower libraries and doing a great job :)"
http://www.java4less.com/barcodedelphi/barcodesdelphi.php
Closed-source, about 40€
Planner
http://www.tmssoftware.com/site/dbplanner.asp
DevExpress ExScheduler
http://www.devexpress.com/Downloads/VCL/ExScheduler/
ShorterPath Planners
http://www.shorterpath.com/products/planners/
http://www.innovasoftware.com
Delphi6?
Here are some components you can use if you need to add a WYSIWYG editor in a Delphi application. Some come as VCLs, others as C-DLLs or COM-DLLs. Some support
HTML, others use RTF (ie. you can embed pictures in the file, but those controls typically don't support Hx tags, etc.). Note that with the introduction of IE 5.5,
Microsoft's DHTMLEdit component has been superseded by the MSHTML Editor:
HTML Viewers
TWebBrowser (Said to leak memory; Google for how to use it to load a local HTML file, or display data from memory)
WPTools (commercial, starts at €350)
PurposeSoft HTMLEdit (commercial, starts at €170)
TRichView (VCL, single user license €225)
DITidy (commercial)
TeeChart (commercial, starts at €180)
ProfDHTMLEdit (commercial, relies on Internet Explorer, starts at €100)
HTML Viewer Components ("Nice component but huge and slow. It also has some redrawing bugs"), and its free small brother ThtmlLite (widget added to
Samples palette). Development stopped with D2006
TurboPower Internet Professional (couldn't set HTML using IpHtmlPanel1.SetHtml(String(MyStuff));)
QHTML (Delphi wrapper around the DLL)
HTML viewer (ActiveX, $US20 per developer)
1. First, install the designtime- and runtime- packages, and add a TRichView and a TRVStyle widgets to a form
2. Next, add the following code
RichView1.Style := RVStyle1;
RichView1.AddNL('Hello World!', 0, 0);
RichView1.Format;
The way TRichView works, applying a different style to a string requires first making the change to its linked TRVStyle widget via its RVStyle1.ParaStyles property, and
then send a string to be formatted.
HTML Cleaners
www.fredshack.com/docs/delphi.html 23/43
31/07/2023, 08:34 Programming in Delphi
Jeffrey Pohlmeyer's wrapper (requires libtidy.dll)
"TLibTidy is a Pascal wrapper for the library version of the HTML Tidy program by Dave Ragget. In opposite to Jeffrey Pohlmeyer's wrapper all functions are
loaded dynamically. A TidyLib.dll is not required until a TLibTidy object is actually created, so your application may also work if the Tidy Library is not available."
(As of 2005, the library is tidy.dll, so this wrapper most likely doesn't work)
TidyCOM - A COM Wrapper for HTML Tidy by André Blavier ("Unfortunately, I am no longer able to maintain TidyGUI and TidyCOM. However, notice that the
HTML Tidy core software is still well alive (see the Tidy Source Forge project). TidyGUI and TidyCOM (based on the 4th August 2000 version of HTML Tidy) will
still be available from this site as long as necessary.")
Outlook Bar
Grid
As of April 2005, recommended grid widgets are GridView, Profgrid, TMS TAdvStringGrid, Virtual Treeview, SMDBGrid, and ExpressSpreadSheet if you have the dinero.
Here are some solutions I found of VCL grid widgets under active development, DB- and non-DB aware:
As a reference, here's the size of an EXE built with Delphi 7 Enterprise to contain just a grid (make sure you clean up the Uses line in the PAS file when replacing one grid
with another...):
Borland's TValueListEditor
This is a two-column grid that you can use to display/change "key=value" tuples:
Scalabium SMDBGrid
"c:\Program Files\Borland\Delphi7\Projects\Bpl\.."
Couldn't find any infos on how to add data (demos load data automagically)
To print the grid you may use the TSMPrintData component: http://www.scalabium.com/smr
Column auto-resizing is available through the eoAutoWidth flag in ExOptions
SMDBGrid can draw the arrow for sorting (like Explorer) but real data sorting must be implemented on dataset level (change the active index for table or ORDER
BY clause for query)
www.fredshack.com/docs/delphi.html 24/43
31/07/2023, 08:34 Programming in Delphi
Use the SMImport (http://www.scalabium.com/smi) for data loading from external file
1. Launch Delphi, and open the DPK file, eg. SOURCES\SMCmpntD7.dpk. If you already had an older version installed, the Install button is disabled
2. Add this new directory to Delphi' Library path
3. Once installed, click in the palette on the SMComponents tab, and add an SMDBGrid widget to a form
[Fatal Error] Unit1.pas(7): File not found: 'Calendar.dcu'. Checked that I had the "VCL Source" installed.
Berg GridView
Moved here.
Kgrid
http://www.tkweb.eu/en/delphicomp/kgrid.html
Requires JCL
X-Files X-DBGrid
http://www.x-files.pl
TMS Software
http://www.tmssoftware.com
Plenty of components available either as stand-alone, or in packs
TAdvStringGrid (Single developer license for commercial use with source, updates and support 75 EUR)
Grid Pack (Single developer license for commercial use with source, updates and support 120E)
Free for use in non-commercial apps (shows some nag text in free version)
To use TMS' TAdvStringGrid, it's better to start with Borland's TStringGrid documentation, since TAdvStringGrid is based on it.
If you need a non-DB-aware editable grid, use TAdvColumnGrid instead: It has all the features of TAdvStringGrid combined with a flexible design-time and run-time
management of cell properties, inplace editors, cell print properties, sort style and formatting.
Here are a few actions that you can perform with this control:
www.fredshack.com/docs/delphi.html 25/43
31/07/2023, 08:34 Programming in Delphi
//Simulate row selecting by changing font and background colors
procedure TForm1.AdvColumnGrid1RowChanging(Sender: TObject; OldRow,
NewRow: Integer; var Allow: Boolean);
var
index : Integer;
begin
with AdvColumnGrid1 do begin
RowColor[OldRow] := clWhite;
RowFontColor[OldRow] := clBlack;
RowColor[NewRow] := clHighlight;
RowFontColor[NewRow] := clWhite;
end;
end;
//When user edits cell, set current row's font + background colors back to normal
procedure TForm1.AdvColumnGrid1DblClickCell(Sender: TObject; ARow,
ACol: Integer);
begin
with AdvColumnGrid1 do begin
RowColor[ARow] := clWhite;
RowFontColor[ARow] := clBlack;
end;
end;
//Triggered when users edits a cell
procedure TForm1.AdvColumnGrid1GetEditText(Sender: TObject; ACol,ARow: Integer; var Value: string);
var
today : TDateTime;
begin
today := Time;
Label1.Caption := IntToStr(MyCounter);
Inc(MyCounter);
end;
Here's a simpler way to change the background color of every other row to cream white:
procedure TForm1.AdvColumnGrid1GetCellColor(Sender: TObject; ARow, ACol: Integer; AState: TGridDrawState; ABrush: TBrush; AFont: TFont);
begin
//Ignore Row[0], ie. header
if ARow > 0 then begin
if (ARow Mod 2 = 0) then begin
ABrush.Color := clCream;
AFont.Color := clBlack;
end;
end;
end;
Note that a grid cannot have just a header, ie. fixed, grey row; It must have at least one non-header row, ie. RowCount > FixedRows:
www.fredshack.com/docs/delphi.html 26/43
31/07/2023, 08:34 Programming in Delphi
With AdvColumnGrid1 do begin
MyID := Cells[ColumnByName['article_id'].Index,Row];
end;
ShowMessage(MyID);
end;
Note: Unlike TAdvColumnGrid.GetEditText, TAdvColumnGrid.CanEditCell is called twice when clicking on a cell (but once when moving to a cell through the keyboard, and
once again when switching to edit mode through eg. F2). Here's how to make a column read-only but allow editing for a specific cell depending on the value of another
column in this row:
CanEdit
Here's how to build a two-column grid to display a key=value interface, with the very first column hidden so as to keep a table's SQL column names alongside their user-
friendly equivalent:
Here's how to add a TAdvColumnGridcontrol to a form, and fill it with a SELECT from a database:
DevExpress
ExpressQuantumGrid
http://www.devexpress.com/Products/VCL/ExQuantumGrid/
$399.99 with full source code (VCL Edition Only)
ExpressLibrary\Packages
ExpressLibrary\Sources
ExpressQuantumGrid 6\Packages
ExpressQuantumGrid 6\Sources
ExpressDataController\Packages
ExpressDataController\Sources
ExpressEditors Library 5\Packages
ExpressEditors Library 5\Sources
ExpressExport Library\Packages
ExpressExport Library\Sources
ExpressGDI+ Library\Packages
ExpressGDI+ Library\Sources
ExpressPageControl 2\Packages
ExpressPageControl 2\Sources
XP Theme Manager\Packages
XP Theme Manager\Sources
2. Compile ExportLibrary\cxLibraryD11.dpk, and compile/instal dclcxLibraryD11.dpk
3. Compile QG\cxGridD11.dpk and compile/install dclcxGridD11.dpk
www.fredshack.com/docs/delphi.html 27/43
31/07/2023, 08:34 Programming in Delphi
4. Compile DC\cxDataD11.dpk, cxADOAdaptersD11.dpk, cxBDEAdaptersD11.dpk, cxIBXAdaptersD11.dpk
5. Compile cxEditorsD11.dpk, compile/install dclcxEditorsD11.dpk, compile cxExtEditorsD11.dpk, compile/install dclcxExtEditorsD11.dpk
6. compile cxExportD11.dpk
7. compile dxGDIPlusD11.dpk
8. compile cxPageControlD11.dpk, compile/install dclcxPageControlD11.dpk
9. compile dxThemeD11.dpk
ExpressSpreadSheet
http://www.devexpress.com/Products/VCL/ExSpreadSheet/
$299.99 with full source code
ObjectSight TopGrid
DbAltGrid
http://www.quasidata.com/dbaltgrid.html
$149
"Did you ever wish of having a grid that lets you display and edit data not as rows and columns, but rather as records? A grid that would allow you to build unique
user interface solutions?"
Virtual TreeView
Moved here.
ProfGrid
Single-user license w/out source code 78.50E (w/ source code 118.15)
http://www.profgrid.com/grid.html
(June 2006) Latest version available is for Delphi7/C++Builder 6
"ProfGrid is one of the most powerful unbound grids on the market."
TStringGrid
This is the standard grid object that comes with Delphi7, and only has basic features. If you want a widget that resizes itself automatically to adapt to the width of the
items and offers sorting by clicking on a column header, you'll have to program this yourself.
TListView
This grid also comes with Delphi, can be used in combination with TTreeList or by itself, and looks more modern that TStringGrid. It doesn't natively support sorting by
clicking on an column header, but this can be implemented easily.
Extended StringGrid
http://www.eye.ch/~mduerig/prog/
Same look and feel as TStringGrid
TKStringGrid
http://www.korzh.com/delphi/components/
Freeware (53KB; requires the 114KB KProcs library, also free)
Missing kctrls7.res
JVCL
Open-source
Must be some grid in there somewhere if you can find it/them...
http://homepages.borland.com/jedi/jvcl/
ABF
VCL
http://www.abf-dev.com/abf-vcl.shtml
"more then 60 components"
Contains an enhanced ListView with sorting columns
Full version of the ABF VCL one developer license including source $99
Any grid in there?
abcComponents
http://www.abf-dev.com/abf-components.shtml
"base part of the ABF Visual Components Library"
free for non-commercial usage
Doesn't contain a grid widget
TjanGrid
www.fredshack.com/docs/delphi.html 28/43
31/07/2023, 08:34 Programming in Delphi
TjanGrid is a TStringGrid descendant
("TjvStringGrid has been renamed to TjanGrid.")
Failed to use after installing in new package (missing stuff)
TXDBGrid
TExDBGrid
RXLib
Open-source library
http://sourceforge.net/projects/rxlib/
Last updated 2002
Torry Grids
Woll2Woll Infopower
http://www.kobira.co.jp/sakura/d_table.htm
http://crlab.com/crgrid/
Doesn't seem to be available as a stand-alone widget
Integrates a query system with a regular grid widget
TfzGrid
http://www.fixzone.com/system/
"for Delphi 5/6"
£29.99
FlyTreeView
http://www.9rays.net
Similar to VirtualTreeView
112.95$
TxDbGrid
http://www.x-files.pl/components/xdbgrid.html
EURO 49.90
Don't like the sort icon
Task Pane
This is the alternative to the Outlook bar introduced with XP. At least five widgets are available: (RIP) TEasyTaskBand, Raize TRzGroupBar, TMS TAdvPanelGroup (also
available in the TMS Component Pack), DevExpress ExpressNavbar, ??? in the JVCL, LMD BarPack, and (RIP) TBX (add-on package to the Toolbar 2000 package).
type
EasyTaskBand1: TEasyTaskBand;
ImageList1: TImageList; //Big icons for groups
ImageList2: TImageList; //Small icons for items in groups
[...]
var
Group: TEasyCollectionItem;
Item: TEasyCollectionItem;
Group: TEasyGroup;
Item: TEasyItem;
begin
www.fredshack.com/docs/delphi.html 29/43
31/07/2023, 08:34 Programming in Delphi
EasyTaskBand1.BeginUpdate();
Group := EasyTaskBand1.Groups.Add;
Group.Caption := 'Group 1';
Group.ImageIndex := Random(ImageList1.Count);
Item := Group.Items.Add();
Item.Caption := 'Item: ' + IntToStr(j);
Item.ImageIndex := j mod ImageListSmall.Count;
Item.Captions[1] := 'Detail 1';
Item.Captions[2] := 'Detail 2';
Item := EasyTaskBand1.Groups[0].Items.Add;
Item.Caption := 'Item: ' + IntToStr(Item.Index);
Item.ImageIndex := 0;
Item := TEasyGroupStored(Group).Items.Add;
Item := LV.Items.Add;
EasyTaskBand1.EndUpdate();
EasyTaskBand1.Groups.Clear
EasyTaskBand1.Groups[0].Bold := CheckBoxSpecialGroup.Checked
If you want a task pane to resize automatically if the user changes the form's size (eg. going from maximized to some smaller, custom size), set the pane's Align property
from its default alNone to alLeft.
Internet
Here's how to fetch a web page and display its HTML source in a memo using ICS' HTTP client.
ICS (open-source)
"Magenta Systems File Transfer Components comprise three Delphi components, TMagFtp, TMagHttp and TMagFileCopy, the first two of which are high level
descendants of the ICS TFtpClient and THttpCli components, all allowing transfer of multiple files and subdirectories with a single function call.
Magenta Systems File Transfer Components are copyrighted software, but the compiled component DCUs may be used without cost in applications for use by the
developer or within their company but which are not otherwise distributed (including freeware and shareware). The component source code may be licensed for a
cost of £65 (UKP) (£76.38 with UK tax) which is about $125, or is available without extra cost to anyone that has financially contributed to the development of the
ICS SSL version at http://www.overbyte.be or that has licensed Magenta Systems TMagRas component. "
Indy (open-source)
Synapse (open-source)
LibCurl (open-source)
TurboPower Internet Professional (open-source; Deadware since 2003)
Clever Internet Suite (commercial)
MarshallSoft (commercial)
To read
If using "nil" as the owner, you must call the Free() method or you'll get a memory leak.
You don't have to use a variable to hold the pointer to the instance (source):
or
with TTable.Create(nil) do
try
DataBaseName := 'MyAlias';
TableName := 'MyTable';
Open;
Edit;
FieldByName('Busy').AsBoolean := True;
Post;
finally
www.fredshack.com/docs/delphi.html 30/43
31/07/2023, 08:34 Programming in Delphi
Free; //If using variables, you can call FreeAndNil() instead
end;
... but it's recommended to use a variable, so you can refer to it later:
FTimer := TTimer.Create(Self) ;
if not Assigned(FTimer) then do begin
ShowMessage('Not assigned');
Exit;
end;
with FTimer do begin
Interval := 1000;
Enabled := False;
OnTimer := MyInternalTimerEventHandler;
end;
FreeAndNil(FTimer);
Alternatively:
FTimer := TTimer.Create(Self) ;
try
with FTimer do begin
Interval := 1000;
Enabled := False;
OnTimer := MyInternalTimerEventHandler;
end;
finally
//Since Delphi doesn't provide try/expect/finally, here's a way to check for errors
if not Assigned(FTimer) then do begin
ShowMessage('Failed creating Timer');
end else begin;
FreeAndNil(FTimer);
end;
end;
Resources
If you'd rather not use several forms to show sets of objects, two alternatives are available: Using a TPageControl, and using frames.
TPageControl
Use a TPageControl to host the different pages, hide them all, and only display the desired page when the user selects the item in a menu.
Frames
Create frames, and insert the desired frame in the main form at runtime
Resources
If your application connects to a SQL server, it will have to display and handle a lot o fields that users can edit and save. Here are ideas proposed by experienced
developers:
Use the TPageControl which allows you to tab through pages on the same form, using Next/Prev buttons to move through pages
TabControl
Use a TScrollBox to scroll horizontally and vertically if needed
TabControl vs. PageControl? "Use TTabControl to add a control with multiple tab settings to a form. Unlike a page control, TTabControl is not made up of several pages
that contain different controls. Instead, TTabControl is a single object. When the current tab changes, the tab control must directly update its contents to reflect the
change in an OnChange event handler. (CLX?) TTabSheet is an individual page in a TPageControl object.
Use TPageControl to create a multiple page dialog or tabbed notebook. TPageControl displays multiple overlapping pages that are TTabSheet objects. The user selects a
page by clicking the page’s tab that appears at the top of the control. To add a new page to a TPageControl object at design time, right-click the TPageControl object and
choose New Page.
To create a tabbed control that uses only a single body portion (page), use TTabControl instead."
www.fredshack.com/docs/delphi.html 31/43
31/07/2023, 08:34 Programming in Delphi
Delphi.Net
To speed it up:
Glossary
BDE
BPL
CLX
Borland CLX™ (Component Library for Cross-platform) library, which encapsulates the Qt widget set for Windows and Linux.
DataSnap
ex-MIDAS; Middleware
DCP
"Delphi Compiled Package"; Contains headers and symbols when compiling a DPK. Must be provided with a BPL for design-time packages.
DCU
Unit in compiled format. All DCUs are combined into a single EXE, with the possible addition of VCLs if you prefer that components be compiled into the EXE instead of as
DLLs.
DFM
DPC
DPK
DPR
ECO
ECO is the .Net version of Bold which was already available in Delphi 7. ECO lets you build a .Net application from an Object model, regardless of whether the persistent
layer is object or relational.
Indy
InterBase
Client/server RDBMS, still available from Borland as a commercial tool, but also available as open-source under the name of Firebird
IntraWeb
Model Maker
www.fredshack.com/docs/delphi.html 32/43
31/07/2023, 08:34 Programming in Delphi
To create UML class diagrams and generate code. Delphi 8 introduces Together, which is also a CASE UML tool and was already available in other Borland products like
JBuilder or C++BuilderX.
PAS
RAVE
To generate reports
Unit
Program module. In a Delphi application, every form has a corresponding unit behind it.
VCL
RTL
Q&A
ShowMessage(ComboBox1.Text);
If you need to show different sets of controls, you can do this either through MDI child windows (the main form being the MDI parent), stand-alone frames, or frames
displayed in a pagecontrol (tab widget).
Unlike regular forms, MDI child windows can not be shown modal (so you can't just use a simple try/finally to remove the object from memory with Free(), and you'll
have to have the MDI child window call some routine in its parent window to have it be removed from RAM), and they flicker when displayed. A frame doesn't show
flickers when it is displayed. Both MDI child windows and frames require calling their parent to be removed from RAM.
After writing the routine, you can have it added to the form's class by using the keyboard combination CTRL-SHIFT-C
Either use Delphi's Runtime Type Information (RTTI), or (no: Doesn't display anything) GExpert's Class Browser.
(From embarcadero.public.delphi.language.delphi.general):
In the frame:
type
TFrame3 = class(TFrame)
private
FOnDone: TNotifyEvent;
public
property OnDone: TNotifyEvent read FOnDone write FOnDone;
end;
procedure TFrame3.Button2Click(Sender: TObject);
begin
if Assigned(FOnDone) then begin
FOnDone(Self);
end;
end;
In the form:
interface
www.fredshack.com/docs/delphi.html 33/43
31/07/2023, 08:34 Programming in Delphi
const
APPWM_FREE_FRAME = WM_APP + 100;
type
TForm1 = class(TForm)
private
procedure FrameIsDone(Sender: TObject);
procedure AppWmFreeFrame(var Message: TMessage); message APPWM_FREE_FRAME;
end;
procedure TForm1.AppWmFreeFrame(var Message: TMessage);
begin
TFrame(Message.LParam).Free;
end;
procedure TForm1.FrameIsDone(Sender: TObject);
begin
if Sender is TFrame3 then begin
PostMessage(Handle, APPWM_FREE_FRAME, 0, Integer(Sender));
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Frame3 : TFrame3;
begin
Frame3 := TFrame3.Create(nil);
Frame3.Align := alClient;
Frame3.Parent := Self;
Frame3.OnDone := FrameIsDone;
Frame3.Visible := True;
end;
ie. calling TFrame1.Done changes the frame's OnDone property, which triggers the frame's FOnDone custom event which is linked to the form's FrameIsDone procedure,
which calls AppWmFreeFrame to call PostMessage and actually unload the frame from memory.
1. Project > Options, and make sure the datamodule is loaded first before any form is loaded
2. In a form, use the following code to double-check:
if Assigned(DataModule3) then begin
ShowMessage('assigned');
end else begin
ShowMessage('not assigned');
end;
If you need to get the application's ExeName in a datamodule, either add "Forms" to the Use clause, or change Application.ExeName to ParamStr(0).
Can the IDE show the matching end for a given begin?
Castalia
Gexperts has editor experts to do this..you can also use the Delforex code formatter to lin up the pairs. Delforex is now part of Gexperts. GExperts allows you to
locate a matching delimiter (eg find an "end" from a "begin"), but it doesn't highlight them automatically like Castalia, for instance.
CnPack uses color highlighting to do just that. Works pretty well. I don't know if CnPack is available for RDS2007 yet though...
www.fredshack.com/docs/delphi.html 34/43
31/07/2023, 08:34 Programming in Delphi
How to support Far-East languages in Delphi 7
Thanks to VCL components, you can generate a stand-alone EXE, putting an end to the so-called "DLL Hell" and other issues that pop up when deploying a VB
app
The custom VCL components that you write can also be compiled into the EXE, instead of external files like in VB
Faster, tighter code, with the same productivity offered by VB (draw interfaces graphically, high-level language)
VB to Delphi - A resource for those moving from Visual Basic to Borland Delphi
Why Delphi ? Why not ?!!?? by Shiv Matlus
More on Moving from VB to Delphi by Michael Cone
VB.NET vs. Delphi: What's all that hype about?
The Case for Delphi by Alan Moore
How a visit to Delphi confirmed my preference for and disappointment in Visual Basic (From Saying Goodbye to Hardcore Visual Basic by "Hardcore VB" author
Bruce McKinney)
Microsoft Visual Basic vs. Inprise Delphi 4 by Peter McMahon
You heard it here first: Scoble was wrong. by Robert Scoble
"I'm Dumping Delphi for VS.NET" by TeamB member Nick Hodges
Follow up to Delphi sucks by Jens Winter
(French) Delphi et Visual Basic : une comparaison détaillée de ces deux environnements par Vincent CALLIES (février 2001)
(French) Présentation de Borland Delphi 8 for Microsoft .NET framework Par hachesse (19/01/2004)
The reason I mention Borland C++ over MS VC++ is that I read that the former has a tool that lets you build GUI screens graphically, while the latter still requires you to
write the whole thing in code, so cannot be reasonably compared to Delphi or VB.
Personally, I find C/C++ a pain to use, because the language itself requires your paying attention to details that are just a waste of time most of the time when
developing client-side applications, and keep you from concentrating on the problem the application is trying to solve. Considering you can build tight, dependency-free
code with Delphi, what's the point of wasting time with a lower-level language that was originally just meant for system development back in 1970?
IDE
Form Designer
Design Guidelines.
Form Positioner
Code Editor:
Debugger
Remote debugging.
Symbol table management.
Expandable watches.
CPU view.
Sort by load order.
Close implicitly opened files.
dbExpress
VCL
www.fredshack.com/docs/delphi.html 35/43
31/07/2023, 08:34 Programming in Delphi
Delphi Language Enhancements:
Operator overloading
Non-virtual method declaration
Regular instance methods
Constructors with non-empty parameter lists
Static methods and properties
FastMM built in
http://blogs.teamb.com/rudyvelthuis/archive/2005/05/11/4270.aspx
http://blogs.teamb.com/rudyvelthuis/archive/2005/05/13/4311.aspx
From Delphi 7 to Delphi 2007 - Comprehensive components list
VCL and RTL enhancements since Delphi 7 (D7)
Delphi 2007 - The Soul of Delphi returns!
C#, .NET, VB.NET, Vista, etc. So What is the Point?
New VCL features since Delphi 7
GExperts offers a Class Browser to see the list of methods, properties, and events provided by an object.
Since the main selling point was the productivity of VB but the speed/compactness of VC++, I don't see the added-value of using Delphi 2005 over VB.Net, unless you're
more familiar with Delphi and would rather use the same language to work with .Net.
Make sure Unit2 is referenced in Unit1's Implementation through "Uses Unit2", and that all exported routines in Unit2 are declared in Unit2's Interface section.
Project Options
An array created in a routine (procedure or function), even if its size is statically defined, is considered an "open array", and thus, starts at 0:
If you want the array to start at something else than 0, define the array as a new type:
type
TMyArray = Array[1..2] of String;
TForm1 = class(TForm)
...
www.fredshack.com/docs/delphi.html 36/43
31/07/2023, 08:34 Programming in Delphi
ShowMessage(IntToStr(High(ReturnArray)));
Check(ReturnArray);
end;
TPerlRegEx (free wrapper around PCRE, with additional support for replace and split actions; "You can choose to link the OBJ files directly into your application, or
to use the DLL"; Under active development; Made by author of www.regular-expressions.info)
PCRE Wrapper for Delphi 7 (requires a DLL; Under active development)
Delphi Regex Library (free for personal use; Last updated 2001)
DIPcre and DIRegEx (new version of DIPcre? Euro 20,00; Euro 60,00 with sources)
TRegExpr (Freeware Delphi Regular Expressions Library; Comes with Unit source, hence no need for DLL; Development stopped in 2004)
Turbo SysTools (Deadware; The StRegEx unit implements the TStStreamRegEx class and TStRegEx component)
TPerlRegex
To install this RegEx engine for Delphi, open, compile and install PerlRegExD7.dpk, which creates PerlRegExD7.bpl, add its directory to the Library path, and add a
TPerlRegEx control to the project's form.
PerlRegEx1.RegEx := '<title>(.+?)</title>';
PerlRegEx1.Options := [preCaseLess];
PerlRegEx1.Subject := 'test <title>bla</title> test';
Next, here's how to look for a pattern, and extract bits if found:
var
RegEx : TPerlRegEx;
Stuff : TStringList;
begin
RegEx := TPerlRegEx.Create(nil);
Stuff := TStringList.Create;
Try
RegEx.RegEx := 'my pattern';
RegEx.Options := [preCaseLess];
RegEx.Subject := 'this is the text to search for my pattern';
If RegEx.Match then begin
repeat
for i := 1 to regex.SubExpressionCount do begin
Stuff.Add(regex.SubExpressions[i]);
Application.ProcessMessages;
end;
until not RegEx.MatchAgain;
For I := 0 to Stuff.Count - 1 do begin
Memo1.Lines.Add(Stuff[I]);
end;
end else begin
ShowMessage('Not found');
end;
Finally
RegEx.Free;
Stuff.Free;
End;
End;
RegEx := TPerlRegEx.Create(nil);
try
RegEx.Subject := LoadFile('myfile.txt');
RegEx.RegEx := 'HERE';
www.fredshack.com/docs/delphi.html 37/43
31/07/2023, 08:34 Programming in Delphi
RegEx.Replacement := 'THERE';
If RegEx.Match then begin
RegEx.Replace;
ShowMessage(RegEx.Subject);
end;
finally
RegEx.Free;
end;
TRegExpr
Although TRegExp is much slower than TPerlRegEx on more complex operations, it's OK for light searches. Here's how to extract tokens from a text file using TRegExpr:
var
Tokens : TStringList;
MyRegex : TRegExpr;
begin
MyRegex := TRegExpr.Create;
Tokens := TStringList.Create;
try
MyRegex.ModifierI := True;
MyRegex.Expression := 'some stuf (\d+) some other stuff';
if MyRegex.Exec (Response) then begin
REPEAT
Tokens.Add (MyRegex.Match[1])
UNTIL not MyRegex.ExecNext;
Memo1.Clear;
for I := 0 to Tokens.Count-1 do begin
Memo1.Lines.Add(Tokens[I]);
end;
end else begin
Memo1.Text := 'Pattern Not Found';
end;
finally
MyRegex.Free;
Tokens.Free;
end;
And here's how to look for patterns, and replace them with something else:
You can combine the Object Inspector and Object TreeView windows through drag and drop,and dock them to the text editor with further drag and drop. Then, to tell
Delphi to keep this layout, hit View > Desktops > Save Desktop, and give a name to this new layout.
You can write programs using just the Object Pascal, a.k.a. Delphi, language and make direct calls to the Windows API so as to builder smaller programs. Read
Programming In A Subset Of Delphi, and DelphiZeus - Developing Delphi programs in Windows API without the Forms unit for more info.
How to get an MDI child form to use the whole client area?
www.fredshack.com/docs/delphi.html 38/43
31/07/2023, 08:34 Programming in Delphi
procedure TForm1.RzGroup1Items0Click(Sender: TObject);
var
Form2 : TForm2;
begin
Form2 := TForm2.Create(Application);
//BAD Form2.Align := alClient;
Form2.Align :=
end;
First, it looks like it's not enough for the second form to be part of the project: It must also be listed in the Uses section of the first form (ie. Uses Unit2), along with the
var section of its interface (var Form2: TForm2;), before being called with this kind of code:
begin
Form2 := TForm2.Create(Application);
ShowMessage(Form2.Name);
Form2.Show;
end;
I had an issue with the Rave part after running the 7.1 update. Here's how to restore Delphi:
I don't know if it hurts, but I also deleted Rave50CLXBE70.bpl and Rave50VCLBE70.bpl from \SYSTEM32.
(From "Delphi in a nutshell") A package has the extension .bpl ("Borland Package Library"), and avoid the problem of DLLs, namely, managing memory and class
identities.
In the Project menu, what's the diff between Compile and Build?
Compiled = turn each PAS file into object code (DCU?), while Build = link all the compiled units into an EXE?
You must first save the .PAS file and the .DPR project file for the Project | Build Project to generate the EXE.
"The ocx's are NOT compiled into a delphi app. In this regard delphi has the same relationship to ocx's as VB. But a delphi app is much less likely to use ocx's
than a VB app. I've never used one (except experimentally). [...]
So long as the components are native to Delphi then they can be compiled into the executable. By default the rest of the support code (which comes as runtime
dll's in VB) is also compiled into the executable. This results in a single exe and no need for runtime dll's. Component publishers often offer delphi native versions
of their ocx components. The delphi executable is relatively large but no way near as big as the VB exe/dll combination.
A significant advantage is that the versioning problems that affect ocx's don't exist in delphi and you don't force the end user to download any large runtime dll's.
(ocx's, incidentally, tend to be much larger than their delphi cousins).
However, delphi also offers the option of the VB approach (small exe and runtime dll's) and calls the dll's "packages". The delphi method of implementing the dll
approach is slightly more sophistocated than VB. Both approaches have their pros and cons.
Neither language can do much about ocx's, though delphi does at least offer an escape route."
Don't use any VCL package, eg. if the application uses no forms or you're willing to make calls to the Win32 API yourself, you can remove the reference to the
Forms unit, and save a lot in terms of EXE size
Build the EXE with packages, ie. the VCL stuff is kept in external .BPL files that you'll need to provide with the EXE, but will not have to ship again the next time
the EXE is updated
Shrink the EXE using binaries compressors like UPX, Shrinker, etc.
"The optimizer normally deletes all functions which are not needed. So it doesn't matter how many units are in the uses clause. Only the needed functions will be
linked into the EXE > Actually, that's not quite the case - if there's an initialization clause or a Register procedure, quite often the whole thing will get linked in -
www.fredshack.com/docs/delphi.html 39/43
31/07/2023, 08:34 Programming in Delphi
the "class of" types and the like ensure that if the unit is used, it will have all the binary available just in case there's a TStream.ReadComponent(nil) and an
object of that class happens to be in the stream file. Works in many cases for one's own units, though. There's a similar logic to why the linker can't get rid of
virtual/dynamic methods. > You can pull the same sort of trick with Delphi, if you care to. The "build with runtime packages" option lets you have a much smaller
.exe, with the base Delphi class library residing within a bunch of files beginning with "vcl" in your C:\Windows\System directory. Since Delphi's not quite as
common as some programming languages, you're more likely to need to distribute these, but you can issue a much smaller update. Our clients seem to be
willing to take the standard everything-compiled-in approach simply for ease of deployment."
var
MyTitle : String;
begin
MessageBox('text', MyTitle, [smbOK]);
Do I really need to call Free() after each Create(), or does Delphi frees memory when the program ends?
Yes, because unlike internal data types like String or Integer, objects must be created manually through Create() and freed with... Free().
CodeGuard cannot report anything that takes place in Windows *after* your application terminates. It correctly reports that, at the time of termination, your
application has failed to explicitly release some memory. Windows, barring some other error, tracks all memory allocations for a process and, upon termination,
will free up that memory anyway. So that, in itself, is not the issue.
The issues are:
1) as long as your application *continues to run* it will be holding memory unnecessarily that cannot be used by other processes. If it is a repeated leak then
eventually the system *will* run out of memory.
2) It isn't just a matter of memory but also other O/S resources. For example if the object you forget to free is holding open file handles or a COM or TCP port, or
graphic resources, etc, then again that is impairing the operation of the system and, in some of these cases, it may be that they *won't* be fully cleaned up by
Windows after the application terminates.
3) Simply bad programming practice to not cleanup properly.
Besides always adding a Try/Finally to .Free() any object, it's a good habit to check a projet with the FullDebugMode option of FastMM, especially during the initial
construction phase of the project.
"[Fatal Error] File not found bla.dcu" after installing a new package
After installing a new design-time package (*.DPK) through File > Open > Install, you also need to add the path to its *.DCU files through Tools > Environment Options
> Library, in the Library Path.
Application.ProcessMessage
Some utilities (such as this one) use RTTI to read this from an object which requires upgrading to Delphi 2010 for full information (more basic information available
through RTTI on previous versions of Delphi).
Here's how to get the datatype expected from a column in a dataset (untested):
uses
TypInfo;
var
aDataType: TDataType;
aDataType := MyQuery.FieldByName('FieldName').DataType;
ShowMessage(GetEnumName(TypeInfo(aDataType), Ord(aDataType));
www.fredshack.com/docs/delphi.html 40/43
31/07/2023, 08:34 Programming in Delphi
Alternative:
//DataType is not a string, and therefore can't be typecast to a string -> Ord()
ShowMessage(IntToStr(Ord(ASQLite3Query1.Fields[myCol].DataType)));
Delphi Peeves
IDE
Can't set bookmarks (eg. F2 in UltraEdit)? The best I found, is CnWizard's use of "margin number"
Moving the caret up/down doesn't move it to the end of the line on which it ends (must hit End)
No foldable blocks, or at least vertical hints to show indentation
Can't save a whole project under a different name, in a different folder? (File > Save As = individual .PAS file; File > Save Project As = only saves project files like
.DPR, .DOF, etc., but leaves all other files in original folder, updating paths)
Can't comment block with {} if it already contains a commented block -> must use {$IfDef Bla}...{$EndIf}
Language
The structure to handle exceptions could be improved. Even in D2006, it's either try/except or try/finally, but some cases need a more fine-tuned structure:
try
IdTCPClient1.Connect;
ShowMessage('ok');
IdTCPClient1.Disconnect;
except
ShowMessage('failed connecting');
finally //Stuff to run whatever the outcome
ShowMessage('this message displayed every time');
end;
D2009 supports this, but not older versions. Take a look at these:
www.glyfx.com
www.iconlook.com
www.iconfinder.net
www.iconlet.com
Resources
Learning Pascal
(for history's sake) Why Pascal is Not My Favorite Programming Language by Brian W. Kernighan, April 2, 1981
(Wikipedia) Pascal programming language
Pascal language tutorial by Gordon Dodrill
Pascal Central
Learn Pascal by Tao Yue
The Pascal Programming Language by Bill Catambay
Marco Cantù's Essential Pascal
Learning Delphi
Sites
Delphi.about.com
Discovering Delphi by Ron Frazier
Delphi Basics (the whole of Delphi summarized on one page)
(Wikipedia) Delphi programming language
Delphi and Pascal Programming Tutorials
(French) Tutoriels, FAQ,
DelphiZeus - Developing Delphi programs in Windows API without the Forms unit
The C# Design Process: A Conversation with Anders Hejlsberg and Deep Inside C#: An Interview with Microsoft Chief Architect Anders Hejlsberg
Object Pascal beats C++ by Jim Phillips
Data access dilemma by Marco Cantu (BDE vs. ADO)
Delphi Tips
The Delphi Super Page
A Brief History of Strings - Delphi strings in depth, and Raw Delphi - Delphi Without the VCL or the IDE by Emil Santos
Delphi @ Wikicities
Free Pascal 64-bits/Cross Platform - Borland Stuck in Stone Age
Controls Demystified By Glenn Lawrence
Tables vs. Query Components - Differences between Desktop and C/S databases
www.fredshack.com/docs/delphi.html 41/43
31/07/2023, 08:34 Programming in Delphi
Object Oriented Programming in Delphi - A Guide for Beginners
Books
Kick Ass Delphi Programming by (Publisher: The Coriolis Group) by Don Taylor et al. (09/01/96)
Mastering Delphi 7 by Marco Cantu (2003)
Delphi Developer's Handbook by Marco Cantu
Mastering Borland Delphi 2005 by Marco Cantu'
Delphi in a Nutshell by Ray Lischner (2000)
Delphi 6 Developer's Guide by Xavier Pacheco, Steve Teixeira
Delphi COM Programming by Eric Harmon
The Tomes of Delphi - Win32 Shell API Windows 2000 Edition
The Tomes of Delphi - Win32 Database Developer's Guide
The Tomes of Delphi - Algorithms and Data Structures by Julian Bucknall
The Delphi Magazine (site gone)
Dr. Bob's Delphi Clinic
Delphi for Win32 VCL Database Development by Bob Swart
Delphi/Kylix Database Development by Eric Harmon (on dbExpress)
Learning Delphi.Net
Tools
Free Pascal (free, open-source Pascal compiler) and Lazarus (the class libraries for Free Pascal that emulate Delphi)
BloodshedSoftware Dev-Pascal (IDE similar to Lazarus)
MSEide + MSEgui - Pascal Cross Platform GUI Development System
LizaJet Installer for Delphi Developers
Lotta free components etc. over at Torry.net
Python for Delphi (latest is 3.25 dated 2003)
Chrome (closed-source ObjectPascal for .Net)
Dependency Viewer, PE Viewer, etc.
"GExperts is an [open-source] set of tools built to increase the productivity of Delphi and C++Builder programmers by adding several features to the IDE" (Article
on GExperts on delphi.about.com)
"Castalia enhances the Borland Delphi IDE to help make developers more productive. Castalia helps developers to write better code faster, understand existing
code more efficiently, and improve the design and quality of existing code."
CnWizards
"Key Objects Library (KOL) is a library of objects, which can be used with Delphi IDE and Delphi compiler to create small 32-bit GUI applications for Windows.
Delphi versions from Delphi2 to Delphi7. The smallest GUI program, which can be created using KOL, is about 14K. Smallest console application is about 4,5K with
KOL. "
"Project JEDI is an international community of Delphi developers with a mission to exploit our pooled efforts, experiences and resources to make Delphi and Kylix-
-the greatest Windows and Linux application development tools--even greater.."
"The JEDI Code Library (JCL) consists of a set of thoroughly tested and fully documented utility functions and non-visual classes which can be instantly reused in
your Delphi and C++ Builder projects."
"The JEDI Visual Component Library (JVCL) consists of a large collection (currently ca 500) visual and non-visual components which can be instantly reused in
your Delphi, Kylix and C++ Builder project"
Freebyte's Guide to free Delphi programming
Components and articles at Programmer's Heaven
Steve Trefethen's Resources for converting from Microsoft Visual Basic (VB) to Borland's Delphi
The ultimate Delphi IDE start-up hack (" will trim the start-up time of your Delphi IDE")
News
Delphi Wiki
Delphi Programming (www.about.com)
Borland
(French) Phidels (active forums)
Delphi32 (forums a bit slow)
Delphi3000
Undu - The Unofficial Newsletter of Delphi Users
DelphiCity - Delphi and C++ Builder tools directory
DelphiSource
DelphiBasics
Delphi Pages
(French) Delphi Codes Sources (et aussi un forum)
(French) Forum Delphi sur developpez.com
(French) Forum Delphi sur hardware.fr
The Delphi Corner
The Delphi Compendium
Delphi developer support
Borland Delphi Newsgroups (borland.public.delphi.*)
Usenet Delphi Newsgroups
comp.lang.pascal.ansi-iso
comp.lang.pascal.borland
comp.lang.pascal.misc
www.fredshack.com/docs/delphi.html 42/43
31/07/2023, 08:34 Programming in Delphi
Code Central Repository is a free, searchable database of code, tips, and other materials of interest to developers
www.fredshack.com/docs/delphi.html 43/43