Lazarus教程 中文版后续给出

市面上有介绍Delphi的书籍(近来Delphi的书也是越来越少了),但没有一本系统的介绍Lazarus的书,这本书是网上的仅有的一本Lazarus教程,目前全部是英文,不过我已经着手开始翻译,争取尽快翻译完供大家学习!(原书来自 freepascal.org )

code.sd
28.Sept.2013

Introduction
This book is written for programmers who want to learn the Object Pascal Language. It is also suitable
as a first programming book for new students and non-programmers. It illustrates programming
techniques in general in addition to the Object Pascal Language.
The Object Pascal Language
The first appearance of the Pascal Language supporting Object Oriented programming was in 1983 by
Apple computer company. After that Borland supported Object Oriented programming for their famous
Turbo Pascal line.
Object Pascal is a general purpose hybrid (structured and object oriented programming) language. It
can be used for a vast range of applications, like learning, game development, business applications,
Internet applications, communication applications, tools development, and OS kernels.
Delphi
After the success of Turbo Pascal, Borland decided to port it to Windows and introduced component
driven technology to it. Soon Delphi became the best RAD (Rapid Application Development) tool at
that time.
The first version of Delphi was released in 1995 with a rich set of components and packages that
supported Windows and Database applications development.
Free Pascal
After Borland dropped support for the Turbo Pascal line, the Free Pascal team started an open source
project to write a compatible compiler for Turbo Pascal from scratch, and then make it compatible with
Delphi. This time the Free Pascal compiler was targeting additional platforms and operating systems
like Windows, Linux, Mac, ARM, and WinCE.
Version 1.0 of the Free Pascal compiler was released in July 2000.

Lazarus
Free Pascal is a compiler, and it lacks an Integrated Development Environment (IDE) similar to the
Delphi IDE for Windows. The Lazarus project was started to provide an IDE for Free Pascal. It
provides a source code editor, debugger, and contains a lot of frameworks, packages, and component
libraries similar to the Delphi IDE.
Version 1.0 of Lazarus has released on August 2012, but there are a lot of applications developed with
beta versions of Lazarus. A lot of volunteers write packages and components for Lazarus, and the
community is growing.
Object Pascal features
Object Pascal is a very easy and readable language for beginners, its compilers are very fast, and the
applications it produces are reliable, fast and can be compared with C, and C++. You can write robust
and large applications with its IDEs (Lazarus and Delphi) without complexity.
Author:
Motaz Abdel Azeem
I am graduated from Sudan University of Science and Technology in 1999. and I started learning
Pascal as a second language after BASIC. Since then, I've been using it continuously, and I found it a
very easy and powerful tool, specially after I studied C, and C++. Then I moved to Delphi. I have
developed using Delphi for long time. Later I have studied Java and I'm using it now specially for web
services, and Free Pascal/Lazarus for desktop applications.
I live in Khartoum. My main job is a software developer.
First Editor
Pat Anderson graduated from Western Washington State College in 1968 and Rutgers Law School in
1975. He works as the City Attorney of Snoqualmie, Washington. Pat began programming on a Radio
Shack TRS-80 Model III in 1982 with the built-in BASIC interpreter, but soon discovered Turbo
Pascal. He has owned all versions of Turbo Pascal from 4.0 to 7.0, and every version of Delphi from
1.0 to 4.0. Pat took a hiatus from programming from 1998 until 2009, when he came upon Free Pascal /
Lazarus, which reignited his passion for programming.
Second Editor
Jason Hackney is a graduate of Western Michigan University's
College of Aviation. He works full-time as a professional pilot for a
power company based in southeast Michigan. Jason has been a casual

programmer since his first exposure to the Commodore 64 around 1984.
Briefly introduced to Turbo Pascal in 1990, he recently rekindled
latent programming interest after discovering Linux, Lazarus, and Free
Pascal.
License:
The License for this book is Creative Commons.
Environment for book examples
We will use Lazarus and Free Pascal for all the examples in this book. You can get the Lazarus IDE,
including the Free Pascal compiler, from this site: http://lazarus.freepascal.org.
If you are using Linux, then you can get Lazarus from the software repository. In Ubuntu you can use
the command:
sudo apt-get install lazarus
In Fedora you can use the command:
yum install lazarus
Lazarus is a free and open source application. And it is available on many platforms. Applications
written in Lazarus can be re-compiled on another platform to produce executables for that platform. For
example if you write an application using Lazarus in Windows, and you want to produce a Linux
executable for that application, you only need to copy your source code to Lazarus under Linux, then
compile it.
Lazarus produces applications that are native to each operating system, and it does not require any
additional libraries or virtual machines. For that reason, it is easy to deploy and fast in execution.
Using Text mode
All examples in the first chapters of this book will be console applications (text mode applications/
command line applications), because they are easy to understand and standard. Graphical user interface
applications will be introduced in later chapters.

Introduction...............................................................................................................................................2
The Object Pascal Language.....................................................................................................................2
Delphi........................................................................................................................................................2
Free Pascal................................................................................................................................................2
Lazarus......................................................................................................................................................3
Object Pascal features...............................................................................................................................3
Author: Motaz Abdel Azeem......................................................................................................................3
First Editor................................................................................................................................................3
Second Editor.............................................................................................................................................3
License:......................................................................................................................................................4
Environment for book examples................................................................................................................4
Using Text mode ........................................................................................................................................4
Contents
Chapter One
Language Basics
Our First Application...............................................................................................................................10
Other examples........................................................................................................................................12
Variables..................................................................................................................................................14
Sub types..................................................................................................................................................18
Conditional Branching............................................................................................................................19
The If condition........................................................................................................................................19
Air-Conditioner program:.......................................................................................................................19
Weight program........................................................................................................................................21
Case .. of statement..................................................................................................................................24
Restaurant program.................................................................................................................................24
Restaurant program using If condition....................................................................................................25
Students' Grades program.......................................................................................................................26
Keyboard program...................................................................................................................................26
Loops........................................................................................................................................................28
For loop...................................................................................................................................................28
Multiplication Table using for loop.........................................................................................................29
Factorial program...................................................................................................................................30

Repeat Until loop.....................................................................................................................................31
Restaurant program using Repeat loop...................................................................................................31
While loop................................................................................................................................................33
Factorial program using while loop........................................................................................................33
Strings......................................................................................................................................................35
Copy function...........................................................................................................................................38
Insert procedure.......................................................................................................................................39
Delete procedure......................................................................................................................................40
Trim function............................................................................................................................................40
StringReplace function.............................................................................................................................41
Arrays......................................................................................................................................................43
Records....................................................................................................................................................46
Files.........................................................................................................................................................48
Text files...................................................................................................................................................49
Reading text file program........................................................................................................................49
Creating and writing into text file............................................................................................................51
Appending to a text file............................................................................................................................54
Add to text file program...........................................................................................................................54
Random access files.................................................................................................................................55
Typed files................................................................................................................................................55
Marks program........................................................................................................................................55
Reading student marks.............................................................................................................................56
Appending student marks program..........................................................................................................57
Create and append student marks program.............................................................................................58
Cars database program...........................................................................................................................59
File copying.............................................................................................................................................61
Copy files using file of byte......................................................................................................................61
Untyped files............................................................................................................................................63
Copy files using untyped files program...................................................................................................63
Display file contents program..................................................................................................................65
Date and Time..........................................................................................................................................67
Date/time comparison..............................................................................................................................69
News recorder program...........................................................................................................................70
Constants.................................................................................................................................................72

Fuel Consumption program.....................................................................................................................72
Ordinal types............................................................................................................................................74
Sets...........................................................................................................................................................76
Exception handling..................................................................................................................................78
Try except statement................................................................................................................................78
Try finally.................................................................................................................................................79
Raise an exception..................................................................................................................................80
Chapter Two
Structured Programming
Introduction.............................................................................................................................................83
Procedures...............................................................................................................................................83
Parameters...............................................................................................................................................84
Restaurant program using procedures.....................................................................................................85
Functions.................................................................................................................................................86
Restaurant program using functions........................................................................................................87
Local Variables........................................................................................................................................88
News database application......................................................................................................................89
Functions as input parameters................................................................................................................92
Procedure and function output parameters.............................................................................................93
Calling by reference.................................................................................................................................94
Units.........................................................................................................................................................96
Units in Lazarus and Free Pascal...........................................................................................................98
Units written by the programmer.............................................................................................................98
Hejri Calendar.........................................................................................................................................99
Procedure and function Overloading....................................................................................................102
Default value parameters......................................................................................................................103
Sorting....................................................................................................................................................104
Bubble sort algorithm............................................................................................................................104
Sorting students' marks..........................................................................................................................106
Selection Sort algorithm........................................................................................................................107
Shell sort algorithm...............................................................................................................................109
String sorting..........................................................................................................................................111

Sorting students name program..............................................................................................................111
Sort algorithms comparison...................................................................................................................112
Chapter Three
The Graphical User Interface
Introduction............................................................................................................................................117
Our First GUI application.....................................................................................................................117
Second GUI application........................................................................................................................122
ListBox application................................................................................................................................124
Text Editor Application..........................................................................................................................125
News Application...................................................................................................................................127
Application with a Second form.............................................................................................................128
Chapter Four
Object Oriented
Programming
Introduction...........................................................................................................................................130
First example: Date and Time...............................................................................................................130
News application in Object Oriented Pascal.........................................................................................135
Queue Application.................................................................................................................................141
Object Oriented File..............................................................................................................................145
Copy files using TFileStream.................................................................................................................146
Inheritance.............................................................................................................................................147

Chapter One
Language Basics

Our First Application
After installing and running Lazarus, we can start a new program from the main menu:
Project/New Project/Program
We will get this code in the Source Editor window:
program Project1;
{mode objfpc}{$H+} uses   {$IFDEF UNIX}{$IFDEF UseCThreads}   cthreads,   {$ENDIF}{$ENDIF}   Classes   { you can add units after this }; {$IFDEF WINDOWS}{$R project1.rc}{$ENDIF} begin end. We can save this program by clicking File/Save from the main menu, and then we can name it, for example, first.lpi Then we can write these lines between the begin and end statements: Writeln('This is Free Pascal and Lazarus'); Writeln('Press enter key to close'); Readln; The complete source code will be: program first; {$mode objfpc}{$H+} uses   {$IFDEF UNIX}{$IFDEF UseCThreads}   cthreads,   {$ENDIF}{$ENDIF}   Classes   { you can add units after this }; {$IFDEF WINDOWS}{$R first.rc}{$ENDIF}   begin   Writeln('This is Free Pascal and Lazarus');   Writeln('Press enter key to close');   Readln; end. The Writeln statement displays the text on the screen (Console window). Readln halts execution to let the user read the displayed text until he/she presses enter to close the application and return to the Lazarus IDE. Then press F9 to run the application or click the button: After running the first program, we will get this output text: This is Free Pascal and Lazarus Press enter key to close If we are using Linux, we will find a new file in a program directory called (first), and in Windows we will get a file named first.exe. Both files can be executed directly by double clicking with the mouse. The executable file can be copied to other computers to run without the need of the Lazarus IDE. Notes If the console application window does not appear, we can disable the debugger from the Lazarus menu: Environment/Options/Debugger In Debugger type and path select (None)   Other examples In the previous program change this line: Writeln('This is Free Pascal and Lazarus'); to this one: Writeln('This is a number: ', 15); Then press F9 to run the application. You will get this result: This is a number: 15 Change the previous line as shown below, and run the application each time: Code: Writeln('This is a number: ', 3 + 2); Output: This is a number: 5 Code: Writeln('5 * 2 = ', 5 * 2); Output: 5 * 2 = 10 Code: Writeln('This is real number: ', 7.2); Output:   This is real number: 7.2000000000000E+0000 Code: Writeln('One, Two, Three : ', 1, 2, 3); Output: One, Two, Three : 123 Code: Writeln(10, ' * ', Output: 10 * 3 = 30 We can write different values in the Writeln statement each time and see the result. This will help us understand it clearly. 3 , ' = ', 10 * 3);   Variables Variables are data containers. For example, when we say that X = 5, that means X is a variable, and it contains the value 5. Object Pascal is a strongly typed language, which means we should declare a variable's type before putting values into it. If we declare X as an integer, that means we should put only integer numbers into X during its life time in the application. Examples of declaring and using variables: program FirstVar; {$mode objfpc}{$H+} uses   {$IFDEF UNIX}{$IFDEF UseCThreads}   cthreads,   {$ENDIF}{$ENDIF}   Classes   { you can add units after this }; var   x: Integer; begin   x:= 5;   Writeln(x * 2);   Writeln('Press enter key to close');   Readln; end. We will get 10 in the application's output. Note that we used the reserved word Var, which means the following lines will be variable declarations: x: Integer; This means two things:    1. The variable's name is X; and    2. the type of this variable is Integer, which can hold only integer numbers without a fraction. It       could also hold negative values as well as positive values. And the statement: x:= 5;   means put the value 5 in the variable X. In the next example we have added the variable Y: var   x, y: Integer; begin   x:= 5;   y:= 10;   Writeln(x * y);   Writeln('Press enter key to close');   Readln; end. The output of the previous application is: 50 Press enter key to close 50 is the result of the formula (x * y). In the next example we introduce a new data type called character: var   c: Char; begin   c:= 'M';   Writeln('My first letter is: ', c);   Writeln('Press enter key to close');   Readln; end. This type can hold only one letter, or a number as an alphanumeric character, not as value. In the next example we introduce the real number type, which can have a fractional part: var   x: Single; begin   x:= 1.8;   Writeln('My Car engine capacity is ', x, ' liters');   Writeln('Press enter key to close');   Readln; end.   To write more interactive and flexible applications, we need to accept input from the user. For example, we could ask the user to enter a number, and then get this number from the user input using the Readln statement / procedure: var   x: Integer; begin   Write('Please input any number:');   Readln(x);   Writeln('You have entered: ', x);   Writeln('Press enter key to close');   Readln; end.   In this example, assigning a value to X is done through the keyboard instead of assigning it a constant value in the application. In the example below we show a multiplication table for a number entered by the user: program MultTable; {$mode objfpc}{$H+} uses   {$IFDEF UNIX}{$IFDEF UseCThreads}   cthreads,   {$ENDIF}{$ENDIF}   Classes   { you can add units after this }; var   x: Integer; begin   Write('Please input any number:');   Readln(x);   Writeln(x, ' * 1 = ', x * 1);   Writeln(x, ' * 2 = ', x * 2);   Writeln(x, ' * 3 = ', x * 3);   Writeln(x, ' * 4 = ', x * 4);   Writeln(x, ' * 5 = ', x * 5);   Writeln(x, ' * 6 = ', x * 6);   Writeln(x, ' * 7 = ', x * 7);   Writeln(x, ' * 8 = ', x * 8);   Writeln(x, ' * 9 = ', x * 9);   Writeln(x, ' * 10 = ', x * 10);   Writeln(x, ' * 11 = ', x * 11);   Writeln(x, ' * 12 = ', x * 12);   Writeln('Press enter key to close');     Readln; end. Note that in the previous example all the text between single quotation marks (') is displayed in the console window as is, for example:   ' * 1 = ' Variables and expressions that are written without single quotation marks are evaluated and written as values. See the difference between the two statements below: Writeln('5 * 3'); Writeln(5 * 3); The result of first statement is: 5*3 Result of the second statement is evaluated then displayed: 15 In the next example, we will do mathematical operations on two numbers (x, y), and we will put the result in a third variable (Res): var   x, y: Integer;   Res: Single; begin   Write('Input a number: ');   Readln(x);   Write('Input another number: ');   Readln(y);   Res:= x / y;   Writeln(x, ' / ', y, ' = ', Res);   Writeln('Press enter key to close');   Readln; end.  Since the operation is division, it might result in a number with a fraction, so for that reason we have declared the Result variable (Res) as a real number (Single). Single means a real number with single precision floating point.   Sub types There are many sub types for variables, for example, Integer number subtypes differ in the range and the number of required bytes to store values in memory. The table below contains integer types, value ranges, and required bytes in memory: Type Byte ShortInt SmallInt Word Integer LongInt Cardinal Int64 Min value 0 -128 -32768 0 -2147483648 -2147483648 0 -9223372036854780000 Max Value 255 127 32767 65535 2147483647 2147483647 4294967295 9223372036854775807 Size in Bytes 1 1 2 2 4 4 4 8 We can get the minimum and maximum values and bytes sizes for each type by using the Low, High, and SizeOf functions respectively, as in the example below: program Types; {$mode objfpc}{$H+} uses   {$IFDEF UNIX}{$IFDEF UseCThreads}   cthreads,   {$ENDIF}{$ENDIF}   Classes; begin   Writeln('Byte: Size = ', SizeOf(Byte),    ', Minimum value = ', Low(Byte), ', Maximum value = ',    High(Byte)); Writeln('Integer: Size = ', SizeOf(Integer),   ', Minimum value = ', Low(Integer), ', Maximum value = ',   High(Integer));   Write('Press enter key to close');   Readln; end.   Conditional Branching One of the most important features of intelligent devices (like computers, programmable devices) is that they can take actions in different conditions. This can be done by using conditional branching. For example, some cars lock the door when the speed reaches or exceeds 40 K/h. The condition in this case will be: If speed is >= 40 and doors are unlocked, then lock door. Cars, washing machines, and many other gadgets contains programmable circuits like micro controllers, or small processors like ARM. Such circuits can be programmed using assembly, C, or Free Pascal according to their architecture. The If condition The If condition statement in the Pascal language is very easy and clear. In the example below, we want to decide whether to turn on the air-conditioner or turn it off, according to the entered room temperature: Air-Conditioner program: var   Temp: Single; begin   Write('Please enter Temperature of this room :');   Readln(Temp);   if Temp > 22 then     Writeln('Please turn on air-condition')   else     Writeln('Please turn off air-condition');   Write('Press enter key to close');   Readln; end. We have introduced the if then else statement, and in this example: if the temperature is greater than 22, then display the first sentence:: Please turn on air-conditioner else, if the condition is not met (less than or equal to 22) , then display this line: Please turn off air-conditioner   We can write multiple conditions like: var   Temp: Single; begin   Write('Please enter Temperature of this room :');   Readln(Temp);   if Temp > 22 then     Writeln('Please turn on air-conditioner')   else   if Temp < 18 then     Writeln('Please turn off air-conditioner')   else     Writeln('Do nothing'); You can test the above example with different temperature values to see the results. We can make conditions more complex to be more useful: var   Temp: Single;   ACIsOn: Byte; begin   Write('Please enter Temperature of this room : ');   Readln(Temp);   Write('Is air conditioner on? if it is (On) write 1,',     ' if it is (Off) write 0 : ');   Readln(ACIsOn); if (ACIsOn = 1) and (Temp > 22) then   Writeln('Do nothing, we still need cooling') else if (ACIsOn = 1) and (Temp < 18) then   Writeln('Please turn off air-conditioner') else if (ACIsOn = 0) and (Temp < 18) then   Writeln('Do nothing, it is still cold') else if (ACIsOn = 0) and (Temp > 22) then   Writeln('Please turn on air-conditioner') else   Writeln('Please enter a valid values'); Write('Press enter key to close'); Readln;   end. In the above example, we have used the new keyword (and) which means if the first condition returns True (ACIsOn = 1), and the second condition returns True (Temp > 22), then execute the Writeln statement. If one condition or both of them return False, then it will go to the else part. If the air-conditioner is connected to a computer via the serial port for example, then we can turn it on/off from that application, using serial port procedures/components. In this case we need to add extra parameters for the if condition, like for how long the air-conditioner was operating. If it exceeds the allowable time (for example, 1 hour) then it should be turned off regardless of room temperature. Also we can consider the rate of losing coolness, if it is very slow (at night), then we could turn if off for longer time. Weight program In this example, we ask the user to enter his/her height in meters, and weight in Kilos. Then the program will calculate the suitable weight for that person according to the entered data, and then it will tell him/her the results: program Weight; {$mode objfpc}{$H+} uses   {$IFDEF UNIX}{$IFDEF UseCThreads}   cthreads,   {$ENDIF}{$ENDIF}   Classes, SysUtils   { you can add units after this }; var   Height: Double;   Weight: Double;   IdealWeight: Double; begin   Write('What is your height in meters (e.g. 1.8 meter) : ');   Readln(Height);   Write('What is your weight in kilos : ');   Readln(Weight);   if Height >= 1.4 then     IdealWeight:= (Height - 1) * 100   else     IdealWeight:= Height * 20;   if (Height < 0.4) or (Height > 2.5) or (Weight < 3) or (Weight > 200) then begin   Writeln('Invalid values');   Writeln('Please enter proper values'); end else if IdealWeight = Weight then   Writeln('Your weight is suitable') else if IdealWeight > Weight then   Writeln('You are under weight, you need more ',     Format('%.2f', [IdealWeight - Weight]), ' Kilos') else   Writeln('You are over weight, you need to lose ',     Format('%.2f', [Weight - IdealWeight]), ' Kilos');   Write('Press enter key to close');   Readln; end. In this example, we have used new keywords: 1. Double: which is similar to Single. Both of them are real numbers, but Double has a double    precision floating point, and it requires 8 bytes in memory, while single requires only 4 bytes. 2. The second new thing is the keyword (Or) and we have used it to check if one of the conditions    is met or not. If one of condition is met, then it will execute the statement. For example: if the    first condition returns True (Height < 0.4), then the Writeln statement will be called:    Writeln('Invalid values'); . If the first condition returns False, then it will check the second one,    etc. If all conditions returns False, it will go to the else part. 3. We have used the keywords begin end with the if statement, because if statement should    execute one statement. Begin end converts multiple statements to be considered as one block    (statement), then multiple statements could be executed by if condition. Look for these two    statemetns: Writeln('Invalid values'); Writeln('Please enter proper values'); It has been converted to one statement using begin end: if (Height < 0.4) or (Height > 2.5) or (Weight < 3) or   (Weight > 200) then   begin     Writeln('Invalid values');     Writeln('Please enter proper values');   end   4. We have used the procedure Format, which displays values in a specific format. In this case we    need to display only 2 digits after the decimal point. We need to add the SysUtils unit to the    Uses clause in order to use this function. What is your height in meters (e.g. 1.8 meter) : 1.8 What is your weight in kilos : 60.2 You are under weight, you need more 19.80 Kilos Note: This example may be not 100% accurate. You can search the web for weight calculation in detail. We meant only to explain how the programmer could solve such problems and do good analysis of the subject to produce reliable applications.   Case .. of statement There is another method for conditional branching, which is the Case .. Of statement. It branches execution according to the case ordinal value. The Restaurant program will illustrate the use of the case of statement: Restaurant program var   Meal: Byte; begin Writeln('Welcome to Pascal Restaurant. Please select your order'); Writeln('1 - Chicken(10)');
Writeln('2 - Fish(7));Writeln(3Meat(8)');
Writeln('4 – Salad(2));Writeln(5OrangeJuice(1)');
Writeln('6 - Milk(1));Writeln;Write(Pleaseenteryourselection:);Readln(Meal);caseMealof1:Writeln(YouhaveorderedChicken,,thiswilltake15minutes);2:Writeln(YouhaveorderedFish,thiswilltake12minutes);3:Writeln(Youhaveorderedmeat,thiswilltake18minutes);4:Writeln(YouhaveorderedSalad,thiswilltake5minutes);5:Writeln(YouhaveorderedOrangejuice,,thiswilltake2minutes);6:Writeln(YouhaveorderedMilk,thiswilltake1minute);elseWriteln(Wrongentry);end;Write(Pressenterkeytoclose);Readln;end.Ifwewritethesameapplicationusingtheifcondition,itwillbecomemorecomplicated,andwillcontainduplications:RestaurantprogramusingIfconditionvarMeal:Byte;beginWriteln(WelcometoPascalrestaurant,pleaseselectyourmeal);Writeln(1Chicken(10)');
Writeln('2 - Fish(7));Writeln(3Meat(8)');
Writeln('4 - Salad(2));Writeln(5OrangeJuice(1)');
Writeln('6 - Milk(1[Math Processing Error])');
Writeln('2 - Fish(7));Writeln(3Meat(8)');
Writeln('4 – Salad(2));Writeln(5OrangeJuice(1)');
Writeln('6 - Milk(1));Writeln;end;procedureGetOrder(AName:string;Minutes:Integer);beginWriteln(Youhaveordered:,AName,,thiswilltake,Minutes,minutes);end;//MainapplicationvarMeal:Byte;beginMenu;Write(Pleaseenteryourselection:);Readln(Meal);caseMealof1:GetOrder(Chicken,15);2:GetOrder(Fish,12);3:GetOrder(Meat,18);4:GetOrder(Salad,5);5:GetOrder(Orangejuice,2);6:GetOrder(Milk,1);elseWriteln(Wrongentry);end;Write(Pressenterkeytoclose);Readln;end.Nowthemainapplicationbecomessmallerandmorereadable.Thedetailsoftheotherpartsareseparatedinprocedures,likethegetorderanddisplaymenuprocedures.FunctionsFunctionsaresimilartoprocedures,buthaveanadditionalfeature,whichisreturningavalue.Wehaveusedfunctionsbefore,likeUpperCase,whichconvertsandreturnstexttouppercase,andAbs,whichreturnstheabsolutevalueofanumber.Inthenextexample,wehavewrittentheGetSummfunction,whichreceivestwointegervaluesandreturnstheirsummation:functionGetSumm(x,y:Integer):Integer;beginResult:=x+y;end;varSum:Integer;beginSum:=GetSumm(2,7);Writeln(Summationof2+7=,Sum);Write(Pressenterkeytoclose);Readln;end.NoticethatwehavedeclaredthefunctionasInteger,andwehaveusedtheResultkeywordtorepresentthefunctionsreturnvalue.Inthemainapplication,wehaveusedthevariableSum,inwhichwereceivethefunctionresult,butwecouldeliminatethisintermediatevariableandcallthisfunctioninsidetheWritelnprocedure.Thisisonedifferencebetweenfunctionsandprocedures.Wecancallfunctionsasinputparametersinotherproceduresorfunctions,butwecannotcallproceduresasparametersofotherfunctionsandprocedures:functionGetSumm(x,y:Integer):Integer;beginResult:=x+y;end;beginWriteln(Summationof2+7=,GetSumm(2,7));Write(Pressenterkeytoclose);Readln;end.Inthenextexample,wehaverewrittentheRestaurantprogramusingfunctions:RestaurantprogramusingfunctionsprocedureMenu;beginWriteln(WelcometoPascalRestaurant.Pleaseselectyourorder);Writeln(1Chicken(10)');
Writeln('2 - Fish(7));Writeln(3Meat(8)');
Writeln('4 – Salad(2));Writeln(5OrangeJuice(1)');
Writeln('6 - Milk(1$)');
Writeln('X - nothing');
Writeln;
end;
function GetOrder(AName: string; Minutes, Price: Integer): Integer;
begin
Writeln('You have ordered: ', AName, ' this will take ',
Minutes, ' minutes');
Result:= Price;
end;
var
Selection: Char;
Price: Integer;
Total: Integer;
begin
Total:= 0;
repeat
Menu;
Write('Please enter your selection: ');
Readln(Selection);
case Selection of
'1': Price:= GetOrder('Checken', 15, 10);
'2': Price:= GetOrder('Fish', 12, 7);
'3': Price:= GetOrder('Meat', 18, 8);
'4': Price:= GetOrder('Salad', 5, 2);
'5': Price:= GetOrder('Orange juice', 2, 1);
'6': Price:= GetOrder('Milk', 1, 1);
'x', 'X': Writeln('Thanks');
else
begin
Writeln('Wrong entry');
Price:= 0;
end;
end;
Total:= Total + Price;
until (Selection = 'x') or (Selection = 'X');
Writeln('Total price= ', Total);
Write('Press enter key to close');
Readln;
end.

Local Variables
We can define variables locally inside a procedure or function to be used only inside its code. These
variables can not be accessed from the main application's code or from other procedures and functions.
Example:
procedure Loop(Counter: Integer);
var
i: Integer;
Sum: Integer;
begin
Sum:= 0;
for i:= 1 to Counter do
Sum:= Sum + i;
Writeln('Summation of ', Counter, ' numbers is: ', Sum);
end;
begin// Main program section
Loop;
Write('Press enter key to close');
Readln;
end.
In the procedure Loop, there are two local variables Sum and I. Local variables are stored in Stack
memory, which is a part of memory that allocates variables temporarily until the procedure's execution
is finished. That means it will be unaccessible and can be overwritten when program execution reaches
this line of code:
Write('Press enter key to close');
Global variables can be accessed from the main program and other procedures and functions. They can
hold values until the application is closed, but this can break the structure of the program and make it
hard to trace errors, because any procedure can change global variable values, which may result in
unknown values and misbehavior when we forget to initialize them.
Defining local variables guarantees their privacy, which helps the procedures and functions to be ported
or called from anywhere without worry about global variables values.

News database application
In this example we have three procedures and one function: Add News title, display all News,
searching, and displaying menu to let the user select the function that he/she want to execute:
program news;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ you can add units after this };
type
TNews = record
ATime: TDateTime;
Title: string[100];
end;
procedure AddTitle;
var
F: file of TNews;
News: TNews;
begin
AssignFile(F, 'news.dat');
Write('Input current news title: ');
Readln(News.Title);
News.ATime:= Now;
if FileExists('news.dat') then
begin
FileMode:= 2; // Read/Write
Reset(F);
Seek(F, System.FileSize(F)); // Go to last record to append
end
else
Rewrite(F);
Write(F, News);
CloseFile(F);
end;
procedure ReadAllNews;
var
F: file of TNews;
News: TNews;
begin
AssignFile(F, 'news.dat');
if FileExists('news.dat') then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, News);
Writeln('------------------------------');
Writeln('Title: ', News.Title);

Writeln('Time : ', DateTimeToStr(News.ATime));
end;
CloseFile(F);
end
else
Writeln('Empty database');
end;
procedure Search;
var
F: file of TNews;
News: TNews;
Keyword: string;
Found: Boolean;
begin
AssignFile(F, 'news.dat');
Write('Input keyword to search for: ');
Readln(Keyword);
Found:= False;
if FileExists('news.dat') then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, News);
if Pos(LowerCase(Keyword), LowerCase(News.Title)) > 0 then
begin
Found:= True;
Writeln('------------------------------');
Writeln('Title: ', News.Title);
Writeln('Time : ', DateTimeToStr(News.ATime));
end;
end;
CloseFile(F);
if not Found then
Writeln(Keyword, ' Not found');
end
else
Writeln('Empty database');
end;
function Menu: char;
begin
Writeln;
Writeln('...........News database..........');
Writeln('1. Add news title');
Writeln('2. Display all news');
Writeln('3. Search');
Writeln('x. Exit');
Write('Please input a selection : ');
Readln(Result);
end;
// Main application

var
Selection: Char;
begin
repeat
Selection:= Menu;
case Selection of
'1': AddTitle;
'2': ReadAllNews;
'3': Search;
end;
until LowerCase(Selection) = 'x';
end.
This application is easy to read and has compact and clear code in the main section. We can also add
new features to any procedure without affecting or modifying other parts.

Functions as input parameters
As we said before, we can call the function as a procedure/function input parameter, because we can
treat it as a value.
See the example below:
function DoubleNumber(x: Integer): Integer;
begin
Result:= x * 2;
end;
// Main
begin
Writeln('The double of 5 is : ', DoubleNumber(5));
Readln;
end.
Note that we have called the DoubleNumber function from inside the Writeln procedure.
In the next modification of the example, we will use an intermediate variable to store the function's
result, and then use it as input to the Writeln procedure:
function DoubleNumber(x: Integer): Integer;
begin
Result:= x * 2;
end;
// Main
var
MyNum: Integer;
begin
MyNum:= DoubleNumber(5);
Writeln('The double of 5 is : ', MyNum);
Readln;
end.
We can also call functions within if conditions and loop conditions:
function DoubleNumber(x: Integer): Integer;
begin
Result:= x * 2;
end;
// Main
begin
if DoubleNumber(5) > 10 then
Writeln('This number is larger than 10')
else
Writeln('This number is equal or less than 10);

Readln;
end.
Procedure and function output parameters
In the previous usage of functions, we found that we can return only one value, which is the result of
the function, but how can we return more than one value in functions or procedures?
Let us do this experiment:
procedure DoSomething(x: Integer);
begin
x:= x * 2;
Writeln('From inside procedure: x = ', x);
end;
//
main
var
MyNumber: Integer;
begin
MyNumber:= 5;
DoSomething(MyNumber);
Writeln('From main program, MyNumber = ', MyNumber);
Writeln('Press enter key to close');
Readln;
end.
In this example, the doSomething procedure receives x as an Integer value, then it multiplies it by two,
and then finally it displays it.
In the main part of the program, we declared the variable MyNumber as an Integer, put the number 5 in
it, and then passed it as a parameter to the DoSomething procedure. In this case, the MyNumber value
(5) will be copied into the x variable.
After calling the function, X 'svalue will be 10, but when we display MyNumber after procedure calling
we will find that it still holds the value 5. That means MyNumber and X have two different locations in
memory, which is normal.
This type of parameter passing is called calling by value, which does not affect the original parameter
MyNumber. We also could use constants to pass such values, e.g:
DoSomething(5);

Calling by reference
If we add the var keyword to the declaration of DoSomething's x parameter, things will be different
now:
procedure DoSomething(var x: Integer);
begin
x:= x * 2;
Writeln('From inside procedure: x = ', x);
end;
//
main
var
MyNumber: Integer;
begin
MyNumber:= 5;
DoSomething(MyNumber);
Writeln('From main program, MyNumber = ', MyNumber);
Writeln('Press enter key to close');
Readln;
end.
This time MyNumber's value will be changed according to x, which means they are sharing the same
memory location.
We should pass a variable (not a constant) to the procedure this time, using the same type: if the
parameter is declared as Byte, then MyNumber should be declared as Byte; if it is Integer, then it
should be Integer.
The next example will generate an error when calling DoSomething, which requires a variable for its
parameter:
DoSomething(5);
In calling by value, the previous code could be used, because it cares only about having a value passed
as its parameter, and 5 is a value, but in calling by reference the program cares about having a variable
passed as its parameter and then acts on its value.
In the next example, we will pass two variables, and then the procedure will swap their values:
procedure SwapNumbers(var x, y: Integer);
var
Temp: Integer;
begin
Temp:= x;
x:= y;
y:= Temp;
end;

//
main
var
A, B: Integer;
begin
Write('Please input value for A: ');
Readln(A);
Write('Please input value for B: ');
Readln(B);
SwapNumbers(A, B);
Writeln('A = ', A, ', and B = ', B);
Writeln('Press enter key to close');
Readln;
end.

Units
A Unit in Pascal is a library that contains procedures, functions, constants, and user defined types that
can be used in many applications.
Units are used to achieve these goals:
1. Accumulate procedures and functions that are frequently used in applications in external units.
This achieves code re-usability in software development.
2. Combine procedures and functions that are used to perform certain tasks in one entity. Instead
of populating the main application's source code with unrelated procedures, it is better to divide
the application into logical modules using units.
To create a new unit, go to File/New Unit in the Lazarus menu, and Lazarus creates this template:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
implementation
end.
After creating a new unit, we should save it using a specific name, like Test. It will be saved in a file
named Test.pas, but the unit name will remain Test in the application.
Then we can start writing procedures, functions, and other re-usable code:
unit Test;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
const
GallonPrice = 6.5;
function GetKilometers(Payment, Consumption: Integer): Single;
implementation

function GetKilometers(Payment, Consumption: Integer): Single;
begin
Result:= (Payment / GallonPrice) * Consumption;
end;
end.
We have written the GallonPrice constant and the GetKilometers function to be called from any
program.
Also we have put the function's header in the Interface part of the unit to make it accessible from
outside the unit. Applications can access only the Interface part of units.
To use this unit, we have created a new program in the same directory as the unit (Test.pas), and then
we have added this unit in uses clause:
program PetrolConsumption;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ you can add units after this }, Test;
var
Payment: Integer;
Consumption: Integer;
Kilos: Single;
begin
Write('How much did you pay for your car''s petrol: ');
Readln(Payment);
Write('What is the consumption of your car (Kilos per one Gallon) ');
Readln(Consumption);
Kilos:= GetKilometers(Payment , Consumption);
Writeln('This petrol will keep your car running for: ',
Format('%0.1f', [Kilos]), ' Kilometers');
Write('Press enter');
Readln;
end.
If we need to go to the GetKilometers function's code, we can press the Ctrl key then click its name
with the mouse to display the GetKilometers function's source code. Lazarus/Delphi will immediately
open the Test unit and display that function.
We can also open the Test unit in the editor by moving the cursor to the unit's name (Test), and then
press Alt + Enter.

We can access units from programs in these conditions:
1. The Unit file exists in the same directory, as the application, as we have done in the previous
example.
2. Adding the unit to the project, by opening the unit in Lazarus then clicking Project/Add Editor
File to project.
3. Adding the unit's path in Project/Compiler Options/Compiler Options/Paths/Other Unit Files.
Units in Lazarus and Free Pascal
Units represent one of the most important building blocks in Lazarus and Free Pascal. We find that
most procedures, functions, types, classes and components exist in units.
Free Pascal has a very rich collection of units that provide functionality used in all different types of
applications. For that reason it is fast and easy to develop applications using Lazarus and Free Pascal.
Examples of Free Pascal/ Lazarus units that contain general procedures and functions: SysUtils, and
Classes.
Units written by the programmer
Programmers can use Lazarus units and they can write their own units. Units that are written by
programmers represent their special needs for their applications. For example, if a developer is writing
software for a car garage, then he/she could make a unit that contains procedures for adding a new car,
searching for a car using plate id, etc.
Putting procedures and functions in units makes the application more readable and easier to be
developed by more than one developer, because each one could concentrate on one module (unit) or
more, then they could test their units functionality independently (Unit testing), then eventually they
could integrate these units together in one project.

Hejri Calendar
The Hejri calender is based on Moon months, and was created by Muslims. We need to create a unit
that helps us to convert the Gregorian calendar to the Moon (Hejri) Calender based on these facts:
1. The first day of Hejri 16 July 622 in the Gregorian calender.
2. The Hejri year contains 354.367056 days.
3. The Hejri month contains 29.530588 days.
The Hejri unit can be used to get current the moon phase.
This is the code of the Hejri unit:
{
********************************************************************************
HejriUtils:
Author:
email:
Home page:
License:
Created on:
Last modifie:
Hejri Calnder converter, for FreePascal and Delphi
Motaz Abdel Azeem
motaz@code.sd
http://motaz.freevar.com/
LGPL
26.Sept.2009
26.Sept.2009
*******************************************************************************
}
unit HejriUtils;
{$IFDEF FPC}
{$mode objfpc}{$H+}
{$ENDIF}
interface
uses
Classes, SysUtils;
const
HejriMonthsEn: array [1 .. 12] of string = ('Moharram', 'Safar', 'Rabie Awal',
'Rabie Thani', 'Jumada Awal', 'Jumada Thani', 'Rajab', 'Shaban', 'Ramadan',
'Shawal', 'Thi-Alqaida', 'Thi-Elhajah');
HejriMonthsAr: array [1 .. 12] of string = ('لوأ عيبر' ,'رفص' , 'مرم',
'ناضمر' ,'نابعش' ,'بجر' ,'رخﻵا ىداج' ,'لوﻷا ىداج' ,'ينااث عيبر',
'ةجةلا يذ','ةدعقلا يذ' ,'لاوش');
HejriYearDays = 354.367056;
HejriMonthDays = 29.530588;
procedure DateToHejri(ADateTime: TDateTime; var Year, Month, Day: Word);
function HejriToDate(Year, Month, Day: Word): TDateTime;
procedure HejriDifference(Year1, Month1, Day1, Year2, Month2, Day2: Word;
var YearD, MonthD, DayD: Word);

implementation
var
HejriStart : TDateTime;
procedure DateToHejri(ADateTime: TDateTime; var Year, Month, Day: Word);
var
HejriY: Double;
Days: Double;
HejriMonth: Double;
RDay: Double;
begin
HejriY:= ((Trunc(ADateTime) - HejriStart - 1) / HejriYearDays);
Days:= Frac(HejriY);
Year:= Trunc(HejriY) + 1;
HejriMonth:= ((Days * HejriYearDays) / HejriMonthDays);
Month:= Trunc(HejriMonth) + 1;
RDay:= (Frac(HejriMonth) * HejriMonthDays) + 1;
Day:= Trunc(RDay);
end;
function HejriToDate(Year, Month, Day: Word): TDateTime;
begin
Result:= (Year - 1) * HejriYearDays + (HejriStart - 0) +
(Month - 1) * HejriMonthDays + Day + 1;
end;
procedure HejriDifference(Year1, Month1, Day1, Year2, Month2, Day2: Word; var
YearD, MonthD, DayD: Word);
var
Days1: Double;
Days2: Double;
DDays: Double;
RYear, RMonth: Double;
begin
Days1:= Year1 * HejriYearDays + (Month1 - 1) * HejriMonthDays + Day1 - 1;
Days2:= Year2 * HejriYearDays + (Month2 - 1) * HejriMonthDays + Day2 - 1;
DDays:= Abs(Days2 - Days1);
RYear:= DDays / HejriYearDays;
RMonth:= (Frac(RYear) * HejriYearDays) / HejriMonthDays;
DayD:= Round(Frac(RMonth) * HejriMonthDays);
YearD:= Trunc(RYear);
MonthD:= Trunc(RMonth);
end;
initialization
HejriStart:= EncodeDate(622, 7, 16);
end.
The HejriUtils Unit contains these procedures and functions:

1. DateToHejri: This procedure is used to convert Gregorian date to Hejri date, example of using
it:
program Project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes , HejriUtils, SysUtils
{ you can add units after this };
var
Year, Month, Day: Word;
begin
DateToHejri(Now, Year, Month, Day);
Writeln('Today in Hejri: ', Day, '-', HejriMonthsEn[Month],
'-', Year);
Readln;
end.
2.
3.
HejriToDate: This function is used to convert the Hejri date to a Gregorian TDateTime value.
HejriDifference: This procedure is used to calculate the difference in years, days, and months
between two Hejri dates.

Procedure and function Overloading
Overloading mean we can write two or more procedures/functions with the same name but different
parameters. Different parameters means different parameter types or a different number of parameters.
For example, we may need to write two versions of the Sum function, where the first one accepts and
returns integer numbers, and the second one accepts and returns real numbers:
program sum;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ you can add units after this };
function Sum(x, y: Integer): Integer; overload;
begin
Result:= x + y;
end;
function Sum(x, y: Double): Double; overload;
begin
Result:= x + y;
end;
var
j, i: Integer;
h, g: Double;
begin
j:= 15;
i:= 20;
Writeln(J, ' + ', I, ' = ', Sum(j, i));
h:= 2.5;
g:= 7.12;
Writeln(H, ' + ', G, ' = ', Sum(h, g));
Write('Press enter key to close');
Readln;
end.
Notice that we have used the reserved word overload, which means: this function is overloaded.

Default value parameters
We can put default values for procedures and functions in parameters. In this case we can ignore
sending these parameters, and the default values will be used.
Look at the next example:
program defaultparam;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ you can add units after this };
function SumAll(a, b: Integer; c: Integer = 0;
d: Integer = 0): Integer;
begin
result:= a + b + c + d;
end;
begin
Writeln(SumAll(1, 2));
Writeln(SumAll(1, 2, 3));
Writeln(SumAll(1, 2, 3, 4));
Write('Press enter key to close');
Readln;
end.
In this example, we have called the SumAll function three times, the first time using two values, the
second time using three values, and the third time using four values. A and B are mandatory parameters
and should be sent in all cases because they have no default values.
We can ignore sending default parameter values from left to right, for example, if we want to ignore
sending a value for c, then we should not send a value for d.
Default parameters should start from right to left. We can not declare a default parameter and declare
another one that has no default value next to it, like the following example:
function ErrorParameters(a: Integer; b: Integer = 10; c: Integer; x: string);
We should put the most important parameters on the left, and unimportant ones (that can be ignored)
on the right side of the function/procedure's header.

Sorting
Data sorting is part of the data structure topic, and we introduce it here because it needs procedures and
functions to implement it.
Sorting is always used with arrays and lists. Suppose that we have an array of integers, and we need to
sort it in ascending or in descending order. We can do this using different methods:
Bubble sort algorithm
This algorithm is one of the simplest sorting algorithms. It compares the first item of array with second
one, and in case of ascending order, it will swap the first one with second if the first is greater than the
second. After that it compares the second item with third one until it reaches the end of the array. Then
it repeats this operation until no swap operation happens, which means the array is already sorted.
Suppose that we have 6 items in an array containing these values:
7
10
2
5
6
3
We will find that these values need more than one cycle to be sorted.
The first number will be compared with the second one, and a swap operation will occur if the first one
is greater than the second, and then the second will be compared with third, until the fifth item is
compared with the sixth one.
After the first cycle, the array will be like this:
7
2
5
6
3
10
After the second cycle:
2
5
6
3
7

10
Third:
2
5
3
6
7
10
Fourth:
2
3
5
6
7
10
We will get a sorted array after the fourth cycle, because in the fourth cycle no swap operation
happens. That means only three cycles are required with that data, but the fourth one is used to check
for the occurrence of a sort.
Notice that the small values float like bubbles over the larger values.
Next is a bubble sort program:
program BubbleSortProj;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
procedure BubbleSort(var X: array of Integer);
var
Temp: Integer;
i: Integer;
Changed: Boolean;
begin
repeat // Outer loop
Changed:= False;
for i:= 0 to High(X) - 1 do // Inner loop
if X[i] > X[i + 1] then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;

Changed:= True;
end;
until not Changed;
end;
var
Numbers: array [0 .. 9] of Integer;
i: Integer;
begin
Writeln('Please input 10 random numbers');
for i:= 0 to High(Numbers) do
begin
Write('#', i + 1, ': ');
Readln(Numbers[i]);
end;
BubbleSort(Numbers);
Writeln;
Writeln('Numbers after sort: ');
for i:= 0 to High(Numbers) do
begin
Writeln(Numbers[i]);
end;
Write('Press enter key to close');
Readln;
end.
We can modify this sort to a descending sort by changing the greater than (>) operator to less than (<),
in this line:
if X[i] < X[i + 1] then
In the next example, we will sort students' grades from larger to smaller marks (descending order):
Sorting students' marks
program smSort;
// Students' marks sort
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ you can add units after this };
type
TStudent = record
StudentName: string;
Mark: Byte;
end;

procedure BubbleSort(var X: array of TStudent);
var
Temp: TStudent;
i: Integer;
Changed: Boolean;
begin
repeat
Changed:= False;
for i:= 0 to High(X) - 1 do
if X[i].Mark < X[i + 1].Mark then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;
until not Changed;
end;
var
Students: array [0 .. 9] of TStudent;
i: Integer;
begin
Writeln('Please input 10 student names and marks');
for i:= 0 to High(Students) do
begin
Write('Student #', i + 1, ' name : ');
Readln(Students[i].StudentName);
Write('Student #', i + 1, ' mark : ');
Readln(Students[i].Mark);
Writeln;
end;
BubbleSort(Students);
Writeln;
Writeln('Marks after Bubble sort: ');
Writeln('----------------------');
for i:= 0 to High(Students) do
begin
Writeln('# ', i + 1, ' ', Students[i].StudentName,
' with mark (', Students[i].Mark, ')');
end;
Write('Press enter key to close');
Readln;
end.
The Bubble sort algorithm is very simple, and programmers could memorize it. It is also suitable only
for a small amount of data, or data that is nearly sorted. In the case of a large amount of unsorted data,
it could take a long time, so that it is better to use another algorithm.
Selection Sort algorithm

This type of sorting is similar to the bubble sort, but it is faster with a large amount of data. It contains
two loops, the outer loop and the inner loop. In the inner loop, the cycles decrease in every outer loop
cycle until it reaches only two cycles.
program SelectionSort;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ you can add units after this };
procedure SelectSort(var X: array of Integer);
var
i: Integer;
j: Integer;
SmallPos: Integer;
Smallest: Integer;
begin
for i:= 0 to High(X) -1 do // Outer loop
begin
SmallPos:= i;
Smallest:= X[SmallPos];
for j:= i + 1 to High(X) do // Inner loop
if X[j] < Smallest then
begin
SmallPos:= j;
Smallest:= X[SmallPos];
end;
X[SmallPos]:= X[i];
X[i]:= Smallest;
end;
end;
// Main application
var
Numbers: array [0 .. 9] of Integer;
i: Integer;
begin
Writeln('Please input 10 random numbers');
for i:= 0 to High(Numbers) do
begin
Write('#', i + 1, ': ');
Readln(Numbers[i]);
end;
SelectSort(Numbers);
Writeln;
Writeln('Numbers after Selection sort: ');

for i:= 0 to High(Numbers) do
begin
Writeln(Numbers[i]);
end;
Write('Press enter key to close');
Readln;
end.
In spite of that, it is faster than a bubble sort, but a bubble sort becomes faster (fewer outer cycles) if
the data is sorted or semi-sorted, while a selection sort always has the same number of cycles
regardless of the data's initial order.
Shell sort algorithm
This is a very fast sort when there is a large amount of data, and its behavior is similar to a bubble sort
if the data is semi-sorted, but it is more complicated than the two previous sort algorithms.
Its name comes from its inventor, Donald Shell.
program ShellSort;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
procedure ShellS(var X: array of Integer);
var
Done: Boolean;
Jump, j, i: Integer;
Temp: Integer;
begin
Jump:= High(X);
while (Jump > 0) do // Outer loop
begin
Jump:= Jump div 2;
repeat// Intermediate loop
Done:= True;
for j:= 0 to High(X) - Jump do // Inner loop
begin
i:= j + Jump;
if X[j] > X[i] then // Swap
begin
Temp:= X[i];
X[i]:= X[j];
X[j]:= Temp;
Done:= False;

end;
end; // end of inner loop
until Done; // end of intermediate loop
end; // end of outer loop
end;
var
Numbers: array [0 .. 9] of Integer;
i: Integer;
begin
Writeln('Please input 10 random numbers');
for i:= 0 to High(Numbers) do
begin
Write('#', i + 1, ': ');
Readln(Numbers[i]);
end;
ShellS(Numbers);
Writeln;
Writeln('Numbers after Shell sort: ');
for i:= 0 to High(Numbers) do
begin
Writeln(Numbers[i]);
end;
Write('Press enter key to close');
Readln;
end.

String sorting
We can sort strings like names, address, etc., using the same comparison operators (> and <) that we
used to sort integers.
Comparison occurs from the left characters to the right, for example the letter A is smaller than B, and
the name 'Ahmed' is smaller than 'Badr'. If two strings have the same first letters, then comparison will
go to the next character. Example 'Ali' and 'Ahmed', this time h is smaller than l.
Sorting students name program
program smSort;
// Students mark sort by name
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
type
TStudent = record
StudentName: string;
Mark: Byte;
end;
procedure BubbleSort(var X: array of TStudent);
var
Temp: TStudent;
i: Integer;
Changed: Boolean;
begin
repeat
Changed:= False;
for i:= 0 to High(X) - 1 do
if X[i].StudentName > X[i + 1].StudentName then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;
until not Changed;
end;
var
Students: array [0 .. 9] of TStudent;
i: Integer;
begin

Writeln('Please input 10 student names and marks');
for i:= 0 to High(Students) do
begin
Write('Student #', i + 1, ' name : ');
Readln(Students[i].StudentName);
Write('Student #', i + 1, ' mark : ');
Readln(Students[i].Mark);
Writeln;
end;
BubbleSort(Students);
Writeln;
Writeln('Marks after Bubble sort: ');
Writeln('----------------------');
for i:= 0 to High(Students) do
begin
Writeln('# ', i + 1, ' ', Students[i].StudentName,
' with mark (', Students[i].Mark, ')');
end;
Write('Press enterkey to close');
Readln;
end.
Sort algorithms comparison
In this example, we will compare the three sorting algorithms that we have mentioned in this chapter
with a large array of Integer. We will measure the time used by each algorithm:
program SortComparison;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils;
//
Bubble sort
procedure BubbleSort(var X: array of Integer);
var
Temp: Integer;
i: Integer;
Changed: Boolean;
begin
repeat
Changed:= False;
for i:= 0 to High(X) - 1 do
if X[i] > X[i + 1] then
begin
Temp:= X[i];

X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;
until not Changed;
end;
// Selection Sort
procedure SelectionSort(var X: array of Integer);
var
i: Integer;
j: Integer;
SmallPos: Integer;
Smallest: Integer;
begin
for i:= 0 to High(X) -1 do // Outer loop
begin
SmallPos:= i;
Smallest:= X[SmallPos];
for j:= i + 1 to High(X) do // Inner loop
if X[j] < Smallest then
begin
SmallPos:= j;
Smallest:= X[SmallPos];
end;
X[SmallPos]:= X[i];
X[i]:= Smallest;
end;
end;
// Shell Sort
procedure ShellSort(var X: array of Integer);
var
Done: Boolean;
Jump, j, i: Integer;
Temp: Integer;
begin
Jump:= High(X);
while (Jump > 0) do // Outer loop
begin
Jump:= Jump div 2;
repeat// Intermediate loop
Done:= True;
for j:= 0 to High(X) - Jump do // Inner loop
begin
i:= j + Jump;
if X[j] > X[i] then // Swap
begin
Temp:= X[i];
X[i]:= X[j];
X[j]:= Temp;
Done:= False;
end;
end; // inner loop
until Done; // innermediate loop end

end; // outer loop end
end;
// Randomize Data
procedure RandomizeData(var X: array of Integer);
var
i: Integer;
begin
Randomize;
for i:= 0 to High(X) do
X[i]:= Random(10000000);
end;
var
Numbers: array [0 .. 59999] of Integer;
i: Integer;
StartTime: TDateTime;
begin
Writeln('----------------- Full random data');
RandomizeData(Numbers);
StartTime:= Now;
Writeln('Sorting.. Bubble');
BubbleSort(Numbers);
Writeln('Bubble sort tooks (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
RandomizeData(Numbers);
Writeln('Sorting.. Selection');
StartTime:= Now;
SelectionSort(Numbers);
Writeln('Selection sort tooks (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
RandomizeData(Numbers);
Writeln('Sorting.. Shell');
StartTime:= Now;
ShellSort(Numbers);
Writeln('Shell sort tooks (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Writeln('----------------- Nearly sorted data');
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
StartTime:= Now;
Writeln('Sorting.. Bubble');
BubbleSort(Numbers);
Writeln('Bubble sort tooks (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
Writeln('Sorting.. Selection');

StartTime:= Now;
SelectionSort(Numbers);
Writeln('Selection sort tooks (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
Writeln('Sorting.. Shell');
StartTime:= Now;
ShellSort(Numbers);
Writeln('Shell sort tooks (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Write('Press enterkey to close');
Readln;
end.

Chapter Three
The Graphical User Interface

Introduction
The Graphical User Interface (GUI) is a new alternative to the console interface. It contains forms,
buttons, message boxes, menus, check boxes and graphical components. It is easier for users to use
GUI applications than console applications.
The GUI is used for business applications, operating system applications, games, and development
tools like Lazarus, and many other applications.
Our First GUI application
To create a new GUI application, click on the Lazarus menu:
Project/New Project/Application
Then save the application by clicking on:
File/Save All
We can then create a new folder, such as firstgui, in which to save our project files. Then we should
save the main unit, for example, main.pas, and finally we should choose a project name, such as
firstgui.lpi.
In the main unit, we can press F12 to view the form associated with the main unit, which will look like
this:
If we run the application, we will get this window:

Then we can close the application to return to the designer.
After that, we drop a button from standard component page on the form:
Then put the button at any place on the form like this picture:
We can display the button's properties (like caption name, width, etc) in the Object Inspector window.
If it does not appear in Lazarus's windows, then we can display it by clicking Window/Object Inspector

from the main menu or by pressing F11. Then we will get this window:
We should make sure that we have selected the button not the form before we do any modification to its
properties. Notice the Inspector window has tabs, the first being Properties and the second being
Events. Each tab displays its own page.
Then we can change the text that is displayed in the button by changing its Caption property to Click.
After that, select the Events tab of the Object Inspector to display the Events page and double click the
OnClick event, which will create this code template in the main unit:
procedure TForm1.Button1Click(Sender: TObject);
begin
end;
Then write this line in the OnClick event code template that Lazarus created for us:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Hello world, this is my first GUI application');
end;
By doing this, when we run the application, it will display a dialog window containing the desired
message when we click the button with our mouse.

In Linux, we will find firstgui as an executable file in the same project directory, and firstgui.exe if we
are using Windows. These are the executable files that we can copy to another computer and can run
without the need of the Lazarus tool.
In the previous example, there are many important issues:
1. Main application file: which is stored in the firstgui.lpi file in the example. We can show it by
clicking Project/Source. We will get this source code:
program firstgui;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms
{ you can add units after this }, main;
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
We may need to modify this code in certain cases for special purposes, but in most cases, we can leave
it as it is, and let Lazarus manage it automatically.
2. Main unit: It is the unit that contains the definition of the form that appears automatically when
we run the application.
Below is the main unit code after we have completed the code for the OnClick event:
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private

{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Hello world, this is my first GUI application');
end;
initialization
{$I main.lrs}
end.
In the main unit header, we find the TForm1 declaration, which is similar to the record type, but is a
Class. We will talk about classes in the next chapter: Object Oriented Programming. Button1 is
declared inside the TForm1 class.
We can show this unit source code by pressing Ctrl-F12 then selecting main unit.
3. Object Inspector/Properties: In this page of the Object Inspector, we can view and modify any
component's properties, like a Button's caption or location, a form's color, or a labels font, etc.
These components are similar to records, and their properties are similar to a record's fields.
4. Object Inspector/Events: This page of the Object Inspector contains a component's events that
we can receive, like On Click event in a button, Key Press of an edit box, double click in a label,
etc. When we click on any event of a component, Lazarus creates a new procedure template for
us to write the code that will be called when this event occurs. We can write Pascal code for this
event like the example below for a button's OnClick event:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Hello world, this is my first GUI application');
end;
This procedure will be called when the user clicks that button. This procedure is called an event
handler.

Second GUI application
In this example, we will let the user enter his/her name in an edit box, and then when he/she clicks on a
button, a greeting message will be displayed in a label.
To write this application, do the following:
- Create a new application and save it as inputform. Save the main unit as main.pas, then drop these
components on the form from the standard component tab:
2 Labels
Edit box
Button
Then modify some properties of the above components as shown:
Form1:
Name: fmMain
Caption: Input form application
Label1:
Caption: Please enter your name
Label2:
Name: laYourName
Edit1:
Name: edName
Text:
Button1:
Caption: Click
Put the components on the form to look like the picture below:

- Put this code in the OnClick event handler:
procedure TfmMain.Button1Click(Sender: TObject);
begin
laYourName.Caption:= 'Hello ' + edName.Text;
end;
Then we can run the application and write our name in the edit box, and then click the button.
In the previous example, we used the field Text in the edit box edName to read what the user types.
This is the graphical alternative to the Readln procedures used in console applications to receive user
input.
We also used the Caption property of the label laYourName to display a message. This is one of the
alternative methods to Writeln in GUI applications.

ListBox application
In the next example, we need to add text in a list box, delete it, and clear the list. To do this application
follow these steps:
– Create a new application and put 4 buttons, an Edit box, and a List Box (TListBox) on its main
form
– Change the name of buttons to these names:
btAdd, btClear, btDelete, btClose
– Change the captions of the buttons according to their names as shown in this figure:
- Write these event handlers for the buttons' OnClick events:
procedure TForm1.btAddClick(Sender: TObject);
begin
ListBox1.Items.Add(Edit1.Text);
end;
procedure TForm1.btClearClick(Sender: TObject);
begin
ListBox1.Clear;
end;
procedure TForm1.btDeleteClick(Sender: TObject);
var
Index: Integer;
begin
Index:= ListBox1.ItemIndex;
if Index <> -1 then
ListBox1.Items.Delete(Index);
end;
procedure TForm1.btCloseClick(Sender: TObject);
begin
Close;

end;
Clicking the Add button will insert the text of the edit box into the list. The Delete button will delete
current selected list item. The Clear button will clear the entire list. Finally, the Close button will close
the application.
Text Editor Application
In this example, we will show how to create a simple text editor application.
Follow these steps:

Create a new application and put these components on it's main form:
- TMainMenu
- TMemo: Change it's align property to alClient and ScrollBars to ssBoth
- TOpenDialog and TSaveDialog from Dialogs page of components palette.
Double click on the MainMenu1 component and add File menu and a sub menu containing
Open File, Save File, and Close menu items.

Our form will look like this:

For the Open File item's OnClick event write this code:
if OpenDialog1.Execute then
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);


For the Save File item write this code:
if SaveDialog1.Execute then
Memo1.Lines.SaveToFile(SaveDialog1.FileName);

For the Close item write:
Close;
After running this text editor application, we can write any text and then save it to disk. We also can
open existing text files, like .pas files:

News Application
This time we need to write an application for storing news titles using these steps:





Create a new application and name it gnews
Add two buttons of type type TButton
Add a text box (TEdit)
Add memo (TMemo)
Change the component's properties according to the following values:
Button1
Caption: Add Title
Button2
Caption: Save
Anchors: Left=False, Right=True
Edit1:
Text=
Memo1
ScrollBars: ssBoth
ReadOnly: True
Anchors: Top=True, Left=Ture, Right=True, Bottom=Ture
Then we will get a form like this:

– For the Add Title button's OnClick event write this code:
Memo1.Lines.Insert(0,
FormatDateTime('yyyy-mm-dd hh:nn', Now) + ': ' + Edit1.Text);
– For the Save button's OnClick event write:
Memo1.Lines.SaveToFile('news.txt');
– For the main form's OnClose event write this code to save entered news:
Memo1.Lines.SaveToFile('news.txt');
– For the main form's OnCreate event write the code that loads previously saved news titles if any
exist:
if FileExists('news.txt') then
Memo1.Lines.LoadFromFile('news.txt');
Application with a Second form
In the previous GUI applications, we have used only one form, but in real applications sometimes we
need multiple forms.
To write a multiple formGUI application, do the following steps:
1. Create a new application and save it in a new folder called secondform.
2. Save the main unit as main.pas, and name the form component as fmMain. Save the project as
secondform.lpi.
3. Add a new form by clicking File / New Form. Save this new unit as second.pas and name its
form component fmSecond.
4. Add a label in the second form and write in its Caption property 'Second Form'. Increase its
font size from the label's Font.Size property.
5. Go back to the main form and put a button on it.
6. Add this line after main unit implementation section:
uses second;
7. For the OnClick event of the button, write this code:
fmSecond.Show;
Then run the application and click the button to display the second form.

Chapter Four
Object Oriented
Programming

Introduction
In Object Oriented Programming, we describe the entities of an application as objects. For example, we
can represent car information as an object that contains model name, model year, price, and this object
has the ability to save this data in a file.
The object contains:
1. Properties which store status information., These values can be stored in variables.
2. Procedures and functions which are called Methods. These methods represents the actions that
can be done in this object.
3. Events: these events could be received by the object, like the mouse moves over the object, a
mouse click, etc
4. Event handlers: These are the procedures that will be executed if an event occurs.
Properties and methods that are related to each other can be represented as one object:
Object = Code + Data
An example of Object Oriented Programming is the GUI that we have used in the previous chapter. In
that chapter we have used a lot of objects like buttons, labels, and forms. Each object contains
properties like Caption, Width, and have methods like, Show, Hide, Close, etc. Also they have events
like OnClick, OnCreate, OnClose, etc. The code that is written by the programmer to respond to
specific events like the OnClick code represents event handlers.
First example: Date and Time
We have written an object that contains date and time with actions that work for date and time.
We have created a new unit which is called DateTimeUnit, and we have created a class in it called
TmyDateTime.
Class is the type of an object. If we need to use that class, we should declare an instance of it. This
instance is called object, the same as we have done with Integer, and String types. We declare instances
of classes as variables (I, J, Address, etc) in order to use them.
This is the code of unit:
unit DateTimeUnit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type

{ TMyDateTime }
TMyDateTime = class
private
fDateTime: TDateTime;
public
function GetDateTime: TDateTime;
procedure SetDateTime(ADateTime: TDateTime);
procedure AddDays(Days: Integer);
procedure AddHours(Hours: Single);
function GetDateTimeAsString: string;
function GetTimeAsString: string;
function GetDateAsString: string;
constructor Create(ADateTime: TDateTime);
destructor Destroy; override;
end;
implementation
{ TMyDateTime }
function TMyDateTime.GetDateTime: TDateTime;
begin
Result:= fDateTime;
end;
procedure TMyDateTime.SetDateTime(ADateTime: TDateTime);
begin
fDateTime:= ADateTime;
end;
procedure TMyDateTime.AddDays(Days: Integer);
begin
fDateTime:= fDateTime + Days;
end;
procedure TMyDateTime.AddHours(Hours: Single);
begin
fDateTime:= fDateTime + Hours / 24;
end;
function TMyDateTime.GetDateTimeAsString: string;
begin
Result:= DateTimeToStr(fDateTime);
end;
function TMyDateTime.GetTimeAsString: string;
begin
Result:= TimeToStr(fDateTime);
end;
function TMyDateTime.GetDateAsString: string;
begin
Result:= DateToStr(fDateTime);
end;
constructor TMyDateTime.Create(ADateTime: TDateTime);
begin
fDateTime:= ADateTime;

end;
destructor TMyDateTime.Destroy;
begin
inherited Destroy;
end;
end.
We have put five buttons on the main form as shown:
We have written the following code in the OnClick event of each button:
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls, DateTimeUnit;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;

Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
MyDT: TMyDateTime;
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
MyDT:= TMyDateTime.Create(Now);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(MyDT.GetDateTimeAsString);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage(MyDT.GetDateAsString);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
ShowMessage(MyDT.GetTimeAsString);
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
MyDT.AddHours(1);
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
MyDT.AddDays(1);
end;
initialization
{$I main.lrs}
end.

In this example, notice these important issues:
In the DateTimeUnit unit:
1. Defining TmyDateTime as class, which is the keyword for defining new classes.
2. Introducing the Constructor method: Create. This is a special procedure that is used to create
objects in memory and initialize them.
3. Introducing the Destructor method: Destroy. This is a special procedure that is called to dispose
of object's memory after finishing using it.
4. There are two sections in that class: private: which contains properties and methods that can not
be accessed from outside the class unit. The other section is public, which contains properties
and methods that can be accessed from outside the unit. If a class does not contains a public
section, that means it can not be used at all.
Main unit:
1. We have added DateTimeUnit in the Uses clause of the main form to access its class.
2. We have declared the MyDT object inside the unit:
MyDT: TMyDateTime;
3. We have created the object and initialized it in the main Form's OnCreate event:
MyDT:= TMyDateTime.Create(Now);
That is the method of creating objects in the Object Pascal language.

News application in Object Oriented Pascal
In this example, we want to rewrite the News application using Object Oriented methods. We also have
to categorize news into separate files.
We have created a new GUI application and named it oonews.
The next example is a new unit that contains the TNews class that has news functionality:
unit news;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
TNewsRec = record
ATime: TDateTime;
Title: string[100];
end;
{ TNews }
TNews = class
private
F: file of TNewsRec;
fFileName: string;
public
constructor Create(FileName: string);
destructor Destroy; override;
procedure Add(ATitle: string);
procedure ReadAll(var NewsList: TStringList);
function Find(Keyword: string;
var ResultList: TStringList): Boolean;
end;
implementation
{ TNews }
constructor TNews.Create(FileName: string);
begin
fFileName:= FileName;
end;
destructor TNews.Destroy;
begin
inherited Destroy;
end;
procedure TNews.Add(ATitle: string);
var
Rec: TNewsRec;
begin

AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
FileMode:= 2; // Read/write access
Reset(F);
Seek(F, FileSize(F));
end
else
Rewrite(F);
Rec.ATime:= Now;
Rec.Title:= ATitle;
Write(F, Rec);
CloseFile(F);
end;
procedure TNews.ReadAll(var NewsList: TStringList);
var
Rec: TNewsRec;
begin
NewsList.Clear;
AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, Rec);
NewsList.Add(DateTimeToStr(Rec.ATime) + ' : ' + Rec.Title);
end;
CloseFile(F);
end;
end;
function TNews.Find(Keyword: string; var ResultList: TStringList): Boolean;
var
Rec: TNewsRec;
begin
ResultList.Clear;
Result:= False;
AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, Rec);
if Pos(LowerCase(Keyword), LowerCase(Rec.Title)) > 0 then
begin
ResultList.Add(DateTimeToStr(Rec.ATime) + ' : ' + Rec.Title);
Result:= True;
end;
end;
CloseFile(F);
end;

end;
end.
In the main form we have added Edit box, ComboBox, three buttons, Memo, and two labels
components as shown:
In the main unit, we have written this code:
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics,
Dialogs, News, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)

btAdd: TButton;
btShowAll: TButton;
btSearch: TButton;
cbType: TComboBox;
edTitle: TEdit;
Label1: TLabel;
Label2: TLabel;
Memo1: TMemo;
procedure btAddClick(Sender: TObject);
procedure btSearchClick(Sender: TObject);
procedure btShowAllClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
NewsObj: array of TNews;
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
SetLength(NewsObj, cbType.Items.Count);
for i:= 0 to High(NewsObj) do
NewsObj[i]:= TNews.Create(cbType.Items[i] + '.news');
end;
procedure TForm1.btAddClick(Sender: TObject);
begin
NewsObj[cbType.ItemIndex].Add(edTitle.Text);
end;
procedure TForm1.btSearchClick(Sender: TObject);
var
SearchStr: string;
ResultList: TStringList;
begin
ResultList:= TStringList.Create;
if InputQuery('Search News', 'Please input keyword', SearchStr) then
if NewsObj[cbType.ItemIndex].Find(SearchStr, ResultList) then
begin
Memo1.Lines.Clear;
Memo1.Lines.Add(cbType.Text + ' News');
Memo1.Lines.Add('--------------------------------------------------');
Memo1.Lines.Add(ResultList.Text);
end
else
Memo1.Lines.Text:= SearchStr + ' not found in ' +
cbType.Text + ' news';
ResultList.Free;

end;
procedure TForm1.btShowAllClick(Sender: TObject);
var
List: TStringList;
begin
List:= TStringList.Create;
NewsObj[cbType.ItemIndex].ReadAll(List);
Memo1.Lines.Clear;
Memo1.Lines.Add(cbType.Text + ' News');
Memo1.Lines.Add('-----------------------------------------------------------');
Memo1.Lines.Add(List.Text);
List.Free;
end;
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var
i: Integer;
begin
for i:= 0 to High(NewsObj) do
NewsObj[i].Free;
NewsObj:= nil;
end;
initialization
{$I main.lrs}
end.
In the previous example, notice these issues:
1. We have used a Dynamic array, which is an array that can be allocated, expanded, reduced and
disposed at run time according to it's usage. We declare a dynamic array of News objects like this:
NewsObj: array of TNews;
At run time and before using it, we should initialize it using the SetLength procedure:
SetLength(NewsObj, 10);
Which means allocate 10 elements for that array. This is similar to the declaration of a normal array:
NewsObj: array [0 .. 9] of TNews;
A normal array's size will remain constant during the time an application is running, but a dynamic
array's size can be increased and decreased.
In this example, we have initialized the array according to categories that exist in the combo box:
SetLength(NewsObj, cbType.Items.Count);
If we add more categories in ComboBox.Items, the dynamic array's size will increase accordingly.

2. The TNews type is a Class, and we can not use it directly,.We must declare an object instance of
it like NewsObj.
3. At the end of the application, we have released the objects, then released the dynamic array:
for i:= 0 to High(NewsObj) do
NewsObj[i].Free;
NewsObj:= nil;

Queue Application
A queue is an example of one of type of data structure. It is used to insert and store elements
sequentially and delete them in the order in which the elements were inserted. Its rule is called First-in-
first-out.
In the next example, we have written a unit called Queue, which contains the TQueue class. The
TQueue class can be used to store data like names, and get them sequentially. Getting data from a
queue deletes that data. For example, if the queue contains 10 items, and we get and read 3 items, 7
items will be left in the queue.
Queue unit:
unit queue;
// This unit contains TQueue class,
// which is suitable for any string queue
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
{ TQueue }
TQueue = class
private
fArray: array of string;
fTop: Integer;
public
constructor Create;
destructor Destroy; override;
function Put(AValue: string): Integer;
function Get(var AValue: string): Boolean;
function Count: Integer;
function ReOrganize: Boolean;
end;
implementation
{ TQueue }
constructor TQueue.create;
begin
fTop:= 0;
end;
destructor TQueue.destroy;
begin
SetLength(fArray, 0); // Erase queue array from memory
inherited destroy;
end;

function TQueue.Put(AValue: string): Integer;
begin
if fTop >= 100 then
ReOrganize;
SetLength(fArray, Length(fArray) + 1);
fArray[High(fArray)]:= AValue;
Result:= High(fArray) - fTop;
end;
function TQueue.Get(var AValue: string): Boolean;
begin
AValue:= '';
if fTop <= High(fArray) then
begin
AValue:= fArray[fTop];
Inc(fTop);
Result:= True;
end
else // empty
begin
Result:= False;
// Erase array
SetLength(fArray, 0);
fTop:= 0;
end;
end;
function TQueue.Count: Integer;
begin
Result:= Length(fArray) - fTop;
end;
function TQueue.ReOrganize: Boolean;
var
i: Integer;
PCount: Integer;
begin
if fTop > 0 then
begin
PCount:= Count;
for i:= fTop to High(fArray) do
fArray[i - fTop]:= fArray[i];
// Truncate unused data
setLength(fArray, PCount);
fTop:= 0;
Result:= True; // Re Organize is done
end
else
Result:= False; // nothing done
end;
end;
end.

The main form for the Queue application:
The code of the main unit:
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics,
Dialogs, Queue, StdCtrls;
type
{ TfmMain }
TfmMain = class(TForm)
bbAdd: TButton;
bbCount: TButton;
bbGet: TButton;
edCustomer: TEdit;
Label1: TLabel;
Memo1: TMemo;
procedure bbAddClick(Sender: TObject);
procedure bbCountClick(Sender: TObject);
procedure bbGetClick(Sender: TObject);
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public

MyQueue: TQueue;
{ public declarations }
end;
var
fmMain: TfmMain;
implementation
{ TfmMain }
procedure TfmMain.FormCreate(Sender: TObject);
begin
MyQueue:= TQueue.Create;
end;
procedure TfmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
MyQueue.Free;
end;
procedure TfmMain.bbCountClick(Sender: TObject);
begin
Memo1.Lines.Add('Queue length is: ' + IntToStr(MyQueue.Count));
end;
procedure TfmMain.bbAddClick(Sender: TObject);
var
APosition: Integer;
begin
APosition:= MyQueue.Put(edCustomer.Text);
Memo1.Lines.Add(edCustomer.Text + ' has been added as # ' +
IntToStr(APosition + 1));
end;
procedure TfmMain.bbGetClick(Sender: TObject);
var
ACustomer: string;
begin
if MyQueue.Get(ACustomer) then
begin
Memo1.Lines.Add('Got: ' + ACustomer + ' from the queue');
end
else
Memo1.Lines.Add('Queue is empty');
end;
initialization
{$I main.lrs}
end.
In the TQueue class, we have used the Put method to insert a new item by expanding the dynamic array
and then put the new item in the new last element of the array.
When calling the Get method to remove the item at the top of the queue, the fTop pointer will be moved
to the next item in the queue.

Removing items from the top of a the dynamic array will result in moving the fTop pointer, but the
items of dynamic array will remain in memory and will occupy space, because we can delete only from
the bottom of the dynamic array, and for that reason if the number of deleted items reaches 100, the
ReOrganize method will be called to shift the queue elements at the top of the dynamic array, then
delete unused elements of the array.
This is the code that shifts queue elements to the top of the dynamic array:
for i:= fTop to High(fArray) do
fArray[i - fTop]:= fArray[i];
And this is the code for cutting the dynamic array from the bottom:
// Truncate unused data
setLength(fArray, PCount);
fTop:= 0;
In this example, we find that object oriented programming introduces information hiding. Access to
sensitive data will be denied, like access to variables. Instead we can use specific methods that will not
result in odd behavior for the object.
Sensitive data and methods will be located in the private section of the class declaration:
private
fArray: array of string;
fTop: Integer;
Programmers who use this class can not access these variables directly. If they were able to access
those variables, then they could corrupt the queue by modifying fTop or fArray by accident. For
example, suppose that fTop has been changed to 1000 while the queue contains only 10 elements, this
will result in an access violation error at run-time.
As an alternative for using variables directly, we have implemented Put and Get methods to add and
remove items from array safely. This method is like using gates to control the inside elements.
This feature of OOP is called encapsulation.
Object Oriented File
In the first chapter, we used different types of files, and we manipulated them using structured
programming (procedures and functions). This time we will access files using a file object.
One of Object Oriented Pascal's file classes is TFileStream, which contains methods and properties to
manipulate files.

Using this method makes things more standard and predictable for programmers. For example to open
and initialize a file, we will use the Create constructor, as any other object in Pascal, but in the
structured method of using files, initializing files is done by AssignFile, Rewrite, Reset and Append
procedures.
Copy files using TFileStream
In this example, we will copy files using the TFileStream type.
To do this, create a new application and put these components on the main form:
TButton, TOpenDialog, TSaveDialog
For the OnClick event of the button, write this code:
procedure TfmMain.Button1Click(Sender: TObject);
var
SourceF, DestF: TFileStream;
Buf: array [0 .. 1023] of Byte;
NumRead: Integer;
begin
if OpenDialog1.Execute and SaveDialog1.Execute then
begin
SourceF:= TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
DestF:= TFileStream.Create(SaveDialog1.FileName, fmCreate);
while SourceF.Position < SourceF.Size do
begin
NumRead:= SourceF.Read(Buf, SizeOf(Buf));
DestF.Write(Buf, NumRead);
end;
SourceF.Free;
DestF.Free;
ShowMessage('Copy finished');
end;
end;
This method is very similar to using untyped files, except that it uses an object oriented file.
We can also use a simpler method of copying files:
procedure TfmMain.Button1Click(Sender: TObject);
var
SourceF, DestF: TFileStream;
begin
if OpenDialog1.Execute and SaveDialog1.Execute then
begin
SourceF:= TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
DestF:= TFileStream.Create(SaveDialog1.FileName, fmCreate);
DestF.CopyFrom(SourceF, SourceF.Size);
SourceF.Free;

DestF.Free;
ShowMessage('Copy finished');
end;
end;
The CopyFrom method copies the entire file contents to the destination file because we gave it the
source file's size : SourceF.Size
Inheritance
Inheritance in Object Oriented Programming means creating a new class from an existing one and
inheriting its methods and properties. After inheriting existing properties and methods, we can add new
methods and properties to the new class.
As an example of inheritance, we want to create new a Integer queue class from our old string queue
class. Instead of writing the Integer queue from scratch, we can inherit from string queue.
To inherit from string queue, add a new unit and put the string queue unit in its uses clause. Then
declare the new integer queue as:
TIntQueue = class(TQueue)
The new unit's name is IntQueue, and we have introduced two new methods: PutInt, and GetInt.
The complete code of the unit that contains the TIntQueue class is:
unit IntQueue;
// This unit contains TIntQueue class, which is inherits TQueue
// class and adds PutInt, GetInt methods to be used with
// Integer queue
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Queue;
type
{ TIntQueue }
TIntQueue = class(TQueue)
public
function PutInt(AValue: Integer): Integer;
function GetInt(var AValue: Integer): Boolean;

end;
implementation
{ TIntQueue }
function TIntQueue.PutInt(AValue: Integer): Integer;
begin
Result:= Put(IntToStr(AValue));
end;
function TIntQueue.GetInt(var AValue: Integer): Boolean;
var
StrValue: string;
begin
Result:= Get(StrValue);
if Result then
AValue:= StrToInt(StrValue);
end;
end.
Note that we didn't write new Create, Destroy and Count methods, because they already exist in the
parent class TQueue.
To use the new integer queue class, we have created a new application and added these components:
The unit's code is:
unit main;
{$mode objfpc}{$H+}

interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics,
Dialogs, IntQueue, StdCtrls;
type
{ TfmMain }
TfmMain = class(TForm)
bbAdd: TButton;
bbCount: TButton;
bbGet: TButton;
edCustomerID: TEdit;
Label1: TLabel;
Memo1: TMemo;
procedure bbAddClick(Sender: TObject);
procedure bbCountClick(Sender: TObject);
procedure bbGetClick(Sender: TObject);
procedure FormClose(Sender: TObject;
var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
MyQueue: TIntQueue;
{ public declarations }
end;
var
fmMain: TfmMain;
implementation
{ TfmMain }
procedure TfmMain.FormCreate(Sender: TObject);
begin
MyQueue:= TIntQueue.Create;
end;
procedure TfmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
MyQueue.Free;
end;
procedure TfmMain.bbCountClick(Sender: TObject);
begin
Memo1.Lines.Add('Queue length is: ' + IntToStr(MyQueue.Count));
end;
procedure TfmMain.bbAddClick(Sender: TObject);
var
APosition: Integer;
begin
APosition:= MyQueue.PutInt(StrToInt(edCustomerID.Text));
Memo1.Lines.Add(edCustomerID.Text + ' has been added as # '

+ IntToStr(APosition + 1));
end;
procedure TfmMain.bbGetClick(Sender: TObject);
var
ACustomerID: Integer;
begin
if MyQueue.GetInt(ACustomerID) then
begin
Memo1.Lines.Add('Got: Customer ID : ' + IntToStr(ACustomerID) +
' from the queue');
end
else
Memo1.Lines.Add('Queue is empty');
end;
initialization
{$I main.lrs}
end.
Note that we have used the properties and methods of TQueue in addition to TIntQueue properties and
methods.
In this case ,we call the original class TQueue the base class or ancestor, and we call the new class the
descendant.
Instead of creating a new class, we could modify the string queue unit and add IntPut and IntGet to
handle integers, but we have created the new class TIntQueue to illustrate inheritance. There is also
another reason: suppose that we didn't have the original source code of TQueue, like having only the
compiled unit file (ppu in Lazarus) or (.dcu in Delphi). In this case we couldn't see the source code and
of course we couldn't modify it. Inheritance will be the only way to add more functionality to this
queue.
The end
Code.sd

 

posted @   Chaobs  阅读(2287)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示