Start Programming Using Object Pascal by Motaz Abdel Azeem - HTML preview

PLEASE NOTE: This is an HTML preview only and some elements such as links or page numbers may be incorrect.
Download the book in PDF, ePub, Kindle for a complete version.

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;

index-133_1.png

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;

index-138_1.png

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 Firstinfirstout.

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;

index-144_1.png

You may also like...