TechiWarehouse.Com


Top 3 Products & Services

1.
2.
3.

Dated: Aug. 12, 2004

Related Categories

Delphi Programming

Introduction

Object (or Delphi) Pascal, a set of object-oriented extensions to standard Pascal, is the language of Delphi. Delphi Pascal is a high-level, compiled, strongly typed language that supports structured and object-oriented design. Its benefits include easy-to-read code, quick compilation, and the use of multiple unit files for modular programming.

Borland Delphi is a sophisticated Windows programming environment, suitable for beginners and professional programmers alike. Using Delphi you can easily create self-contained, user friendly, highly efficient Windows applications in a very short time - with a minimum of manual coding.

Delphi TutorialDelphi provides all the tools you need to develop, test and deploy Windows applications, including a large number of so-called reusable components.
Borland Delphi, in it's latest version, provides a cross platform solution when used with Borland Kylix - Borland's RAD tool for the Linux platform. Borland Delphi (1/2/3/4/5) is a development tool for Microsoft Windows applications. Delphi is powerful and easy to use tool for generating stand-alone graphical user interface (GUI) programs or 32-bit console applications (programs that have no GUI presence but instead run in what is commonly referred to as a "DOS box.")

When paired with Borland Kylix, Delphi 6 users can build single-source applications for both Windows and Linux, which opens new opportunities and increases the potential return on development investments. Use the Cross-platform CLX component library and visual designers to build high-performance portable applications for Windows that can be easily re-compiled on Linux.

Delphi is the first programming language to shatter the barrier between high-level, easy-to-use rapid application development environments and low-level bits-and-bytes power tools. Delphi ships in a variety of configurations aimed at both departmental and enterprise needs. With Delphi, you can write Windows programs more quickly and more easily than was possible ever before.

Delphi can access many types of databases. Using forms and reports that you create, the BDE (Borland Database Engine) can access local databases, like Paradox and DBase, network SQL server databases, like InterBase, and SysBase, and any data source accessible though ODBC (open database connectivity).

Application vs CLX Application

With some versions of Delphi (supposed Delphi 6 Professional or Enterprise), you can build and develop cross platform applications that can be ported to Linux and compiled with Kylix. To develop a CLX application, instead of standard Windows application, you could pick CLX Application from the File | New menu. The Delphi IDE is similar to one when you build Windows applications, except that the Component palette changes dynamically to show the objects that are available for use in Linux CLX applications.

Since this course is about Delphi for the Windows platform, we will be exploring Delphi programming from that point of view. However, if you have Kylix and want to join this course you are of course encouraged to do so. Even though, my intention at this stage of this Course, is not to explain differences between CLX (Linux) and VCL (Windows) development you should know that there are no reasons why you should not join the course and just have in mind that when we talk about, let's say, form1.DFM you think form1.XFM.

Delphi vs Others

What is the BEST RAD tool for you!

"I would like to learn a visual orientated programming language but I can't choose between Delphi, Visual Basic, Java, C/C++, PowerBuilder, Clarion...." A question commonly asked by software developers. If you have ever asked yourself a question like this one (and I bet you have) than you know that there is no straight answer.

"Just for the fun of it, let's place Visual Basic, Delphi, and Oracle Power Objects side by side. Let's test development capabilities, database support, performance, and other features that really matter. May the best tool win!" From Borland.com

Visual Basic and Delphi Head to Head

"We did a side-by-side comparison of the currently shipping versions of Delphi and VB that are specifically geared toward client/server development: Borland's Delphi Client/ Server and Microsoft Visual Basic 3.0, Professional Edition." From ZDNet

Why I really like Delphi

"We are VB people, but first and foremost we are solution designers. While we may be most comfortable with Visual Basic and in spite of the Microsoft Marketing team saying we can do anything with VB, the fact is that VB has limits." From Visual Basic Developers Association

Delphi. Reasons why.

"Delphi combines much of the power of C++ with the ease that one expects (and doesn't get) of VB. Here is why..."

Rapid Application Development Tools

NSTL compared leading rapid application development (RAD) tools for Windows 95 and Windows NT. The products evaluated were Visual Basic 6.0, PowerBuilder 6.0 and Delphi 4.0.

Why shun Delphi?!

"My personal belief is that the Delphi system and its language (Borland Object Pascal) is not an appropriate system for teaching introductory programming. Readers are welcome to disagree!" From Graham Perkins

Delphi and Clarion for Windows

Clarion for Windows version 1.5 and Delphi Desktop Edition version 1 with focus on database application development. From Sean Gates.

The Case for Delphi

"They are concerned that by using Delphi we will not be able to integrate into new technologies like Office 2000". Read this article and you'll find out that they are wrong. From DelphiMag.com

Conclusion

It is up to you as the developer to make your own decision based on your needs, but you have to know that: "No language is perfect nor perfectly suited for every programming purpose" If you already know what tool is best for you than you should know: "Better to suffer, while limitations are sufferable, than to abandon the languages to which we are accustomed."

Lets the Game Begin

My First Delphi Program

The first step in developing a Delphi application is to plan what the user will see. We have to design the screens. What menus do you want? How many windows should there be? Will the application have places to enter text (edit boxes)?

In Delphi, the objects a programmer places on the windows (forms) are called components. Some of the components are buttons, edit boxes, labels, combo boxes, option buttons, etc.

As you will see, all these components (objects) are standard Windows objects. Depending on which version of Delphi you have, you start with more than 100 components at your disposal, and than you can add components by buying them or creating them.

Only after you design the interface of your application, you should start writing code.

Further steps in developing a Delphi application:

Customize the windows that user sees. This means placing components on the form - you literally draw the user interface, almost as though you are using a paint program

Decide what events the components on the form should recognize. For example: we have to specify what will happen if user clicks the button. An event is something that occurs as a result of a component's interaction with the user or with Windows.

Write the event procedures for those events. The programming code in Delphi that tells your program how to respond to events like mouse clicks is inside what Delphi calls event procedures.

Now lets come to Code

We'll begin by launching Delphi. When you first start the program, you are presented with both a blank form and the IDE (integrated development environment).

At the top of the blank form is the title bar with its caption. To the left of the form, the Object Inspector shows the properties for the form. Choose the caption property and change it from 'form1' to 'My first Delphi program'.

Now press F9 or choose Run-Run from the main menu. Before you even know what has happened, Delphi has built the program. The form is displayed, and the caption shows My first Delphi program. Notice that what you see is an ordinary looking Windows window. This IS a true Windows program. Window can be moved by dragging the title bar, it can be sized, it can be minimized, it can be maximized, and it can be closed by clicking the Close button.

Try it, and finally close it.

You can even locate the program in Windows Explorer (it will probably be in your \Delphi??\ directory as Project1.exe) and double-click on it to run it.

Ok, ok I know this is not something. So, let us write some code. If you still have your first program running, close it by using ALT-F4.

Click on the Events tab in the Object Inspector window. Double click in the right column of the item marked "OnClick". This brings the Code Editor window to the top of the screen. Delphi generates an event handler for the button's OnClick event. The generated code looks like this:

procedure TForm1.FormClick(Sender: TObject);
begin
|
end;

Right now, you don't need to be concerned with everything you see here. You only need to understand that the OnClick event handler is a section of code that will be executed every time the form is clicked.
Enter this code at the cursor:

form1.Caption:='User clicked on the form!';

This code simply assigns the value User clicked on the form to the Caption property of the form.

Now run the program (let's us term project, rather than program, to refer to the combination of programming code and user interface). Click on the form and notice that the caption changes from My first Delphi program to User clicked on the form!.

As you have noticed by now, this is not a very useful application. However, by creating it you have learnt some essential steps of creating any application in Delphi.

Ordinal Data Types

Extend Delphi's built-in types by constructing your own types.

Delphi's programming language is an example of a strongly typed language. This means that all variables must be of some type. A type is essentially a name for a kind of data. When we declare a variable we must specify its type, which determines the set of values the variable can hold and the operations that can be performed on it.

Many of Delphi's built-in data types, such as Integer or String, can be refined or combined to create new data types. In this article we'll see how to create custom ordinal data types in Delphi.

Ordinal types

The defining characteristics of ordinal data types are: they must consist of afinitive number of elements and they must be ordered in some way.

The most common examples of ordinal data types are all the Integer types as well as Char and Boolean type. More precisely, Object Pascal has twelve predefined ordinal types: Integer, Short int, Small int, Long int, Byte, Word, Cardinal, Boolean, Byte Bool, Word Bool, Long Bool, and Char. There are also two other classes of user-defined ordinal types: enumerated types and sub range types.

In any ordinal types, it must make sense to move backward or forward to the next element. For example, real types are not ordinal because moving backward or forward doesn't make sense: the question "What is the next real after 2.5?" is meaningless.

Since, by definition, each value except the first has a unique predecessor and each value except the last has a unique successor, several predefined function are used when working with ordinal types:

Function Effect
Ord(X) Gives the index of the lement
Pred(X) Goes to the element listed before X in the type
Succ(X) Goes to the element listed after X in the type
Dec(X;n) Moves n elements back (if n is omitted moves 1 element back)
Inc(X;n) Moves n elements forward (if n is omitted moves 1 element forward)
High(X) Returns the lowest value in the range of the ordinal data type X.
Low(X) Returns the highest value in the range of the ordinal data type X.


For example, High (Byte) returns 255 because the highest value of type Byte is 255, and Succ(2) returns 3 because 3 is the successor of 2.

Note: If we try to use Succ when at the last element Delphi will generate a run-time exception if the range checking is on.

Enumerated Data Types

The easiest way to create a new example of an ordinal type is simply to list a bunch of elements in some order. The values have no inherent meaning, and their ordinality follows the sequence in which the identifiers are listed. In other words, an enumeration is a list of values.

type TWeekDays = (Monday, Tuesday, Wednesday,
Thursday, Friday, Saturday, Sunday);

Once we define an enumerated data type, we can declare variables to be of that type:

var SomeDay : TWeekDays;

The primary purpose of an enumerated data type is to make clear what data your program will manipulate. An enumerated type is really just a shorthand way of assigning sequential values to constants. Given these declarations, Tuesday is a constant of type TWeekDays.

Delphi allows us to work with the elements in an enumerated type using an index that comes from the order that they were listed in. In the previous example: Monday in the TWeekDays type declaration has the index 0, Tuesday has the index 1, and so on. The functions listed in the table before let us, for example, use Succ(Friday) to "go to" Saturday.

Now we can try something like:

for SomeDay := Monday to Sunday do
if SomeDay = Tuesday then
ShowMessage('Tuesday it is!');

The Delphi Visual Component Library uses enumerated types in many places. For example, the position of a form is defined as follows:

TPosition = (poDesigned, poDefault, poDefaultPosOnly,
poDefaultSizeOnly, poScreenCenter);

We use Position (through the Object Inspector) to get or set the size and placement of the form.

Subrange Types

Simply put, a subrange type represents a subset of the values in another ordinal type. In general, we can define any subrange by starting with any ordinal type (including a previously defined enumerated type) and using a double dot:

type TWorkDays = Monday .. Friday;

Here TWorkDays includes the values Monday, Tuesday, Wednesday, Thursday and Friday.

Design Patterns in Delphi

Exploring design patterns in real programming, focusing on implementation issues in Delphi

"Patterns describe a problem which occurs over and over again in our environment, and then describe the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice."

Design Patterns

Patterns are devices that allow programs to share knowledge about their design. In our daily programming, we encounter many problems that have occurred, and will occur again. The question we must ask ourselves is how we are going to solve it this time.

In object-oriented programming, a pattern can contain the description of certain objects and object class to be used, along with their attributes and dependencies, and the general approach to how to solve the problem. By analogy, design patterns are to object-oriented programming what algorithms are to procedural programming. The basic elements of procedural programming (step instruction, conditionals, and branching) aren't very useful without concepts like linked list and quick sort to give them some structure.

In other words, Design Patterns provide tested and effective solutions to common problems that occur in software development.

SINGLETON
Creating a real singleton class in Delphi
A singleton is a class that supports the creation of just one object. It's like your computer -- there's just one keyboard. So if you were writing Delphi code that simulated your computer, you would want just one object instance to deal with keyboard read, write, and control activities. The article describes how to create a class that follows the singleton pattern. The class described will take care of the singleton requirements and effects itself, effectively leaving the programmer to use the class as any others.

Implementing a Singleton Pattern
Some common examples of Singletons used in the VCL are the TApplication and TScreen classes that are existent in all Delphi applications. Others include TPrinter and TClipboard. In this article, the author presents a practical use for the singleton pattern by illustrating a global user configuration object.

TEMPLATE METHOD
Frameworks with the Template Method Pattern
The Template Method pattern are like abstract classes in the VCL. In this article, the author will create a simple application framework using a commonly used pattern, the Template Method. We will discuss two concepts: designing a framework around which you develop a user interface, and using patterns to accomplish this.

BUILDER
Extending Frameworks - Building Add-in Packages
In this article, two aspects of patterns are discussed: pattern classifications and how patterns are described. The Builder pattern is a useful creational technique for structuring complex objects resulting in a self-contained product.

MEDIATOR
Introduction to Process Control Frameworks
The Mediator pattern is used to "Define an object that encapsulates how a set of objects interact". In this article, the author uses use the Mediator pattern to illustrate how to solve the problem of process flow control in a batch processing system.

RECYCLING FACTORY
A Recycling Factory Pattern in Delphi
The problems of using and reusing many varying size objects in an application can cause fragmentation of the heap that can slow down processing speed. In this article, the author uses a factory object to make and recycle objects with minimal fragmentation effects.

 

DLL in Dephi

A Dynamic Link library, or DLL, is a collection of routines (small programs) that can be called by applications and by other DLLs. Like units, DLLs contain sharable code or resources, they provide the ability for multiple applications to share a single copy of a routine they have in common. The concept of DLLs is the core of the Windows architectural design, and for the most part Windows is simply a collection of DLLs.


If you look in the project file of any Delphi application, you'll see that it starts with the reserved word Program. By contrast, DLLs always begin with the reserved word Library. This is then followed by a uses clause for any needed units. In this simple example, there then follows a procedure called DllMessage which does nothing except showing a simple message.

At the end of the source code we find an exports statement. This lists the routines that are actually exported from the DLL in a way that they can be called by another application

 

.

VARIABLE SCOPE


Scope of Variables and Constants

The term scope refers to the availability of a variable or constant declared (or used) in one part of a program to other parts of a program.

Unless we specify otherwise, changing the value of a variable named, let's say, SomeNumber in one procedure (function) will not affect another variable with the same name in another procedure (function).

Since Delphi requires us to declare variables, it's a lot harder to fall into the trap caused by side effects accidentally. As we know by now, every variable used in some procedure has to be declared in the var section of the event handler.

In general, we declare a variable where we want to use it. For example, if we want to use a variable in an event handler, we declare the variable within the event handler.

Local Scope (+ variable declaration and initialization)

Most variables have local scope, which means that the variable is visible only within the code block in which it is declared (usually: Event Handler for some method). In particular, an event handler will not normally have access to the value of a variable in another event handler.

If we want to be sure a variable is local within an event handler, we have to declare it in the var section inside the event handler. Since we must declare a variable before we can use it, if we can use a variable without declaring it locally, we know that there is a variable with greater scope with the same name somewhere around project.
Let us look at the first example:

1. Start Delphi, this will give us (by default) new application with one blank form.
2. Double click somewhere on the form (to create OnCreate event handler)
3. Write down this code:
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowMessage(FloatToStr(SomeNumber));
end;

4. If you try to run your project now, you will be prompted with: "Undeclared Identifier: 'SomeNumber'" error. This means that we haven't declared SomeNumber variable in our project (note: entire project, not FormCreate event handler).

5. To declare SomeNumber variable as double type change your code to:
procedure TForm1.FormCreate(Sender: TObject);
var SomeNumber: double;
begin
ShowMessage(FloatToStr(SomeNumber));
end;


6. Run your project, message box will appear with some strange (value of the memory region where variable is stored) number. Delphi will also give us "Variable 'SomeNumber' might not have been initialized" warning. This means that, before using declared variable, it is a good practice to initialize it (just to be sure). For that purpose add this line of code before ShowMessage...
SomeNumber := 123.45;

7. Now, when you run your project message box will display 123,45 (no errors, no warnings). Finally, we can see why local variables are called local.

8.Add one TButton component to form and double-click it to create Buttons OnClick event handler. Add the following code (so that OnClick looks like):

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(FloatToStr(SomeNumber));
end;

Again we have "Undeclared Identifier: 'SomeNumber'" error. This is what local variables are all about: even if we have declared (and initialized) SomeNumber variable in OnCreate event handler of the form, SomeNumber is not accessible in the OnClick handler of TButtton. We simply cannot use SomeNumber (with 123.45 value) in the OnClick (at least for now). This means that SomeNumber from OnCreate and SomeNumber from OnClick are two different variables (that can, of course, hold different values)

9. Don't close this project, jet. We will need it again...

10. Add the following line before ShowMessage in the OnClick event handler (we will need it later, don't worry about this for now)
SomeNumber:=555.55;

Sharing variables across procedures (event handlers)

Occasionally we will want to share the values of variables (and constants) across event handlers or across units. For example, if an application is designed to perform a calculation involving one SomeNumber at a time, that SomeNumber should be available to all procedures in a unit.
Depending on where we declare a variable, the variable can be thought of as a true global variable accessible by any other code in the application, or a unit-level variable accessible by any code in the unit.

Unit level variables - unit level scope
We put the declaration statements for unit-level variables in a var section in the unit's implementation section. Unit-level constants are declared in a const section.

Let's look at the second example:

0. We will be modifying our first example (be sure to have it)
1. Add declaration of SomeNumber, so that implementation code of the unit looks like:
...
implementation
{$R *.DFM}
var
SomeNumber: Double;
...



2. Run your program. As you can see, we don't have "Undeclared Identifier: 'SomeNumber'" error in OnClick handler of the TButton. When program starts message box will appear with 123.45 value. When you click on the Button1 message box will display 555.55; that's why we need step 10 in the first example - we have initialized SomeNumber to 555.55 in the OnClick event of the Button1.

No we have two SomeNumber variables in our project and they both hold different values.

Obviously, we have to be careful when assigning values to unit-level variables. Although we can use the same variable (or constant) name for both local and unit-level variables, this is not a good idea. Any var (or const) declaration contained in a procedure takes precedence over global (unit-level) declarations. Duplicating the names makes the global variable invisible to the procedure (Delphi doesn't tell us whether a global variable has been defined with the same name as a local variable). That is why SomeNumber holds the 123,45 value in the OnCreate event handler of the form (we cannot use global variable SomeNumber in the OnCreate procedure)

Note 1: If you really have to use two variables with the same SomeNumber name (one global and one local), you can access the global SomeNumber variable value in the forms OnCreate procedure with the call to unit1. SomeNumber (unit1 is the name of the unit with the global SomeNumber variable). That is, something like
unit1.SomeNumber:=444.44;

will change value of the global variable SomeNumber inside OnCreate event handler of the form (remember that there is a SomeNumber variable local to this procedure which will stay unchanged)

Note 2: As global SomeNumber is global to the unit we can access (more important: change) its value from any other procedure inside this unit. However click to Button 1 will reset SomeNumber value to 555.55. Better way to initialize global variables is inside initialization section of the unit.

Global variables - program level scope

If we want to create true global variables (or/and constants) in a project, we have to place the declaration in the interface section of the unit. Variables declared in the interface section will be visible (accessible) to any unit which uses that unit.


For example, to change SomeNumber variable value that is declared in Unit1 from Unit2, use this statement:

Unit1.SomeNumber:=999.99;

.

WORKING WITH COMPONENTS

An introduction to Delphi VCL and a simple application.

As you probably know by now, components are essential elements of the Delphi environment. It's crucial for every Delphi beginner to understand what VCL has to offer.
Prior to understanding this article it will be good idea to read What is Delphi, and Delphi for Beginners: Getting started.

Overview

First of all, let's distinguish components from controls. Simply putt controls are those components that the user can see. Furthermore, Delphi distinguishes between windowed and nonwindowed (graphical) controls. The major distinction is that windowed controls can receive the focus and nonwindowed controls cannot.

The distinction between windowed and graphical controls can be important when you design your user interfaces. For example, if you create a tool bar that contains a large number of buttons, you could choose a nonwindowed speed-button component instead standard Windows button components. Non graphical controls consume fewer system resources.

Some components are visual components; others are nonvisual components. A visual component, is one that can be seen by the user at run time. Visual components include components such as edit controls, buttons, list boxes, labels, and so on. A nonvisual component is one that cannot be seen by the user at run time (system timers, database components, image lists, etc.) When you place a nonvisual component on a form, Delphi displays an icon representing the component on the form. This icon is used to access the component at design time in order to change the component's properties, but the icon does not show up when the program runs.

Depending on which version of Delphi you have, you start with more than 100 components. Each page tab in the Component palette displays a group of icons representing the components you can use to design your application interface.

 

Each component has a set of properties - such as color, size, position, caption - that can be modified in the Delphi IDE or in your code, and a collection of events - such as a mouse click, keypress, or component activation - for which you can specify some additional behavior (in event procedures).

Adding components to the form
To place a component on the form, click once on the desired component on the toolbar. Then move the mouse cursor over to the Form and click on the Form where you want the component to be. Repeat the same procedure with the rest of the components you wish to use.

Of course, you may want a component to be smaller or larger than the default size. To change the dimensions of the component simply stretch it using the mouse (in a way you deform any standard window). Take a moment to see that Height and Width property of that controls changes in the Object Inspector.

To move a component to a different location simply select a component (click on it) and drag it to its new location. Again, you are changing properties: Left, Top.
If you would like to cancel a design-time drag operation you've already begun, do the following: after you've begun the drag but before you release the mouse button, press the Esc key. The control will snap back to its original position!

Container components

Besides the form itself, Delphi provides several components-such as the group box, panel and page control that can contain other components. The idea of a container is that all the components will behave as one at design time. For example when you move a container component, the child components move with it. Once you have placed container component on the form, make sure that it is selected than add child components to the container as you normally would.

Simple application - My Second Delphi Program

This simple application will show you how to change some of the standard component properties at design and run-time.
When you change a component's properties through the Object Inspector and Form Designer, you are said to make a design-time change. When you modify a property through code that executes when the program runs, you are said to make a runtime change.

We will build our application in few steps, so here they are: 0. Start Delphi, and as we know, you are presented with both a blank form and the IDE.

1. Put one Label (TLabel is a nonwindowed control that displays text on a form.), Edit (TEdit is a standard Windows edit control) and a Button on the form -all components are on the Standard Page of components palette

2. Change form caption to 'My Second Delphi Program', Button caption to 'Copy text'. (this is not necessary for application - we are just design-time changing properties)

The idea is to change the text in Label component to the text in Edit component when the user clicks on the Button component.

3. Select the Button and click on the Events tab in the Object Inspector window. Double click in the right column of the item marked "OnClick".
4. Enter this code (marked red).
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption:=Edit1.Text;
end;


5. Now, run the project (F9), and notice that every time you click on the button, text in Label component changes to the text in Edit box. Of course, try to change the text in Edit box before clicking on the Button to see the results.

In that line of code, that we had to write down, is everything we need to accomplish desired task. We are run-time changing the Caption property of the Label so that it's the same as the Text property of the EditBox.

When you assign a value to a property, the value on the right side of the assignment statement is assigned to the property on the left side of the assignment statement. When a value is assigned, a copy of the value is placed into the property.

 

Loops in Delphi

Loops

The loop is a common element in all programming languages. Object Pascal has three control structures that execute blocks of code repeatedly: for, repeat-until and while-do.

The FOR loop

Suppose we need to repeat an operation a fixed number of times.

// show 1,2,3,4,5 message boxes
var i: integer;
begin
for i := 1 to 5 do
begin
ShowMessage('Box: '+IntToStr(i));
end;
end;

The value of a control variable (i), which is really just a counter, determines how many times a for statement runs. The keyword for sets up a counter. In the preceding example, the starting value for the counter is set to 1. The ending value is set to 5.

When the for statement begins running the counter variable is set to the starting value. Delphi than checks whether the value for the counter is less than the ending value. If the value is greater, nothing is done (program execution jumps to the line of code immediately following the for loop code block). If the starting value is less than the ending value, the body of the loop is executed (here: the message box is displayed). Finally, Delphi adds 1 to the counter and starts the process again.

Sometimes it is necessary to count backward. The downto keyword specifies that the value of a counter should be decremented by one each time the loop executes (it is not possible to specify an increment / decrement different than one). An example of a for loop that counts backward.

var i: integer;
begin
for i := 5 downto 1 do
begin
ShowMessage('T minus ' + IntToStr(i) + 'seconds');
end;
ShowMessage('For sequence executed!');
end;

It's important that you never change the value of the control variable in the middle of the loop. Doing so will cause errors.

Nested FOR loops

Writing a for loop within another for loop (nesting loops) is very useful when you want to fill / display data in a table or a grid.

var i,j: integer;
begin
//be aware:
//this double loop is executed 4x4=16 times
for i:= 1 to 4 do
for j:= 4 downto 1 do
ShowMessage('Box: '+
IntToStr(i)+ ',' +
IntToStr(j));
end;

The rule for nesting for-next loops is simple: the inner loop (j counter) must be completed before the next statement for the outer loop is encountered (i counter). We can have triply or quadruply nested loops, or even more.

Note: Generally, the begin and end keywords are not strictly required, as you can see. If begin and end are not used, the statement immediately following the for statement is considered the body of the loop.

The WHILE and REPEAT loops

Sometimes we won't know exactly how many times a loop should cycle. What if we want to repeat an operation until we reach a specific goal?

The most important difference between the while-do loop and the repeat-until loop is that the code of the repeat statement is always executed at least once.

The general pattern when we write a repeat (and while) type of loop in Delphi is as follows:

repeat
begin
statements;
end;
until condition = true


while condition = true do
begin
statements;
end;

Here goes the code to show 5 successive message boxes using repeat-until.

var i: integer;
begin
i:=0;
repeat
begin
i:=i+1;
ShowMessage('Box:'+IntToStr(i));
end;
until i>5;
end;

As we can see, the repeat statement evaluates a condition at the end of the loop (therefore repeat loop is executed for sure at least once).

The while statement, on the other hand, evaluates a condition at the beginning of the loop. Since the test is being done at the top, we will usually need to make sure that the condition makes sense before the loop is processed, if this is not true the compiler may decide to remove the loop from the code.

var i: integer;
begin
i:=0;
while i<5 do
begin
i:=i+1;
ShowMessage('Box:'+IntToStr(i));
end;
end;

Break and Continue

The Break and Continue procedures can be used to control the flow of repetitive statements: The Break procedure causes the flow of control to exit a for, while, or repeat statement and continue at the next statement following the loop statement. Continue allows the flow of control to proceed to the next iteration of repeating operation. See how they work.


 

STRING TYPES IN DELPHI

Understanding and managing string data types in Delphi's Object Pascal. Learn about differences between Short, Long, Wide and null-terminated strings.

As like in any programming language, in Delphi, variables are placeholders used to store values; they have names and data types. The data type of a variable determines how the bits representing those values are stored in the computer's memory.

When we have a variable that will contain some array of characters, we can declare it to be of type String.

Delphi provides a healthy assortment of string operators, functions and procedures. Before assigning a String data type to a variable, we need to thorughly understand Delphi's four string types.

Short String
Simply put, Short String is a counted array of (ANSII) characters, with up to 255 characters in the string. The first byte of this array stores the length of the string. Since this was the main string type in Delphi 1 (16 bit Delphi), the only reason to use Short String is for backward compatibility.
To create a ShortString type variable we use:

var s: ShortString;
s := 'Delphi Programming';
//S_Length := Ord(s[0]));
//which is the same as Length(s)

The s variable is a Short string variable capable of holding up to 256 characters, its memory is a statically allocated 256 bytes. Since this is usually wastefull - unlikely will your short string spread to the maximum length - second approach to using Short Strings is using subtypes of ShortString, whose maximum length is anywhere from 0 to 255.

var ssmall: String[50];
ssmall := 'Short string, up to 50 characters';



This creates a variable called ssmall whose maximum length is 50 characters.

Note: When we assign a value to a Short String variable, the string is truncated if it exceeds the maximum length for the type. When we pass short strings to some Delphi's string manipulationg routine, they are converted to and from long string.

String / Long / Ansi
Delphi 2 brought to Object Pascal Long String type. Long string (in Delphi's help AnsiString) represents a dynamically allocated string whose maximum length is limited only by available memory. All 32-bit Delphi versions use long strings by default. I recomend using long strings whenever you can.

var s: String;
s := 'The s string can be of any size...';


The s variable can hold from zero to any paractical number of characters. The string grows or shrinks as you assign new data to it.

We can use any string variable as an array of characters, the second character in s has the index 2. The following code

s[2]:='T';
assigns T to the second character os the s variable. Now the few of the first characters in s look like: TTe s str....

Don't be mislead, you can't use s[0] to see the length of the string, s is not ShortString.

Reference counting, copy-on-write

Since memory allocation is done by Delphi, we don't have to worry about garbage collection. When working with Long (Ansi) Strings Delphi uses reference counting. This way string copying is actually faster for long strings than for short strings.
Reference counting, by example:
var s1,s2: String;
s1 := 'first string';
s2 := s1;

When we create string s1 variable, and assign some value to it, Delphi allocates enough memory for the string. When we copy s1 to s2, Delphi does not copy the string value in memory, it ony increases the reference count and alters the s2 to point to the same memory location as s1.

To minimize copying when we pass strings to routines, Delphi uses copy-on-write techique. Suppose we are to change the value of the s2 string variable; Delphi copies the first string to a new memory location, since the change should affect only s2, not s1, and they are both pointing to the same memory location.

Wide String
Wide strings are also dynamically allocated and managed, but they don't use reference counting or the copy-on-write semantics. Wide strings consist of 16-bit Unicode characters.

About Unicode character sets

The ANSI character set used by Windows is a single-byte character set. Unicode stores each character in the character set in 2 bytes instead of 1. Some national languages use ideographic characters, which require more than the 256 characters supported by ANSI. With 16-bit notation we can represent 65,536 different characters. Indexing of multibyte strings is not reliable, since s[i] represents the ith byte (not necessarily the i-th character) in s.

If you must use Wide characters, you should declare a string variable to be of the WideString type and your character variable of the WideChar type. If you want to examine a wide string one character at a time, be sure to test for multibite characters. Delphi doesn't support automatic type conversions betwwen Ansi and Wide string types.

var s : WideString;
c : WideChar;

s := 'Delphi_ Guide';
s[8] := 'T';
//s='Delphi_TGuide';

Null terminated
A null or zero terminated string is an array of characers, indexed by an integer starting from zero. Since the array has no length indicator, Delphi uses the ASCII 0 (NULL; #0) character to mark the boundary of the string.

This means there is essentially no difference between a null-terminated string and an array[0..NumberOfChars] of type Char, where the end of the string is marked by #0.

We use null-terminated strings in Delphi when calling Windows API functions. Object Pascal lets us avoid messing arround with pointers to zero-based arrays when handling null-terminated strings by using the PChar type. Think of a PChar as being a pointer to a null-terminated string or to the array that represents one.

For example, The GetDriveType API function determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive. The following procedure lists all the drives and their types on a users computer. Place one Button and one Memo component on a form and asign an OnClick handler of a Button:

procedure TForm1.Button1Click(Sender: TObject);
var
Drive: Char;
DriveLetter: String[4];
begin
for Drive := 'A' to 'Z' do
begin
DriveLetter := Drive + ':\';
case GetDriveType(PChar(Drive + ':\')) of
DRIVE_REMOVABLE:
Memo1.Lines.Add(DriveLetter + ' Floppy Drive');
DRIVE_FIXED:
Memo1.Lines.Add(DriveLetter + ' Fixed Drive');
DRIVE_REMOTE:
Memo1.Lines.Add(DriveLetter + ' Network Drive');
DRIVE_CDROM:
Memo1.Lines.Add(DriveLetter + ' CD-ROM Drive');
DRIVE_RAMDISK:
Memo1.Lines.Add(DriveLetter + ' RAM Disk');
end;
end;
end;


Mixing Delphi's strings
We can freely mix all four different kinds of strings, Delphi will give it's best to make sence of what we are trying to do. The assignment s:=p, where s is a string variable and p is a PChar expression, copies a null-terminated string into a long string.

Character types

In addition to four string data types, Delphi has three character types: Char, AnsiChar, and WideChar. A string constant of length 1, such as 'T', can denote a character value. The generic character type is Char, which is equivalent to AnsiChar. WideChar values are 16-bit characters ordered according to the Unicode character set. The first 256 Unicode characters correspond to the ANSI characters.


 

FUNCTIONS AND PROCEDURES

Have you ever found yourself writing the same code over and over to perform some common task within event handlers? Yes! It's time for you to learn about programs within a program. Let's call those mini programs subroutines.

Intro to subroutines
Subroutines are an important part of any programming language, and Object Pascal is no exception. In Delphi, there are generally two types of subroutines: a function and a procedure. The usual difference between a function and a procedure is that a function can return a value, and a procedure generally will not do so. A function is normally called as a part of an expression.

Take a look at the following examples:

procedure SayHello(const sWhat:string);
begin
ShowMessage('Hello ' + sWhat);
end;

function YearsOld(const BirthYear:integer): integer;
var Year, Month, Day : Word;
begin
DecodeDate(Date, Year, Month, Day);
Result := Year - BirthYear;
end;

Once subroutines have been defined, we can call them one or more times.

procedure TForm1.Button1Click(Sender: TObject);
begin
SayHello('Delphi User');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
SayHello('TGuide');
ShowMessage('You are ' +
IntToStr(YearsOld(1973)) +
' years old!');
end;

Functions and Procedures
As we can see, both functions and procedures act like mini programs. In particular, they can have their own type, constants and variable declarations inside them.
Take a closer look at a (miscellaneous) SomeCalc function:

function SomeCalc
(const sStr: string;
const iYear, iMonth: integer;
var iDay:integer): boolean;
begin
...
end;

Every procedure or function begins with a header that identifies the procedure or function and lists the parameters the routine uses, if any. The parameters are listed within parentheses. Each parameter has an identifying name and usually has a type. A semicolon separates parameters in a parameter list from one another.

sStr, iYear and iMonth are called constant parameters. Constant parameters cannot be changed by the function (or procedure). The iDay is passed as a var parameter, and we can make changes to it, inside the subroutine.

Functions, since they return values, must have a return type declared at the end of the header. The return value of a function is given by the (final) assignment to its name. Since every function implicitly has a local variable Result of the same type as the functions return value, assigning to Result has the same effect as assigning to the name of the function.

Positioning and calling subroutines
Subroutines are always placed inside the implementation section of the unit. Such subroutines can be called (used) by any event handler or subroutine in the same unit that is defined after it. (I will write about recursions in some of future articles.)

Be aware: the uses clause of a unit tells you which units it can call. If we want a specific subroutine in a Unit1 to be usable by the event handlers or subroutines in another unit (say Unit2), we have to:

add a Unit1 to the uses clause of Unit2
place a copy of the header of the subroutine in the interface section of the Unit1.
This means that subroutines whose headers are given in the interface section are global in scope.

When we call a function (or a procedure) inside its own unit, we use its name with whatever parameters are needed. On other hand, if we call a global subroutine (defined in some other unit, e.g. MyUnit) we use the name of the unit followed by a period.

...
//SayHello procedure is defined inside this unit
SayHello('Delphi User');
//YearsOld function is defined inside MyUnit unit
Dummy := MyUnit.YearsOld(1973);

...

Note: Functions or procedures can have their own subroutines embedded inside them. An embedded subroutine is local to the container subroutine and cannot be used by other parts of the program. Something like:

procedure TForm1.Button1Click(Sender: TObject);
function IsSmall(const sStr:string):boolean;
begin
//IsSmall returns True if sStr is
in lowercase, False otherwise
Result:=LowerCase(sStr)=sStr;
end;
begin
//IsSmall can only be uses
inside Button1 OnClick event
if IsSmall(Edit1.Text) then
ShowMessage('All small caps in Edit1.Text')
else
ShowMessage('Not all small caps in Edit1.Text');
end;

Passing arrays

Delphi allows us to use open parameters for passing arrays to subprograms. This gives us the flexibility of passing array to a subroutine without needing to declare the array's limits. Open-array parameters can be constant and variable parameters.

The MakeZero procedure in the next example assigns zero to each element of an array of Double, Because the Arr parameter is an open-array parameter, the subroutine can operate on any array with an element type of Double.

procedure MakeZero(var Arr: Array of Double)
var i:integer;
begin
for i:= Low(Arr) to High(Arr) + 1 do Arr[i] := 0;
end;

Class Methods

A method is a procedure or function that performs an operation on an object. A class method is a method that operates on a class reference instead of an object reference.
If you read between the lines, you will find that class methods are accessible even when you haven't created an instance of the class (the object).

Like

procedure TfrMain.mnuInfoClick(Sender: TObject);
begin
AboutBox:=TAboutBox.Create(Application);
try
AboutBox.ShowModal;
finally
AboutBox.Release
end;
end;

This, of course, is a very nice way to do the job, but just to make the code easier to read, it would be much more efficient to change it to:

procedure TfrMain.mnuInfoClick(Sender: TObject);
begin
TAboutBox.ShowYoureself;
end;

Now

class procedure TAboutBox.ShowYoureself;
begin
AboutBox:= TAboutBox.Create(Application);
try
AboutBox.ShowModal;
finally
AboutBox.Release;
end;
end;

Conclusion

The definition of a class method must include the reserved word class before the procedure or function keyword that starts the definition. AboutBox form is not auto-created (Project-Options). Put AboutBox unit to the uses clause of the main form. Don't forget to declare the procedure in the interface (public) part of the AboutBox unit. Again, so what .If nothing else, we succeeded to reduce the code in the main form of application. On the other hand, think of this approach as a good way to create an object, use it, and destroy it immediately.

Routine in Delphi

Extending Object Pascal's functions and procedures with default (optional) parameters and method overloading.

As we know, functions and procedures are an important part of the Object Pascal language. Starting with Delphi 4, Object Pascal enables us to work with functions and procedures that support default parameters (making the parameters optional), and permits two or more routines to have identical name, but operate as totally different routines.
Let's see how Overloading and default parameters can help us code better...

Overloading

Simply put overloading is declaring more than one routine with the same name. Overloading allows us to have multiple routines that share the same name, but with different number of parameters and their types.

As an example, let's consider the following two functions:

{Overloaded routines must be declared
with the overload directive}
function SumAsStr(a, b :integer): string; overload;
begin
Result := IntToStr(a + b);
end;

function SumAsStr
(a, b : extended; Digits:integer): string; overload;
begin
Result := FloatToStrF(a + b, ffFixed, 18, Digits);
end;

These declarations create two functions, both called SumAsStr, that take different number of parameters, that are of different types. When we call an overloaded routine, the compiler must be able to tell which routine we want to call.
For example, SumAsStr(6, 3) calls the first SumAsStr function, because its arguments are integer-valued. On the other hand, if we try to call the SumAsStr function as follows:
SomeString := SumAsStr(6.0,3.0)

we'll get the following error: "there is no overloaded version of 'SumAsStr' that can be called with these arguments", meaning that we should also include the Digits parameter used to specify the number of digits after the decimal point.

Note: there is only one rule when writing overloaded routines: an overloaded routine must differ in at least one parameter type. The return type, instead, cannot be used to distinguish among two routines.

Two units - one routine
Let's say we have one routine in unit A, and unit B uses unit A, but declares a routine with the same name. The declaration in unit B does not need the overload directive: we should use unit A's name to qualify calls to A's version of the routine from unit B. Something like:

unit B;
...
uses A;
...
procedure RoutineName;
begin
Result := A.RoutineName;
end;

An alternative to using overloaded routines is to use default parameters, which usually results in less code to write and maintain.

Default parameters

In order to simplify some statements we can give a default value for the parameter of a function or procedure, and we can call the routine with or without the parameter, making it optional.
To provide a default value, end the parameter declaration with the = symbol followed by a constant expression.

For example, given the declaration
function SumAsStr
(a,b : extended; Digits : integer = 2): string;


the following function calls are equivalent.
SumAsStr(6.0, 3.0)

SumAsStr(6.0, 3.0, 2)

Note: parameters with default values must occur at the end of the parameter list, and must be passed by value or as const. A reference (var) parameter cannot have a default value.

When calling routines with more than one default parameter we cannot skip parameters (like in VB):

function SkipDefParams
(var A:string; B:integer=5, C:boolean=False):boolean;

...
//this call generates an error message
CantBe := SkipDefParams('delphi', , True);

Overloading with default parameters
When using both function or procedure overloading and default parameters, don't introduce ambiguous routine declarations.

Consider the following declarations:

procedure DoIt(A:extended; B:integer = 0); overload;

procedure DoIt(A:extended); overload;

The call to DoIt procedure like DoIt(5.0) does not compile. Because of the default parameter in the first procedure, this statement might call both procedures, because it is impossible to tell which procedure is meant to be called.

Records in Delphi

Sets are ok, arrays are great. Suppose we want to create three one-dimensional arrays for 50 members in our programming community. The first array is for names, the second for e-mails, and the third for number of uploads (components or applications) to our community. Each array (list) would have matching indexes and plenty of code to maintain all three lists in parallel. Of course, we could try with one three-dimensional array, but what about it's type? We need string for names and e-mails, but an integer for the number of uploads.

The way to work with such a data structure is to use Object Pascal's record structure.

An example
For example, the following declaration creates a record type called TMember, the one we could use in our case.

type
TMember = record
Name : string;
eMail : string;
Posts : Cardinal;
end;

Essentially, a record data structure can mix any of Delphi's built in types including any types you have created. Record types define fixed collections of items of different types. Each item, or field, is like a variable, consisting of a name and a type.

TMember type contains three fields: a string value called Name (to hold the name of a member), a value of a string type called eMail (for one e-mail), and an integer (Cardinal) called Posts (to hold the number of submitions to our community).

Once we have set up the record type, we can declare a variable to be of type TMember. TMember is now just as good variable type for variables as any of Delphi's built in types like String or Integer. Note: the TMember type declaration, does not allocate any memory for the Name, eMail, and Posts fields;
To actually create an instance of TMember record we have to declare a variable of TMember type, as in the following code:

var DelphiGuide, AMember : TMember;

Now, when we have a record, we use a dot to isolate the fields of DelphiGuide:

DelphiGuide.Name := 'Zarko Gajic';
DelphiGuide.eMail := 'delphi.guide@about.com';
DelphiGuide.Posts := 15;

Note: the above peace of code could be rewritten with the use of with keyword:

with DelphiGuide do begin
Name := 'Zarko Gajic';
eMail := 'delphi.guide@about.com';
Posts := 15;
end;

We can now copy the values of DelphiGuide's fields to AMember:

AMember := DelphiGuide;

Scope and visibility
Record type declared within the declaration of a form (implementation section), function, or procedure has a scope limited to the block in which it is declared. If the record is declared in the interface section of a unit it has a scope that includes any other units or programs that use the unit where the declaration occurs.
To learn more about Object Pascal variable scope go the Variable Scope article.

In arrays
Since TMember acts like any other Object Pascal type, we can declare an array of record variables:

var DPMembers : array[1..50] of TMember;

To access the fifth member we use:

with DPMembers[5] do begin
Name := 'First name Last';
eMail := 'FirstLast@domain.com'
Posts := 0;
end;

Or, to display information (e-mail, for example) about every member we could use:

var i: cardinal;

for i:= 1 to 50 do
ShowMessage(DPMembers[i].eMail);

Records as fields
Since a record type is legitimate as any other Delphi type, we can have a field of a record be a record itself. For example, we could create ExpandedMember to keep track of what the member is submitting along with the member information:

type
TExpandedMember = record
SubmitType : string;
Member : TMember;
end;

Filling out all the information needed for a single record is now somehow harder. More periods (dots) are required to access the fields of TExpandedMember:

var SubTypeMember :TExpandedMember;

SubTypeMember.SubmitType:='VCL';
SubTypeMember.Member.Name:='vcl Programmer';
SubTypeMember.Member.eMail:='vcl@about.com';
SubTypeMember.Member.Name:=555;

Conclusion

A record type can have a variant part (I don't mean Variant type variable). Variant records are used, for example, when we want to create a record type that has fields for different kinds of data, but we know that we will never need to use all of the fields in a single record instance. To learn more about Variant parts in Records take a look at Delphi's help files.

The use of a variant record type is not type-safe and is not a recommended programming practice, particularly for beginners.

Static and Multidimensional Arrays

The concept of arrays in Object pascal is simple: arrays allow us to refer to a series of variables by the same name and to use a number (an index) to tell them apart. Arrays have both upper and lower bounds, and the elements of the array are contiguous within those bounds.

Elements of the array are values that are all of the same type (string, integer, real).

In Delphi, there are two types of arrays: a fixed-size array which always remains the same size - static array, and a dynamic array whose size can change at run-time.

Static Arrays

Suppose we are writing a program that lets a user enter some values (e.g. the number of appointments) at the beginning of each day. We would choose to store the information in a list. We could call this list Appointments, and each number might be stored as Appointments[1], Appointments[2], an so on.

To use the list, we must first declare it. For example:

var Appointments : array[0..6] of Integer;

declares a variable called Appointments that holds an one-dimensional array (vector) of 7 integer values. Given this declaration, Appointments[3] denotes the third integer value in Appointments. The number in the brackets is called the index.

If we create a static array but don't assign values to all its elements, the unused elements contain random data; they are like uninitialized variables. The following code can be used to set all elements in the Appointments array to 0.

for i := 0 to 6 do Appointments[i] := 0;

Sometimes we need to keep track of related information in an array. For example, to keep track of each pixel on your computer screen, you need to refer to its X and Y coordinates. This can be done using a multidimensional array to store the values.

With Delphi, we can declare arrays of multiple dimensions. For example, the following statement declares a two-dimensional 7 by 24 array:

var DayHour : array[1..7, 1..24] of Real;

To compute the number of elements in a multidimensional array, multiply the number of indexes. The DayHour variable, declared above, sets aside 168 (7*24) elements, in 7 rows and 24 columns.

To retreive the value from cell in the third row and seventh column we would use: DayHour[3,7] or DayHour[3][7]. The following code can be used to set all elements in the DayHour array to 0.

for i := 1 to 7 do
for j := 1 to 24 do
DayHour[i,j] := 0;

Dynamic Arrays

Sometimes you may not know exactly how large to make an array. You may want to have the capability of changing the size of the array at run time.
Delphi 4 introduced the concept of dynamic arrays in Object Pascal. A dynamic array declares its type, but not its size. The actual size of a dynamic array can be changed at run time by the use of the SetLength procedure.

For example, the following variable declaration

var Students : array of string;

creates a one-dimensional dynamic array of strings.
The declaration does not allocate memory for Students. To create the array in memory, we call SetLength procedure. For example, given the declaration above,

SetLength(Students, 14);

allocates an array of 14 strings, indexed 0 to 13. Dynamic arrays are always integer-indexed, always starting from 0 to one less than their size in elements.

To create a two-dimensional dynamic array, use the following code:

var Matrix: array of array of Double;
begin
SetLength(Matrix, 10, 20)
end;

which allocates space for a two-dimensional, 10 x 20, array of Double floating-point values.

Note: To remove a dynamic array's memory space we assign nil to the array variable, like:

Matrix := nil;

Very often, your program doesn't know at compile time how many elements will be needed, that number will not be known until runtime. With dynamic arrays you can allocate only as much storage as is required at a given time. In other words, the size of dynamic arrays can be changed at run time, which is one of the key advantages to dynamic arrays. The next code creates an array of integer values and then calls the Copy function to resize the array.

var Vector: array of Integer;
i : integer;
begin
SetLength(Vector, 10);
for i := Low(Vector) to High(Vector) do
Vector[i] := i*10;

...
//now we need more space
SetLength(Vector, 20);
//here, Vector array can hold up to 20 elements
//(it already has 10 of them)
end;

Conclusion:

SetLength function creates a larger (or smaller) array, and copies the existing values to the new array. The Low and High functions ensure you access every array element without looking back in your code for the correct lower and upper index values.

Errors and Exceptions

"The most bug-free line of code is the one you don't have to write."

Unfortunately, building applications includes coding. Regardless of how carefully you write/debug your program, it will be impossible to imagine every situation that can go wrong. Inexperienced user might, for example, try to open a nonexisting file or input a bad value into a data field.
Users make mistakes and we should be prepared to handle/prevent these errors wherever and whenever possible.

Errors, Exceptions

An exception is generally an error condition or other event that interrupts normal flow of execution in an application. Whenever an error results from processing a line of code, Delphi creates (raises) an object descendent from TObject called the exception object.

Guarded Blocks
An application responds to an exception either by executing some termination code, handling the exception, or both. The way to enable error/exception trapping within a given code, the exception must occur within a guarded block of statements. The general code looks like:

try
{guarded block of code}
except
on <ESomeException> do begin
{exception block-handles SomeException}
end;
end;

A try...except statement executes the statements in the guarded block of code. If the statements execute without any exceptions being raised, the exception block is ignored, and control is passed to the statement following the end keyword.

Example:
...
Zero:=0;
try
dummy:= 10 / Zero;
except
on EZeroDivide do
MessageDlg('Can not divide by zero!',
mtError, [mbOK], 0);
end;
...

Protecting Resources

When a section of code acquires a resource, it is often necessary to ensure that the resource is released again, regardless of whether the code completes normally or is interrupted by an exception. In this case, the syntax uses finally keyword and looks like:

{some code to allocate resources}
try
{guarded block of code}
finally
{termination blok - code to free resources}
end;

Example:
...
AboutBox:=TAboutBox.Create(Self);
try
AboutBox.ShowModal;
finally
AboutBox.Release;
end;

Application.OnException

If your application doesn't handle the error that caused the exception, then Delphi will use its default exception handler - it will just pop up a message box. You may consider writing code in the OnException event for TApplication object, in order to trap errors at the application level.

Break On Exceptions

When building a program with exception handling, you may not want Delphi to break on Exceptions. This is a great feature if you want Delphi to show where an exception has occurred; however, it can be annoying when you test your own exception handling.

Few final words

The idea of this article is to give you just a quick look at what exceptions are. For further discussion on exception handling, consider some of the following:

Text Files in Delphi

Simply put, text files contain readable ASCII characters. We can think of working with text file in Delphi as analogous to playing or recording information on a cassette tape.

Although it is possible to make changes within text file, jump around when processing information or add some data to the file other than at the end, it is advisable to use a text file only when we know that we are working with ordinary text and no such operations are necessary.

Text files are considered to represent a sequence of characters formatted into lines, where each line is terminated by an end-of-line marker (a carriage-return / linefeed combination). Just think of Win.ini or Autoexec.bat.

Assign In order to start working with text files from Delphi we have to link a file on a disk to a file variable in our program. To create this link we must first declare a variable of type TextFile and then use AssignFile procedure in order to associate a file on a disk with a file variable.

...
var
SomeTxtFile : TextFile;
begin
AssignFile(SomeTxtFile, FileName)

...

Note: Unless the file named FileName is in the current directory, we need to provide enough information to identify its path. Be sure that value of a text variable has a legal Windows filename.

Reading information from a Text File

If we want to read back the contest of a file into a string list, our task is easy. Just one line of code will do the job.

Memo1.Lines.LoadFromFile('c:\autoexec.bat')
...

On the other hand, to read information from a file line by line, we must open the file for input by using the Reset procedure. The Reset opens the existing file with the name assigned to TextFile variable. An error results if no existing external file of the given name exists.

Once a file is reset, we can use ReadLn to read information from a file:

...
var
SomeTxtFile : TextFile;
buffer : string;
begin
AssignFile(SomeTxtFile, 'c:\autoexec.bat');
Reset(SomeTxtFile);
ReadLn(SomeTxtFile, buffer);
Memo1.Lines.Add(buffer);
CloseFile(SomeTxtFile);
end;

...

Procedure called ReadLn, reads one line of text from a file then moves to the next line.

After adding one line of text from a file to a memo component SomeTxtFile needs to be closed. This is done by the Close keyword.

Note: We can also use Read procedure to read information from a file. Read works just like ReadLn, except it does not move the pointer to the next line. As the next example shows, we can use multiple variables in each Read statement:

var
SomeTxtFile : TextFile;
buf1,buf2 : string[5];
begin
AssignFile(SomeTxtFile, 'c:\autoexec.bat');
Reset(SomeTxtFile);
ReadLn(SomeTxtFile, buf1,buf2);
ShowMessage(buf1 + ' ' +buf2);
CloseFile(SomeTxtFile);
end;

The EOF
Eof is the EndOfFile checking function. We can use this function to make sure that we are not trying to read beyond the end of the file. Let's say we want to display the contest of the file in message boxes - one line at a time, until we get to the end of a file:

var
SomeTxtFile : TextFile;
buffer : string;
begin
AssignFile(SomeTxtFile, 'c:\autoexec.bat');
Reset(SomeTxtFile);
while not EOF(SomeTxtFile) do begin
ReadLn(SomeTxtFile, buffer);
ShowMessage(buffer);
end;
CloseFile(SomeTxtFile);
end;

Note: It is better to use While loop than an Until loop to take into account the (unlikely) possibility that the file exists but does not contain any data.

Sending information to a Text File

Writing text to a file is as easy as reading text from a file. The WriteLn command is probably the most common way to send individual pieces of information to a file. The following code will read a text from a Memo1 component (line by line) and send it to some newly created text file.

var
SomeTxtFile : TextFile;
i: integer;
begin
AssignFile(SomeTxtFile, 'c:\MyTextFile.txt');
Rewrite(SomeTxtFile);
for i := 0 to (Memo1.Lines.Count - 1) do
WriteLn(SomeTxtFile, Memo1.Lines[i]);
CloseFile(SomeTxtFile);
end;


Depending on the state of the file provided to the Rewrite procedure in the previous example, the Rewrite creates a new file (opens the file for output) with the name assigned to SomeTextFile. If a file with the same name already exists, it is deleted and a new empty file is created in its place. If SomeTextFile is already open, it is first closed and then re-created. The current file position is set to the beginning of the empty file.

Note: Memo1.Lines.SaveToFile('c:\MyTextFile.txt') will do the same.

Sometimes we'll just need to add some text data to the end of an existing file. If this is the case, we'll call Append to ensure that a file is opened with write-only access with the file pointer positioned at the end of the file. Something like:

var
SomeTxtFile : TextFile;
begin
AssignFile(SomeTxtFile, 'c:\MyTextFile.txt');
Append(SomeTxtFile);
WriteLn(SomeTxtFile, 'New line in my text file');
CloseFile(SomeTxtFile);
end;

Be aware In general, you should always use exception handling when working with files. I/O is full of surprises. Always use CloseFile in a finally block to avoid the possibility of corrupting a user's FAT. All the previous examples should be rewritten as follows:

var
SomeTxtFile : TextFile;
buffer : string;
begin
AssignFile(SomeTxtFile, 'c:\MyTextFile.txt');
try
Reset(SomeTxtFile);
ReadLn(SomeTxtFile, buffer);
finally
CloseFile(SomeTxtFile);
end;
end;

To be sure that a given file exists we have to use FileExists boolean function. This function will return True if the file exists, Else otherwise. The syntax is

function FileExists(const FileName: string): boolean

Conclusion

Delphi has the ability to handle both ASCII files and files that hold binary data. Next time we will see the techniques for working with typed and untyped (binary) files.

Conclusion

Delphi is the first programming language to shatter the barrier between high-level, easy-to-use rapid application development environments and low-level bits-and-bytes power tools.

Delphi provides all the tools you need to develop, test and deploy Windows applications, including a large number of so-called reusable components.
Borland Delphi, in it's latest version, provides a cross platform solution when used with Borland Kylix - Borland's RAD tool for the Linux platform.

Delphi Personal - makes learning to develop non-commercial Windows applications fast and fun. Delphi 6 Personal makes learning Windows development easy with drag-and-drop visual programming.

Delphi Professional - adds the tools necessary to create applications with the latest Windows® ME/2000 look-and-feel. Dramatically enhance functionality with minimal code using the power and flexibility of SOAP and XML to easily integrate Web Services into client-side applications.

Delphi ships in a variety of configurations aimed at both departmental and enterprise needs. With Delphi, you can write Windows programs more quickly and more easily than was possible ever before.

Now that you've gotten free know-how on this topic, try to grow your skills even faster with online video training. Then finally, put these skills to the test and make a name for yourself by offering these skills to others by becoming a freelancer. There are literally 2000+ new projects that are posted every single freakin' day, no lie!


Previous Article

Next Article


Amparo's Comment
This paragraph gives clear idea in support of the new people of blogging, that actually how to do blogging. descuentos on line https://500px.com/codigopromocional http://priokish.blogspot.com/ http://randycateshorsetraner.blogspot.com/ https://github.com/codigopromocional/descuentos/wiki
04 Tue Jul 2017
Admin's Reply:



Yuli's Comment
Mueller Yes, I know there is an overload for copy, but thknas anyway @Xepol Exceptions should NOT be used to control code behavior. That being said, exceptions would not be thrown if you do everything correctly from the start. If, you make a mistake and pass 0 it would notify you. I see this as the best tool to avoid more complex mistakes. Sometimes you may pass 0 even if you did not indent to which would result in a silent failure .@Frank We're not talking about Delphi pro's here Think about many new developers which come from strict environments. That can be really hard for them. Knowing each side-effect is a daunting task.@Ralph I did not say it's a side-effect per-se. It can lead to side-effects if you're new to Delphi and simply do not read the documentation (which happens a lot since the name of the function + parameters say a lot themselves).I believe there are 2 schools of thought here, first The library assumes you know what you are doing and if not, it's your fault. And the second the library tends to always assume the worst about programmers and tends to make as many checks as possible to avoid side-effects.While I love freedom, sometimes having something/someone watch over your back is also a good thing.
09 Wed Jan 2013
Admin's Reply:



Jared's Comment
Excellent work hey ... Really helping me, writing Delphi prac tomorro :D
16 Wed Nov 2011
Admin's Reply:

 best of luck Jared :)




hamid's Comment
je veut de plus en plus de details
25 Sun Sep 2011
Admin's Reply:

 Hamid

you can explore the site :) hopefully you will find more detail




Katherine's Comment
Good to see a tnlaet at work. I can't match that.
31 Sun Jul 2011
Admin's Reply:

 thank you katherine




anam's Comment
thank
18 Mon Jul 2011
Admin's Reply:

 thank you very much anam




Edwin's Comment
Have you thought about my request on how to make sounds in Delphi 7 ?
27 Fri May 2011
Admin's Reply:

Thanks for your question, if i know answer i will reply. Surendra Gupta




Edwin Rickson's Comment
Not sure if this is the correct way of going about it..., but I have a problem & maybe you can help. How do I sound a beep (or other sounds) in Delphi ver 7 ? Thank you.
24 Sun Apr 2011
Admin's Reply:

if I know the answer, I'll be happy to help.




http://pickatutorial.com .'s Comment
Good work. keep it up.
05 Fri Nov 2010
Admin's Reply:

Thanks




Clement's Comment
JUST LEARNING
10 Sat Jul 2010
Admin's Reply:

Hope your learning goes beyond expectations.




efren's Comment
thank you for the articles and information you had posted online. I learn many things.
07 Wed Jul 2010
Admin's Reply:

I'm glad to hear that.

You should get your friends to come here too.




Hitesh Vaghani's Comment
Good tips
17 Thu Dec 2009
Admin's Reply:

Thanks






Facebook