P. 1
Delphi Tutorial

Delphi Tutorial

|Views: 105|Likes:
Delphi Tutorial
Delphi Tutorial

More info:

Published by: Jay Ryan Rivera Santos on Mar 18, 2013
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as DOCX, PDF, TXT or read online from Scribd
See more
See less

06/24/2013

pdf

text

original

Sections

  • Chapter 3
  • Chapter 4
  • Chapter 5
  • Chapter 6
  • Chapter 7
  • Chapter 8
  • Chapter 9
  • Chapter 10
  • Chapter 11
  • Chapter 12
  • Chapter 13
  • Chapter 14
  • Chapter 15
  • Chapter 16
  • Chapter 17
  • Chapter 18

Delphi (Beginner) Chapter 3 Creating your first 'Hello World' Delphi Application Page 1: Creating a simple project in Delphi

. Welcome to the third chapter of the FREE online programming course: A Beginner’s Guide to Delphi Programming. An overview of application development with Delphi, including creating a simple project, writing code, compiling and running a project. Also, find out how to ask Delphi for help. More of this Feature • Page 2: Writing and compiling code • Page 3: Saving your work, geting help

Join the Discussion Creating your first 'Hello World' Delphi "Post your views and Application comments to this It's time to create a simple example in Delphi now. chapter of the free When you start Delphi, a default project is created Delphi Programming with one form. This default project automatically Course" creates a blank form, with its associated unit file and Discuss! a project file, among others. Related To get started, from the beginning, close anything Resources that's open by choosing File | Close All from the • A Beginner's Guide to main menu. Delphi Programming.TOC Before you create your first Delphi project, you need to know what you want to develop; a DLL, MDI application, SDI application a CLX application (for Linux) or something else. To start without all the bells and whistles we'll create a standard SDI Windows application. Simply point your mouse to File | New and select Application. This creates a new project group with a single application in it.

Page | 1

The new project contains an empty form, a unit (associated with its form), and a project file. As you develop and build your application, new files will be created and added to the project. The project files are listed in the Project Manager window, display it by selecting View | Project Manager from the main Delphi menu. With the Project Manager, you can easily visualize how all your project files are related. If you share files among different projects, using the Project Manager is recommended because you can quickly and easily see the location of each file in the project. Application vs. CLX Application With some versions of Delphi (supposed Delphi 6 Professional or Enterprise), you can build and develop cross platform applications that can be ported to Linux and compiled withKylix. To develop a CLX application, instead of standard Windows application, you could pick CLX Application from the File | New menu. The Delphi IDE is similar to one when you build Windows applications, except that the Component palette changes dynamically to show the objects that are available for use in Linux CLX applications. Since this course is about Delphi for the Windows platform, we will be exploring Delphi programming from that point of view. However, if you have Kylix and want to join this course you are of course encouraged to do so. Even though, my intention at this stage of this Course, is not to explain differences between CLX (Linux) and VCL (Windows) development you should know that there are no reasons why you should not join the course and just have in mind that when we talk about, let's say, form1.DFM you think form1.XFM. Creating your first 'Hello World' Delphi Application Page 2: Writing code, compiling and running your application for the first time.

Hello Delphi Now that we've created a project, we can begin work on our first application. This first application will be pretty simple - we'll change the caption of the (main) form once the application is executed. The change will be initiated from code - no user interaction will be necessary. To add the code that changes the caption of the form we need to *call* the Code Editor window. If you have the Project Manager displayed on the screen, double click the Form1. This will bring up the Form designer window to the front. Another way to bring the Form1 to the front of the screen is to select Form1 from the Window menu. Once Form1 is on top and active, double click it. This action has the following result: the Code editor is positioned on the top of the screen and Delphi creates the skeleton code for the new event handler. Note: another way of achieving the same result is to activate Form1 in the Object Inspector, select the Events tab and double click in the OnCreate column value.

Page | 2

As stated in the second chapter of this course, each form has a collection of events – such as a mouse click, keypress, or component activation – for which you can specify some additional behavior. In this case the event is called OnCreate. This event occurs when the form is created. The skeleton code looks like:

procedure TForm1.FormCreate(Sender: TObject); begin //this is where your code goes end

For the moment do not get bothered with the meaning of the text you see. Now alter the code so that it looks like:

procedure TForm1.FormCreate(Sender: TObject); begin Caption := 'Hello Delphi! ' + DateTimeToStr(Now); end

Running a project for the first time To see the results of this action, you need to (successfully) compile and run you project. From the Run menu choose Run or press F9. The compiler will try to build the project and execute your application. If the compiler encounters an error, it displays an Error dialog box. When you choose OK to dismiss the dialog box, the Code editor places the cursor on the line of code containing the error.

Page | 3

Note: if you want to see progress reports while your program compiles, you'll need to check the "Show compiler progress" check box in the "Compiling and running" section on the Preferences page of the Environment Options dialog box. Call this dialog box by selecting Environment Options from the Tools menu.

If everything goes well (it should) your application is executed and you see a blank form on the screen. Note several things. First, the form is blank - there are no dots that make up the grid you see when designing the form look. Second, there is a new button on the Windows Task Bar - when you point to it you'll see that it has the Project1 caption. Third, the caption of Delphi IDE is changed from "Delphi 6 - Project 1" to "Delphi 6 - Project 1 [Running]". And fourth, most important for us, the caption of the form is Hello Delphi ! + *date and time of the execution*. There is not much you can do with this window, you can move it resize it and finally close it. Every time you (compile and) run this project a form caption will say Hello Delphi with the date and time of the execution. Ok, I know this is not a lot, but be patient - this is your first project - it is not supposed to do something meaningful. If you want a little more, here goes another simple example. Creating your first 'Hello World' Delphi Application Page 3: Saving your work. Getting help from Delphi.

Saving the project To properly get the job done, you should save the project, along with all its associated files. To save the current form design and its code, select File | Save All from the main menu bar. By default, Delphi opens the Projects folder. I suggest you to create a new folder (inside the Projects folder) for your project. Let's call it "HelloExample". While in the Save As dialog, open the newly created HelloExample folder and save the following
Page | 4

files: . save Unit1 as MainUnit.pas . save Project1 as HelloProject.dpr Note 1: When you have saved the unit file, the corresponding form was saved as MainUnit.dfm Note 2: In the Code Editor window, Unit1 is now referred to as MainUnit. Note 3: Since you have saved the project with the *new* name, if you run your application now, the button on the Task Bar will say "HelloProject". Of course the name of the application and the name of the project do not need to be the same, later we will see how to change the name of a Delphi application.

Note, if you open up the HelloExample folder in the Windows Explorer, you should find several files inside it. These are MainUnit.pas, MainUnit.dfm and several others. The most important file inside this folder is the HelloProject.exe. This is your applications executable file, if you double click it you'll execute it. If you want to "install" your application on another machine this is the only file you need to copy. Getting HELP from Delphi Let's stop for the moment to explore ways to get help from Delphi in situations when help is necessary. First of all, Delphi is supplied with extensive documentation. If you do not have the printed manuals, those that came (as PDF) with the installation will do. As stated in the first chapter of this course, the books include: . Quick Start - a brief introduction to Delphi, . Object Pascal Language Guide - a complete reference to the underlying Delphi programming language, and . Developers Guide - which covers advanced topics, from creating database applications to creating your custom components. Beside printed materials, Delphi holds a great deal of information in the Help system. Even though you'll need to learn how to use it, it is really worth it - there are many code examples to help you understand all the nuts and bolts of Object Pascal programming. What's more, context-sensitive Help is available from nearly every portion of the Code editor. To get context-sensitive Help from the Code editor window simply place the cursor on the property, event, method, procedure or type for which you want Help, then press F1. Try it. Position the mouse cursor inside the word "Caption" in the Code Editor (the wordCaption you typed in the only example so far) and hit the F1 key.

Page | 5

Once you press the F1 key, a pop up window will ask you to specify more exactly what you want to know. Here comes the hard part: how in the world you know what topic to pick. The "problem" lies in the fact that, in Delphi, many components have properties of the same name (and behavior). To get the help on Form Caption property you need to pick TControl.Caption. Why TControl, when you are working with Form not something called TControl? Well, for the moment this is hard to explain, let's just say that Form derives from something called Control and that Control has a Caption property. What you will find out is that in general, Caption is used for text that appears as a window title. But how will you know what to pick? There is a solution. Point to Object Inspector, Properties page. Select the property you want to find out about and than press F1. Some exercises for you... Since this Course is an online course, there is much you can do to prepare for the next chapter. At the end of each chapter I'll try to provide several tasks for you to get more familiar with Delphi and the topics we discuss in the current chapter. Here are some exercises for you: 0. Learn about the Name property of the Form object. Note that the Name property should tell you what the form does. 1. Explore the Object Inspector and try to figure what properties relate to the Form positioning on the screen (Left, Top, Width, Height, ...) and what happens when you alter them at design time. 2. Try to change the color of the Form from the Object Inspector (Color property) 3. Learn about the BorderIcons and BorderStyle properties and how they relate to visual representation of the Form at run time. 4. Find what exactly DateTimeToStr is used for. 5. Be sure not to miss the next chapter!

Chapter 4 Learn about: properties, events and Delphi Pascal Page 1: Placing Components on a Form

Page | 6

You can find all the components you can place on a form on the Component palette. Delphi supplies a number of components for you to create complex user interfaces. in this Course. I'll explain what happens to code (if some exists) associated with the component. As explained. Placing Components on a Form All forms of a Delphi application have one or more components. When you first place a component on a form. our task is to create a more complex application that involves several Delphi components . This action places a component on the active form. it is your task. This time. Components. Create your second simple Delphi application allowing you to learn hot to place components on a form. methods and events. The idea is to help you understand the Delphi Pascal source and how components operate and communicate with their properties. write event handler procedures to make components cooperate together. For example a Label is used to display static text.again. to decide what happens when a user clicks a button or changes a text in an Edit box. an Edit box is used to allow user to input some data. set their properties. Your second Delphi application We can now start adding components to a form. it is placed in a default position. Activate the only form in a project. As stated before. when you run Delphi a new project (application) is created with one blank form. the application will be pretty simple. you should remember that Windows is even-driven. with default width and height.Welcome to the fourth chapter of the FREE online programming course: A Beginner’s Guide to Delphi Programming. To place a component on a form. by using the Object Inspector. while your application is running a user can interact with any component on a form. Creating your second Delphi Application In the previous chapter we have created a simple Delphi application without going into details of the Object Pascal language behind all Delphi projects. Any combination of components can be placed on a form. You can change the size and position later. or objects. click on it and press the [Del] key. point to the Component palette and select the "Standard" tab. To start. Visual representation of most components is set with their set of properties. Later. as a programmer. usually display information or allow the user to perform an action. Note: to remove a component from a form. Page | 7 . run Delphi. locate its icon on the Palette and double-click it. a Button can be used to initiate actions.

it is not important to create "nicely looking" user interfaces. you can set their properties with the Object Inspector.We will add three standard Windows components and write some example code to see how components work together.Events and Event Handlers Changing Component Properties After you place components on a form. Delphi will provide a default name for the component: Label1.  TEdit : standard Windows edit control. it specifies the name of the component as referenced in code. I suggest you to Page | 8 . Learn about: properties. changes the way a component behaves and appears in an application. Button1. Writing Code . The properties are different for each type of component. Edit1. Altering a component property. All the components have a property called "Name". The Name property is very important.  TButton : use this component to put a standard push button on a form. I strongly encourage you to always try to arrange components on form so they create a user friendly interface. Double click the following three components:  TLabel : use this component when you want to add some text to a form that the user can't edit. Edit controls are used to retrieve text that users type. Here are some suggestions and Standards of Screen Design. some properties apply to most components. events and Delphi Pascal Page 2: Changing Component Properties. When you first place a component on a form. Using drag-and-drop to rearrange the components to appear on a form similar to: Note: even though at this stage of the Course.

I'll do the opposite. an ellipsis button appears near the property name. When a component is selected. To change the component property click on a property name in the Object Inspector. I'll leave all the default component names through this Course . change the Caption (the static text the label displays on the form) of Label1 to 'Your name please:'. Page | 9 . When a property has an associated editor. Change the Text property (text displayed in the edit box .. For example if you click the ellipsis of the Font property a Font property dialog box will appear.g. You can do this by changing the value of the Name property in the Object Inspector.g.give your components a meaningful name before writing the code that refers to them.small square handles appear at each corner and in the middle of each side. Now. to set complex values. To change a boolean property double click the property value to toggle between the states. change the Caption property for Button1 (I'll refer components by their names) to 'Hello. then either type a new value or select from the drop-down list. Note: with the last statement in mind. Width or Left). Some properties can hold a number (e. To actually change a component property you first need to activate it click it to select it .. some can store a boolean value (True or False). In most cases. write your name). a string (e. like Enabled.this text will be changeable at run time) of Edit1 to 'Zarko Gajic' (this is my name. For example. Here are some suggestions on how to give names to components. its properties (and events) are displayed in the Object Inspector. Another way to select a component is to click its name in the drop down list that appears at the top of the Object Inspector.just as they appear when you place them on a form.' (of course without the single quotation marks) Components have different kinds of properties. This list lists all the components on the active form along with their types in the following format: "Name Type". Caption or Text) or even a set of "simple valued" properties.

procedure TForm1. All such components have an event for getting and loosing the focus. To really create an event handling procedure. To see a list of events a component can react on. and double click the OnClick event name. However if you do not specify the code for OnEnter and OnExit (OnEnter got focus. Windows as even-led environment requires the programmer to decide how a program will (if it will) react on user actions. All components have a set of events that they can react on. we'll explain all that in the following chapters. For example.Button1Click(Sender: TObject). If the OnClick event for a button is specified it gets executed. too. has a set of events. Windows sends a message to the application and the application reacts to this new event. beside its properties. select the Button1 component. Just follow along. begin //this is where your code goes end Note: For the moment there is no need to understand what all the words in the above code stand for. select a component and in the Object Inspector activate the Events tab. Each Delphi component. all clickable components have an OnClick event that gets fired if a user clicks a component with a mouse. when a user clicks a button on a form. Remember: components are building block of any Delphi form.Writing Code . OnExit . and double click the event name.Events and Event Handlers To really enable components to do something meaningful you have to write some actionspecific code for each component you want to react on user input. decide on what event you want your component to react.lost focus) the event will be ignored by your application. the code behind each component ensures a component will react on an action. You need to understand that Windows is a message-based operating system. Delphi will bring the Code Editor to the top of the screen and the skeleton code for the OnClick event will be created. The code to respond to events is contained in Delphi event procedures (event handlers). System messages are handled by a message handler that translates the message to Delphi event handlers. Page | 10 . For example. For instance.

new language behavior and keywords were added to deal with the component model.you must write some event handling code in the body of the procedure.. a set of object-oriented extensions to standard Pascal. it lists valid elements that you can select from and add to your code. Here's more info on Delphi Code Insight tools. the component name "Button1". ShowMessage(s)." wait a little.Button1Click(Sender: TObject). In general. compiled. end. var s: string. a procedure must have a unique name within the form. Delphi Pascal is a high-level. It can be said that Delphi Pascal is to Pascal what C++ is to C. hit F9 to compile and run your project. As Delphi was being developed. begin s := 'Hello ' + Edit1.Text + ' Delphi welcomes you!'. Now. The above procedure. click the Button1 ('Hello.". Page | 11 . The name consists of: the name of the form (prefixed with T) "TForm".'). We'll now write some code for the OnClick event handler of Button1. A few words on Delphi (Object) Pascal The code you write inside event procedures is Pascal code. Delphi component event-driven procedure. Change the text in the Edit box and hit the Button again. Just creating an event handler does not guarantee your application will do something on the event . Object Pascal or Delphi Pascal (as I will mostly call it).. and the event name "Click".. A message box will pop up saying 'Hello Zarko Gajic. a full stop ". Alter the above procedure body to: procedure TForm1.As you will understand more clearly through this course. For any component there is a set of events that you could create event handlers for. strongly typed language that supports structured and object-oriented design. Delphi will display a list box with all the properties of the edit box you can pick.. Delphi Pascal enables you to take advantage of object-oriented programming to its fullest. In general. is named for you. Delphi welcomes you!'. When the program starts. is the language of Delphi. A few words on Delphi Code completion When you reach to the second line and write "Edit1.

set their properties and even do a small do-somethingfunny Delphi application..this results in a pop up box your see above.  The first line under the begin keyword. Variables have to be declared before they can be used. Again. Try adding a code for the OnCreate event of a form to make a form appear centered on a screen. Let's see. after you finish reading this chapter: 1. actually the string type. not too smart. ShowMessage(s). var s: string. We do this after the var keyword. Use the Font property Editor to alter the font of the TLabel component 3. By now you should know how to place components on a form. If you ask Delphi about the Text property of an Edit component. before the end keyword.. sets a value for the variable s. Since this Course is an online course. 5. Here are some exercises for you. Find out about the PasswordChar property of the TEdit component to create a simple password dialog form 4. there is much you can do to prepare for the next chapter. is the one that calls the message dialog and sends it the value of variable s .Text + ' Delphi welcomes you!'. This assignment involves reading a value of the Text property for the Edit component. Play with the Color property of the Form object 2. That text is of the TCaption type. Variables in Delphi Pascal hold information (values).What follows is a simple explanation of the code that runs this application. s := 'Hello ' + Edit1. you'll find out that it holds the text string that is displayed in the edit box. Be sure not to miss the next chapter! Chapter 5 Understanding the Delphi unit source Page 1: Delphi Unit source code Page | 12 .. Some exercises for you. declares a string typevariable.  The last statement. Be sure to visit all the links in the above paragraph. not too hard but serves the purpose. Also. At the end of each chapter I'll try to provide several tasks for you to get more familiar with Delphi and the topics we discuss in the current chapter.  The first line under the procedure name. make yourself familiar with the Position property of the TForm object. That's it..

For the moment reefer to the example in the last chapter. Messages. Interface. implementation. uses and other keywords explained in easy language! Understanding the unit source In the previous chapter you have created your second simple Delphi application without going into details about the Delphi Pascal keywords that appear in each Delphi unit. SysUtils. especially the unit source. After we have placed a Label. This time. an Edit box and a Button. Take a closer look at exactly what each keyword means by examining each line of the Delphi form unit source code. 02: interface 03: uses 03: Windows. the source code looked like: 01: unit Unit1. As you know already by now.Welcome to the fifth chapter of the FREE online programming course: A Beginner's Guide to Delphi Programming. and added an OnClick event handling procedure for the button. 04: type Page | 13 . Variants. Controls. 03: Graphics. forms are visible building blocks of all (well. Dialogs. Classes. our task is to take a look at exactly what each keyword means by examining each line of the forms unit source code. The best way to describe the unit code is to take a look at the source. The unit contains the source code for any event handlers attached to the events of the form or the components it contains. Each form in a Delphi project has an associated unit. at least 99%) Delphi projects. Forms. StdCtrls.

Button1: TButton. Label1: TLabel.dfm} 19: procedure TForm1. Page | 14 . 20: var s: string.05: TForm1 = class(TForm) 06: 07: 08: 09: Edit1: TEdit. procedure Button1Click(Sender: TObject).Button1Click(Sender: TObject). 17: implementation 18: {$R *.Text + ' Delphi welcomes you!'. 10: private 11: { Private declarations } 12: public 13: { Public declarations } 14: end. 21: begin 22: s := 'Hello ' + Edit1. 15: var 16: Form1: TForm1.

Lines in red were added by you in the previous chapter. which is followed by the interface. let's just say that such words are a part of Delphi object oriented programming. black lines appear in the forms unit source the first time you add a form to a project.. Delphi creates the corresponding unit file with the skeleton code marked black. we will discuss them in the following chapters more clearly Understanding the Delphi unit source Page 2: Interface. it is completely up to you to Page | 15 .. object and similar will be mentioned. The unit name (Unit1 in the above source) must match the unit file name on a disk. the UNIT keyword must be the first line in the source. Several new words like class. do not get frightened if you do not understand what they mean. First. When you add a component on a form and write an event handler for it. followed by a unit (file) name. The unit heading starts with a word unit (line 01). We'll now explore and try to figure what each line stands for. implementation. The rest of the article will discuss parts of the unit source. Lines colored in green were added by Delphi when you have placed those three components on a form. and finalization sections. Delphi will place the corresponding code at the exact location in the unit file. Whenever you create a new form.23: ShowMessage(s). The initialization and finalization sections are optional. Note another thing: in the above code. This strict format is "predefined" by Delphi. You should change the unit's name only by using the File-Save As command from the Delphi IDE main menu. implementation. In a single project all unit names must be unique. a note: Delphi units follow a predefined format. followed by INTERFACE. initialization. its associated unit source is already created with special keywords and type declaration. For example. 24: end. meaning that when you add an empty form to a project. Of course. 25: end. uses and other keywords explained in easy language! The UNIT keyword A unit file begins with a unit heading.

The code from line 04 to 14 declares the existence and structure of a class called TForm1. since it does not appear on the component palette . if you add a TOpenDialog component on your form (Dialogs page on the component palette). This section is used to declare any publicsections of code that appear in a unit. Messages. Everything else is hidden. As you drop components on a form.pas has a uses clause.you must manually add the word Registry to the uses list. The INTERFACE USES section If the interface section includes a uses clause. The INTERFACE TYPE section Another part of the interface section is the type section. The entire contents of the interface section. all it sees is the interface section.decide how will you name your units. Page | 16 . In most cases. The INTERFACE section The interface section of a unit starts with the word interface (line 02) and continues until the word implementation (line 17). The form type declaration (or form class declaration) section introduces the form as a class. variable and procedure declarations. In some situations. required by a program. like 'MainUnit' for Main form (form with a Name property set to 'Main'). the necessary units will be added automatically to the uses clause. you can see that the code for unit1. etc are all standard Delphi units. internal to the unit. For example. When any other part of the program looks at a unit. Suppose you are to use the TRegistry object. SysUtils. The Windows. and a variable declaration section. you'll need to manually add units to interface uses clause. the Dialogs unit will appear in the uses clause because it contains the logic for the TOpenDialog component (and other Dialog components). it must appear immediately after the word interface. You could say that the interface section contains a list of items in the unit that other units can use. a type section. designed to access the Windows Registry. In most cases the interface section will define several "subsections". part of the implementation. are visible to any other unit which uses this unit. including type. In most cases you'll want your units to have the name similar to the name of the form to which they are linked. You cannot drop the TRegistry component on a form. A uses clause (line 03) lists units used by the unit. Be sure to give name to units in the early stage of a form design development. all necessary units are placed in the interface uses clause when Delphi compiler generates and maintains a units source.

An object: DELPHI PROGRAMMER is a specific instance of a class. When you need to read a value from this particular edit box you use the Edit1 variable.16) of the interface section is used to declare (create) a Form1 object as an instance of the TForm1 class. The IMPLEMENTATION section The implementation section is defined as everything between the implementation word and either the initialization statement or the end of the file (as denoted by the end. you could create a variable of that type in this part of the interface section.Text'. a part of the Creating Custom Delphi Components . Each event handling procedure for a form events or events for components dropped on a form (form fields) will have its declaration (line 09) in the interface type part. The basics of object oriented programming in Delphi will be discussed in the next chapter of this course. properties and methods) as a part of this unit. however some words must be explained now. The INTERFACE VAR section This part (line 15. Edit1 is a variable of a TEdit type. The implementation section of a unit can contain its own uses clause as well.A few words on classes and objects I'm aware that this is not the place to explain OOP in Delphi. A class. For example. and can contain both declarations and code. For example. and properties. or class type. but I sense that something must be stated.Inside and Out article. like in 's := Edit1. keyword). methods. in real world. which you see on the screen when you run the program. The TForm1 is a class inherited from TForm (line 05). It can expose methods like: Write_Program and Talk_To_Users. Instances of a class type are called objects. A class is something that does not truly exists. A few words on using another unit (form) Page | 17 . If you have created your own data type (with fields. please refer to Hiding Data. The implementation is where you write code that performs actions. defines a structure consisting of fields. This section is private to the unit. a class PROGRAMMER can have properties like: Years_Of_Experience and Projects_Developed. For an explanation on private and public parts (lines 10 through 14) of a class declaration. Each component dropped on a form becomes a field (or variable) of the TForm1 class (lines 06 through 08).

unit name: AboutFormUnit) when you click on this button. such as freeing any resources allocated in the initialization part. If your unit needs to perform any cleanup when the application terminates.the structure of such a unit Page | 18 . If we want to initialize any data the unit uses. If in some stage of the development of your project you decide to save AboutFormUnit under a different name . we can add an initialization code to the initialization section of the unit.you will need to change the call to any procedure inside that unit. The second part is one (or more) units attached to forms . This is the reason why you should give meaningful name to units in the early stage of form (unit) development. you use the following syntax: AboutFormUnit. When an application uses a unit.) and a procedure name. You can see the structure of the project file by pointing you mouse to Project|View Source from the Delphi main menu. when you have learned about the structure of a Delphi form unit.. This fact is very important. it's time to see what other units can appear in a project. you can add a finalization section to your unit. What you want to do is to show an about box form (form name: AboutForm.As you will see in the following chapters of this course. Suppose you have a main form (form name: MainForm. Every Delphi program has at least two main parts.. To be able to do this the MainFormUnit must use the AboutFormUnit. This means that a procedure or function declared and defined (implemented) in the implementation section cannot be called from another unit unless its header is listed in that unit's interface. but before the final end. the code within the unit's initialization part is called before the any other application code runs. The INITIALIZATION and FINALIZATION sections These two sections are optional. Simply put.dpr. Other units of a Delphi project Now. The finalization section comes after the initialization section. Anything that appears in a unit's implementation section that is not referenced in the interface is private to that unit. since the name of the unit will no longer be AboutFormUnit. The first is a project file such as Project1. this means that one form can call another form. the AboutFormUnit should be placed in the implementation uses clause. they are not automatically generated when we create a unit. unit name: MainFormUnit) in a project with an 'About.SomeProcedureName(parameters) Note that the call to a procedure SomeProcedureName consists of a unit name (AboutFormUnit) followed by a period (. To actually call a method (procedure or function) from MainFormUnit that is declared in the AboutFormUnit. a (form) unit can use another unit.' button on it.

a set of object-oriented extensions to standard Pascal. Chapter 6 Delphi Language: tutorials Delphi language. A Code Unit contains code that is called from other units in the project. and global routines defined in your unit. Looking in the past: Code Explorer In the second chapter of this course you have learned the main parts of the Delphi IDE.. quick compilation. is the language of Delphi. Its benefits include easy-to-read code. Variable Scope Object Pascal Variable Scope: now you see me. you will probably store them in a code unit. The Code Explorer makes it easy to navigate through your unit source. units don't have to be associated with forms. one part of that window was left unexplained . By default. Unit. with practical and easy to understand code snippets. Loops Repeating operations in Object Pascal in Object Pascal in Object Pascal in Page | 19 .. and the use of multiple unit files for modular programming. Delphi Pascal is a high-level. When we were discussing the Code Editor window. Each tutorial will help you to understand a particular feature of Delphi Pascal language.is discussed through this article. However. Here's a list of tutorials. When you start building libraries of useful routines. To add a new code unit to Delphi application choose File-New . like Button1Click. classes. it only lacks the type declaration for the "linked" TForm class. I use the Code explorer to quickly jump to a procedure or type declaration by simply double-clicking on an item name. the Code Explorer is docked to the left of the Code editor. properties. Typed constants How to implement persistent values between function calls.the Code Explorer. global variables. strongly typed language that supports structured and object-oriented design. methods. The structure of a code unit is similar to form unit. that will help you learn Delphi Pascal. an introduction to Delphi Pascal. It also shows the other units listed in the uses clause. now you don't. compiled. The Code Explorer contains a tree diagram that shows all the types.

Functions and Procedures Creating user defined subroutines in Object Pascal.Object Pascal. Records in Delphi Learn about records. Decisions Making decisions in Object Pascal or NOT. why. String Types in Delphi Understanding and managing string data types in Delphi's Object Pascal. Delphi's Pascal data structure that can mix any of Delphi's built in types including any types you have created. What are pointers. Here are some intermediate Delphi problems and articles for everyday development tasks. Variant Records in Delphi Why and when to use variant records. Statements/Properties/Variables The basic layout of a Pascal/Delphi program. At the end of each chapter I'll try to provide several tasks for you to get more familiar with Delphi and the topics we discuss in the current chapter. there is much you can do to prepare for the next chapter. Recursions in Delphi Writing and using recursive functions in Object Pascal.. plus creating an array of records. Chapter 7 Sophisticated Delphi Pascal techniques for Beginners Sophisticated Delphi Pascal techniques for Beginners. Since this Course is an online course. Ordinal and Enumerated Data Types Extend Delphi's built-in types by constructing your own types. Pointers in Delphi An introduction to pointer data type in Delphi. Time to extend your Delphi Pascal knowledge to the max. Here are some intermediate Delphi problems and articles for everyday development Page | 20 . Learn about differences between Short. Long. Time to extend your Delphi Pascal knowledge to the max. Some exercises for you. Arrays in Object Pascal Understanding and using array data types in Delphi. Wide and null-terminated strings.. Welcome to the seventh chapter of the FREE online programming course: A Beginner’s Guide to Delphi Programming. when and how to use them. Routines in Delphi: Beyond the Basics Extending Object Pascal functions and procedures with default parameters and method overloading.

after you finish reading this chapter: Chapter 8 Commenting Delphi code Learn the art of helping yourself. Welcome to the eighth chapter of the FREE online programming course: Page | 21 .. Base Conversions. Each tutorial will help you to better understand a particular feature of Delphi Pascal language. At the end of each chapter I'll try to provide several tasks for you to get more familiar with Delphi and the topics we discuss in the current chapter.. if you are unfamiliar with the term. just follow the article code and you'll understand it completely. The purpose of adding comments to Delphi code is to provide more program readability using understandable description of what your code is doing. a text-mode program that runs without a graphical interface. Auto completing Dates Date manipulation: improve your code.tasks. with practical and easy to understand workigng code examples. Here are some suggested actions for you. Errors and Exceptions How to handle errors and exceptions in Delphi. Int to Hex. and more Routines for converting Int to Bin. Even more: see how to capture the output of a console application in a GUI Delphi program. Some of the articles use Windows API calls. Since this Course is an online course. let them type faster NO GUI Delphi applications Creating a console mode application with Delphi. Int to Roman and vice versa Disk in drive A: Some useful routines when playing with floppy disk and Delphi Start from Delphi Executing and running applications and files from Delphi. that will help you learn more of Delphi Pascal. when it comes to code maintenance. Various tutorials and articles on using Delphi Some exercises for you. and articles. there is much you can do to prepare for the next chapter. Delphi Pascal: a step forward Here's a list of tutorials. do not run away. Text Files in Delphi Handling ASCII files from Object Pascal code.

you should know that after a few months even the *simplest* functions will be hard to read .. The purpose of adding comments to code is to provide an understandable description of what your code is doing .. That is.pas): Page | 22 .you'll simply forget what the idea was. only comments out the current line. There are two ways to add block comments. any text between a left brace and a right brace constitutes a comment.. How and When Even though at *this* stage of your latest Delphi project development you are pretty sure about what every line in the source does. In the next example the j:=5 part of the code is commented. text between a left-parenthesis-plus-asterisk and an asterisk-plus-right-parenthesis also constitutes a comment. Commenting code is a manner of adding (displaying) textual information in relation to your code without it being parsed by compiler (or compiled in an exe). var i.to make your source more readable .e. i:=0. There are two kinds of comments in Delphi: block comments and line comments. Other users who attempt to maintain your code will thank you as well. The purpose of adding comments to Delphi code is to provide more program readability using understandable description of what your code is doing Why. you will thank yourself.j :integer .. Learn the art of helping yourself. They are put at the start of the bit of code you want to comment out and stop the compiler *seeing* any of the code after the comment symbol and until the end of the line. Line comments (the // symbol . The { } symbols and (* *) are used (in pair) to comment out a block of code (i.A Beginner’s Guide to Delphi Programming.for you and for other developers that may need to alter (or understand) the code. as the name suggests. //j:=5 .double-slash) were added within Delphi source. When you come back to maintain the code a year later. when it comes to code maintenance. For example (from Windows. more than one line).

{ user default } . Delphi expects the comment to end with a closing brace "}".. if you have a large amount of code that you want to comment out. However. Notice. {$WARNINGS OFF} tells the compiler not to generate warning messages. and not an asterisk-paren "*)". depending on whether you have already used those operators in the code. have one set of comments inside another) in Delphi Pascal. that a text that contains a dollar sign ($) immediately after the opening { or (* (for block comments) is a compiler directive . You must be quite careful when using block comments as it often seems the case that you could want to comment out a chunk of code that already has comments in it.. But. Here's a definitive way to comment out code: {$IFDEF False} your code goes here do not fear if you have used Page | 23 . however.{The name immediately following SUBLANG_ dictates which primary language ID that sublanguage ID can be combined with to form a valid language ID. if you start a comment with an open brace "{". For example. { language neutral } {$EXTERNALSYM SUBLANG_NEUTRAL} SUBLANG_DEFAULT = $01.e. Note one more thing.something definitively not ignored by the compiler. the problem with this is that we can't nest comments (i. none of the above operators may help.} SUBLANG_NEUTRAL = $00.

line or block comment inside this block! {$ENDIF} As a help to developer. to convey whether global variables are changed within the procedure.  The alternative notation of (* *) shall be reserved for temporarily removing code ("commenting out") during development. never mind my 10+ years of Delphi Page | 24 . don't forget to update existing comments if the code change causes the description to be inaccurate.  Comments preceding functional blocks of code should be aligned with the code on the left hand side  When documenting source code.  Tricky. Chapter 9 Yes. In certain circumstances. to state whether those arguments should be within a certain range of values. Delphi code editor (by default) uses italics and a blue font to specify that a peace of code is actually a comment Delphi Commenting TIPS  Delphi Pascal doesn't support nesting comments of the same type within each other.  The use of // shall be restricted to one-line comments.  Each unit should begin with a comment block. if there is. you have created an additional code-maintenance problem. and to relate the procedure's return values. // Add one to i  Misleading comments are worse than no comments at all.  If your comments speak to how the code works. you will use comments to document the arguments passed to a procedure. Always make sure the description still describes the new functionality.  Avoid making obvious comments: i := i + 1.  Each class definition and each method (procedure/function) within a unit should have a separate function comment. and/or clever coding techniques should always be documented (if not avoided entirely). even the experienced Delphi programmers make mistakes It happens to me all the time. Avoid "saving it for later. or. usually { } pairs shall be used.  Always enter or revise your comments as soon as you write the code.  For commenting. because comments that describe how code works must be revised whenever you change the code. instead of to what it does. above the method." because there is rarely time to do it later. you will not understand the code as well when you come back to it. that generally describes the contents of the unit. confusing.

begin j := 1 l := 5. Errors and How to Prevent Errors Page | 25 . for k:= 1 to l do j = k * j. Below is a solution to the problem . Incompatible types: 'String' and 'Integer'. constantly pop up! Suppose you are writing a recursive procedure to calculate the factorial value of an integer.to calculate 5! (=120). The procedure should also output each iteration value to the screen in a console mode Delphi application. after pressing the F9 key (run command in the Delphi IDE).programming experience. How many possible compile (or logic) errors (not warnings) can you count? How many? I'm counting four. Missing operator or semicolon. writeln(j) . In less than 7 lines of code there are 4 errors . j : string. var l. end. the program will only output one number: 120. The output should look like: 1 2 6 24 120 Here's the procedure: [line [line [line [line [line [line [line [line [line [line 0] 1] 2] 3] 4] 5] 6] 7] 8] 9] procedura ErrorTesting. k : integer. Compiler errors like "Missing operator or semicolon" or ":= expected but = found".and on the first look the code looks ok! Line Line Line Line 0: 4: 5: 7: Error! Error! Error! Error! Declaration expected but identifier 'procedura' found. := expected but = found There is even one logic error! If you correct all 4 errors in the source.

Many times. while run time and logic errors tend to crash your program right in front of the user's eyes! The good thing about design and compile time errors is that Delphi will not let you build (compile) the project . changing '=' to ':=' solves the problem. Design and compile time errors are seen only by a developer.therefore stopping you deploying a non working version of the application. The bad thing about the run time and logic errors is that Delphi will build the exe for you . even the simplest program. I'm pretty sure that in [line 5] i := 5...but that exe might or might not work properly. Setting the TabOrder property of any control on a form to more than 32767 will result in a design time error. Simply. This is the second page of the two page article! Design time and compile time errors Fighting against these two is fairly easy. Delphi will stop the compile process and display the errors inside the Messages window. if you are unsure about some of the errors (that is how to fix them). we tried to do a logical operation '=' on the expression. Page | 26 . compiler errors will prevent you from building the exe for the application. However. By mistake. A message box will pop up telling you what the boundaries are for the property values. Read on to lean how to prevent and fix common coding errors. How about 'Missing operator or semicolon'? Delphi warns that the error is in line 5. When you press the F9 key and there are some errors in the code. An example. On the other hand. you should select that error inside the Messages windows and press F1 (Help). In the case of ':= expected but = found'. If you know how to correct the particular error. the error description will provide enough information for you to be able to correct your code. you simply go to the line of code the Delphi compiler reported and fix it.There are four types of errors a Delphi programmer can experience while developing. what we wanted to do is to assign the value of the right side (k * j) of the = sign to the variable (j) on the left.

You. a semicolon is often missing on the previous line! Run-time and Logic errors Fighting against these two is. a fairly hard task. or more scarily. Firstly.there is no missing operator! Ah. those nasty logic errors. as a beginner developer. yes. Logic Errors Oh.' at the end of line 4. They can go unnoticed indefinitely..in order for you to be able to recreate the situation and correct the code. Delphi compiler actually sees j := 1 i := 5. in Pascal language. We have a missing '. Secondly. unfortunately. Statement can be a simple or structured statement that does not change the value of counter. where we need 5 lines. for each iteration of the for loop. The "Preventing Access Violations in Delphi code" article provides a more indepth discussion on run time errors. do Delphi statement.the output will only contain one line. But why did Delphi stated that the error is in line 5? Remember that. each line of code must end with the '. There is a logic error in the code above . The problem is in the for . you'll not know about those errors until the users of your application report them.' sign. Therefore. in an accounting application). you'll be truly happy if those users succeed in explaining why your program stopped working . (two lines) as (one line) j := 1 i := 5. The for loop is defined as follows: for counter := initialValue to finalValue do statement The most tricky part is the "statement". In the code above. would most likely run into problems with Page | 27 . If the structured statement consists only of simple statements (that is more than one) it MUST be surrounded with the begin / end pair. they can go unnoticed indefinitely and really mess with the users data (for example. Structured statements are built from other statements.

Help yourself Spend a few bucks and buy a book! "The Tomes of Delphi Developer's Guide to Delphi Troubleshooting". This book is an alphabetical reference to nearly 800 design-time. covers all versions of Delphi. and run-time error messages of Borland’s Delphi Object Pascal language. DO surround that line with the begin / end pair.using the for loop with a structured statement as if it were a simple statement. Therefore our for loop should look like this: for k:= 1 to l do begin j = k * j. writeln(j) . how to quickly resolve the problem. Code samples clearly demonstrate how to eliminate the errors in different versions of Delph Chapter 10 Your First Delphi Game: Tic Tac Toe Page 1: Preparing the Game GUI Welcome to the tenth chapter of the FREE online programming course: A Beginner’s Guide to Delphi Programming. Designing and developing a real game using Delphi: Tic Tac Toe. by Clay Shannon. compile-time. Note: ALWAYS. if you have a for loop with only one simple statement inside its body. end. After nine chapters of this course you are ready for some real action. and what type of project would you be more interested than creating a game? Page | 28 . always write Delphi commands that expect a simple OR a structured statement like they expect a structured statement!! In other words. It's time to create a full working Delphi project. stop playing with Delphi. Error message entries include an explanation of what actions or omissions may have caused the error message. Ok. and how to avoid receiving the error message in the future.

naturally we'll use the form object Delphi "prepared" for us. diagonal or vertical.pas. game proceeds with the opponents alternately placing their marks at any unoccupied cell. Next. The goal of this game is to be the first one with three marks in a row. The Save As dialog box will be displayed. I suggest you to rename that default form. Our game will require only one form where all the action is taking place.pas and click Save. Here are the topics you'll practically try and learn here:  Building a program GUI  Building a program Logic  Working with arrays  Building Functions. and name it 'TicTacToe'. the Rules Tic Tac Toe is a traditional game.. save the project. played by two opponents that alternately place X's and O's into 3x3 playing field. You will then be prompted to save the project. the default name will be Unit1. Preparing the Tic Tac Toe Game At this moment you should have your copy of Delphi up and running. It is advisable to save every project in a separate folder. Now. Procedures using Parameter Passing  Casting one Delphi object to another Tic Tac Toe. by default Delphi will name this project 'Project1' (DPR). a new (standard Windows) project is created hosting one Form object (and the associated unit). by assigning the string 'frMain' to the Name property (using the Object Inspector). when you start Delphi..Your goal in this chapter is to create a simple game using Delphi.pas to Main. Saving for the first time Before we move on. where the row can be horizontal. change the name of the Unit1. the game is a draw. of course we'll Page | 29 . use the 'Create New Folder' toolbar button to create a new folder. If all cells are occupied and both players don't have a winning combination. After the first move. players have to decide who will go first and who will mark his moves with an X. as you know by now. The offered location will be inside the Projects folder under the Delphi install folder. providing you with the option to first save the form's unit file. By default. Before the game starts. by pointing to File | Save All (Delphi IDE main menu). therefore. Back to the "drawing board" .

Size = 16 Font. For this purpose we will name the label 'lblCell0'. just use Ctrl+Shift+S (keyboard shortcut for Save All). let's say. and choose 'View As Text' command from the context pop up menu. GUI Ok. name it. The easiest way to do that is to create first label.Style = [fsBold] Layout = tlCenter end Note: If you right click anywhere on your form. Later on. Use the Object Inspector to set the following properties: object lblCell0: TLabel // note Name = lblCell0 Left = 8 Top = 8 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell0' Color = clCream Font. first we build the game GUI (graphical user interface). you are presented with text description of the form’s attributes. Your goal is to create a "grid" consisting of 9 cells. 'TicTacToe'. X or O. when you want to save the current status of your project. color. Drop one on the form. and set every other property. For the moment we only have a form object named 'frMain'.Name = 'Tahoma' Font. Note.change it to. That's it. choose the appropriate font. Page | 30 . use Object Inspector to change the Caption property to 'About Delphi Programming: Tic Tac Toe' The playfield. we'll need 9 labels looking similar. The simplest is to use the Label component from the Standard palette. where each cell will display either nothing.

Caption = 'Score Board') with six labels (names : lblX. lblO. Label object with Name lblCell0 zero should be in the top left corner. click the ellipsis button.  One TGroupBox object (Name = 'gbScoreBoard'. we add some more objects to the form:  Two TButton objects (Standard Palette). To switch back to 'For View'. select this RadioGroup and point to the Items property. only the Name property will be re-set to Label1. lblOScore. Now. note that you must also manually change the Caption property to lblCell1. The value of the ItemIndex property determines which radio button is currently selected. Select the label object. Alter it manually to lblCell1. After we shape up the first (cell) label. Make sure that the Name properties are sequential in the grid. just right click this "code" window and choose 'View As Form'. name them 'btnNewGame' and 'btnResetScore'. and the bottom right label should be lblCell8. Go on and create all nine labels.  One TRadioGroup object (Standard Palette). select the form (click anywhere on the form) and press CTRL+V to create another label object. We do not really need the Caption property at this moment. The second object will inherit all properties from the first one. we will build the game logic on the cell position / name. Now.inside the Code Editor window. we can create other eight elements of the grid. but if you delete it (making it an empty string) you will not be able to differentiate one cell from another (without selecting one. set the Caption property to 'First to play'. lblXScore. Add two radio buttons. of course). lblMinus. When you are finished your form should be looking something like: Next. Page | 31 . name it 'rgPlayFirst'. each string in Items makes a radio button appear in the radio group box with the string as its caption. and press CTRL+C.

. the bottom-right [3. 3]. etc. who is on the move (sPlaySign). we move on to game logic and initialization. we can place all cells in one-dimensional array. Beside playfield variables we need to declare variables that will tell us how many moves are played (iMove). and two variables that will hold the number of victories for each player (iXScore and iOScore)..pas. Your First Delphi Game: Tic Tac Toe Page 2: Game Initialization The GUI design part of the Tic Tac Toe game is complete. Initializing the Tic Tac Toe Game Before we start coding we have to decide how to represent the playfield (label/cell grid) in the computer memory. Once we have the game GUI. the top-right corner will be [1. Since we want to automate our program as much as possible we will represent cells as a two dimensional array. Each cell can be treated individually. we can proceed to game logic and initialization. Two playfield variables will be created for playfield data. is the game in progress or is the game over (bGameOver). or we can make two-dimensional array. 1]. as the code will be more readable if we store each player moves separately. Place the following code above the implementation keyword inside the unit Main. just below the frMain variable: Page | 32 . The top-left "corner" will have an index of [1.lblColon). 3].

var frMain: TfrMain. //added by Delphi .. we have to define our "array type". Now. sPlaySign : String. implementation .do NOT delete iXPos : TXOPosArray. 1.FormCreate(Sender: TObject).. iXScore : Integer.3] of Integer. iOScore : Integer. bGameOver : Boolean. iMove : Integer.. like: type TXOPosArray = array [1. begin Page | 33 . inside the FormCreate event handler (double click a form to create one) we add the following code: procedure TfrMain. iOPos : TXOPosArray.3... Since we'll need to send an array as a parameter to a procedure. Note: the TXOPosArray (two-dimensional integer array ...holding 9 elements) type is declared above the form type declaration.

begin for i := 1 to 3 do begin for j := 1 To 3 do begin Page | 34 . Playfield Initialization During a playfield initialization we will clear the cells (that is. iOScore := 0. Captions of all Labels with lblCellX names) by setting the Caption property to '' (empty string). InitPlayGround.inside the InitPlayGround procedure. Also. k: integer. add the next code: procedure TfrMain. var i. It is necessary to set iXPos and iOPos arrays to zero. This is because we don't want to change their values until user presses the btnResetScore button. All other variables have to be initialized after the end of each game . To create the InitPlayGround procedure. end. we have to reset the number of moves to zero (iMove). go to the Code Editor window and below the implementation keyword. we have to check the value of the rgPlayFirst radio group ItemIndex property to determine which player will play first in the next game. j. The iXScore and iOScore variables are initialized when the form is created. and set the bGameOver variable to False.iXScore := 0. Beside that.InitPlayGround.

and consider the next two lines in the above code: k:= (i .. . Note that you will also need to add this procedure's header in the private section of the form declaration (interface part of the unit): . 8 TLabel(FindComponent('lblCell' + IntToStr(k))). bGameOver := False. end.Caption := ''. 8 TLabel(FindComponent('lblCell' + IntToStr(k))). iXPos[i.. iOPos[i][j] := 0. Stop for the moment.1. iMove := 0.1.ItemIndex = 1 then sPlaySign := 'O'. j] := 0.k:= (i ..ItemIndex = 0 then sPlaySign := 'X'. private procedure InitPlayGround. // 0 .. if rgPlayFirst.Caption := ''. end.. if rgPlayFirst.1) * 3 + j . Page | 35 . end. // 0 .1) * 3 + j ..

Bad practice! The above code "tip". lblCell8.Caption:=''.What we want to do in the InitPlayGround procedure is to set the caption to all lblCellX label components to an empty string. After we verify that the game is in progress. . searches for a component on a form by its name (FindComponent). CellIndex would have the value Page | 36 . X. your turn! Until now we have created the Tic Tac Toe game GUI and we've initialized the variables. casts it to TLabel and assigns an empty string to the Caption Property. Your First Delphi Game: Tic Tac Toe Page 3: Player X. One way to achieve this is to use 9 lines of code: lblCell0. lblCell1. lblCell7. It is very important to be sure that the current game is in progress.Caption:=''. your turn! (or O if you prefer) Event OnClick for the particular lblCellX component will be called each time a player presses a (left) mouse button on the Label component making the playfield grid.in a procedure GamePlay that expect an integer parameter named CellIndex.Caption:=''. There is one more thing we have to check before we process the user input.. We are ready to make our first move. In the case that the game is over. lblCell2.. we will simply exit this procedure. we can process the user input .Caption:=''. FindComponent returns the component in the forms Components property array with the name that matches the string in the only parameter required.Caption:=''.

if TLabel(Sender). If the cell already hosts 'X' or 'O'.1)). end. CellIndex := StrToInt(RightStr(TLabel(Sender). the Code Editor receives the input focus. To create an OnClick event handler procedure for the first label (lblCell0). var iWin : integer. You'll need to manually add this unit to the uses list in the interface uses Page | 37 . begin if bGameOver = True Then Exit. go to Object Inspector.set to 0 for the top-left corner cell (label) of the playfield and the value 8 for the bottom-right corner. cast it to TLabel and test the Caption property. if the label clicked is named lblCell5. In order to "see" whether the cell is occupied we use the Sender parameter. we display a message using the ShowMessage Delphi function.Caption <> '' then begin ShowMessage('Cell occupied!'). we exit the procedure. for example. To get the CellIndex we extract the cell number from the label name. iWin := GamePlay(CellIndex).lblCell0Click(Sender: TObject). the CellIndex for that label (cell) is 5.Name. switch to Events and double click the column right to OnClick. end. and you can enter the programming logic code for the OnClick handler: procedure TfrMain. Either way. CellIndex : 0. Note 1 : to assign a value to CellIndex we use the RightStr function defined in the StrUtils. Note 0: If the cell is occupied (was clicked before during the game).. Exit.8. or select the lblCell0 component.pas unit. simply double click it.

which means that user didn't click on the already occupied cell. To have the lblCellX (where X stands for 0 to 8) share this specific OnClick event handler. 3 to [2.. iXPos and iOPos arrays hold information about already played moves by the X and O player. The user's choice must be the regular move. 8 to [3. y := (xo_Move Mod 3) + 1. check the How To Share an Event Handler in Delphi.1] . Then we have to translate the coordinates form one-dimensional to two-dimensional array. with the above code.2] . b) Go the Events page of the Object Inspector c) In the right column to the OnCLick.3. Inc(iMove). x := (xo_Move Div 3) + 1. let me refresh your memory.. var x. is to use this one procedure for all lblCellX label components and their OnClick events. begin Result := -1. from the drop down list pick the lblCell0Click. 1 to [1. the compiler will report an error: "Undeclared Identifier 'RightStr'"!! Note 2: The above event handler was coded with the following in mind: there is no need to have a separate event handler for each and every of 9 cells making the playfield. y : 1. Page | 38 .. If you forget to do that. Processing the Move Before we start with processing. The xo_Move value of 0 will be translated to [1.GamePlay(xo_Move : Integer):integer. we have to increase the counter (iMove) by one.clause of the Main. function TfrMain... iWin : integer. .. do the following: a) select the "rest" of the eight lblCell label components (Shift + Click 'em). iMove tells us how many moves are already made. If the user makes a regular move. the next time you try to compile your project.pas unit.1].3]. If you experience difficulties.. What we are preparing for.

if sPlaySign = 'O' then begin iOPos[x. iWin := CheckWin(iOPos).y] := 1. the variables will have the following values: Take a look at the values when O player makes his move in the middle of the playfield: Page | 39 .Caption := sPlaySign. TLabel(FindComponent('lblCell' + IntToStr(xo_Move))). end.Also we have to check which player has made the move because this routine will process the input from both players. end else begin iXPos[x. when the player X places his mark in the top left corner of the playfield. For example.y] := 1. iWin := CheckWin(iXPos).

CheckWin will return the number of the winning combination. //mark victory if sPlaySign = 'X' then begin iXScore := iXScore + 1. If the player succeeds to win. lblXScore. if iWin >= 0 then begin bGameOver := True.Caption := IntToStr(iOScore). lblOScore. CheckWin will return -1.Caption := IntToStr(iXScore). the current result will be placed on the scoreboard. end else begin iOScore := iOScore + 1. In case that we have the winner the game will end. Page | 40 . and a congratulation message will pop up.After every move we call the CheckWin function to look for the winning combination. end. Result := iWin. If there is no winner.

//function GamePlay Ok. Page | 41 . Do we have a winner? After each move we have to check if the game is over. we now have the main part of the code logic done. what's left is the CheckWin function. O player wins the game. and the current game is over. column or diagonal. it is a draw. if (iMove = 9) AND (bGameOver = False) Then begin ShowMessage('It''s a Draw!'). if the game is still in progress. we have to allow the other player to make his move. we have the winner. On the other hand. To look for a possible winner we count the number of X's and O's in each row. column and diagonal. end. Game could end in three ways: X player wins the game. if sPlaySign = 'O' Then sPlaySign := 'X' else sPlaySign := 'O'. If players played nine moves and there is no winner.Wins!').ShowMessage(sPlaySign + ' . end. bGameOver := True end. If the player manages to put three signs in row. or it is a draw.

i : Integer. function TfrMain.CheckWin(iPos : TXOPosArray) : Integer..j]). for j := 1 To 3 do Inc(iScore. Inc(Result).//for i . for i := 1 to 3 do begin iScore := 0. for the rest of the function look at the project code. j : Integer. iPos[i. begin Result := -1. //in rows? iScore := 0. Page | 42 . if iScore = 3 Then Exit end.Here's a portion of the CheckWin function.. var iScore : Integer.

btnNewGameClick(Sender: Page | 43 . Note: a player can click on the btnNewGame button after the game is finished (bGameOver = True) or during a game (bGameOver = False). function CheckWin(iPos : TXOPosArray) : integer.. Because of that it would be nice to ask the user to confirm his decision. Double click the btnNewGame button to create and add the code for the New Game option: procedure TfrMain. Just remember that good programming practice implicate getting the user's confirmation. New Game We already have the InitPlayGround procedure. All we have to do is call the InitPlayGround. the creation of the event handlers for 'New Game' and 'Reset Score'. function GamePlay(xo_Move : Integer) : integer. Your First Delphi Game: Tic Tac Toe Page 4: New Game? There are two more handlers we have to code: create a procedure for a new game. and a procedure that will reset the score. We now move to the last stage of our Tic Tac Toe development. as you did with the InitPlayGround procedure.. therefore creating a new game would be a peace of cake. In this particular case there would be negligible damage or there would be no damage at all.Note that you will have to add these procedure's headers in the private section of the form declaration. Now the private section is looking like: private procedure InitPlayGround.

Note: if you are using a Non English Delphi version and want to have dialog buttons and messages on your local language. end. mbOKCancel.Caption and lblOScore. Oponents read the score form the lblXScore and lblOScore labels. begin Page | 44 . Reseting the Scoreboard Recall that the iXScore and iOScore variables hold the number of wins for each player. mtConfirmation.Caption. get the user's confirmation first. The task is simple: set iXScore and iOScore values to zero. InitPlayGround. procedure TfrMain. Off course.0) = mrCancel then Exit. and update lblXScore. begin if bGameOver = False then begin if MessageDlg( 'End the current game?'. end. explore the article: "The fastest path to Delphi localization".TObject).btnResetScoreClick(Sender: TObject).

lblOScore.Caption := IntToStr(iXScore). lblXScore. mbOKCancel. take a look at that CheckWin function again. Please. What is this number for? See the picture: Page | 45 .. end.. iXScore := 0.0) = mrCancel then Exit.if MessageDlg( 'Reset the scores?'. iOScore := 0. mtConfirmation. Some exercises for you.Caption := IntToStr(iOScore). Note that in case of a "we have a winner" it returns an integer number from 0 to 8.

htm A Beginner’s Guide to Delphi Programming: Chapter 10.PAS unit Main.com/library/library/weekly/aa021803a. interface Page | 46 .If we have a winner and the winner has occupied the middle row. For example. Designing and developing a real game using Delphi: Tic Tac Toe. the CheckWin will retun 2.. it's up to you.. .about. Or. Download only EXE. } Main. you could change the background color for the three labels making the wining combination. Download the ZIPed source. draw an ellipse arround the cells. Your excersise (for this chapter) is to create a new function to mark (in any way you want) a victory on a playfied.) Anyway be sure to see the full Tic Tac Toe game code. { Article: Your First Delphi Game: Tic Tac Toe http://delphi.

rgPlayFirst: TRadioGroup. 1. procedure FormCreate(Sender: TObject).uses Windows. lblCell2: TLabel. var frMain: TfrMain. public { Public declarations } end. lblCell6: TLabel. btnNewGame: TButton. bGameOver : Boolean. gbScoreBoard: TGroupBox. Variants. Graphics. iXPos : TXOPosArray.3. procedure btnResetScoreClick(Sender: TObject).3] of Integer. StdCtrls. lblColon: TLabel. lblMinus: TLabel. procedure btnNewGameClick(Sender: TObject). lblCell5: TLabel. sPlaySign : String. iOPos : TXOPosArray. btnResetScore: TButton.. StrUtils. ExtCtrls. lblCell1: TLabel. lblCell3: TLabel. Controls. private procedure InitPlayGround. function GamePlay(xo_Move : Integer) : integer. function CheckWin(iPos : TXOPosArray) : integer. Dialogs. lblCell7: TLabel. Label1: TLabel. procedure lblCell0Click(Sender: TObject). lblCell8: TLabel. lblCell4: TLabel. lblX: TLabel. Page | 47 . type TfrMain = class(TForm) lblCell0: TLabel.. type TXOPosArray = array [1. Forms. Messages. SysUtils. lblXScore: TLabel. Classes. lblOScore: TLabel.

//in rows? iScore := 0.iMove : Integer. var i. if rgPlayFirst.. iXScore : Integer. bGameOver := False.FormCreate(Sender: TObject). i : Integer. begin Result := -1. j. InitPlayGround. for i := 1 to 3 do begin iScore := 0.dfm} procedure TfrMain. end. j : Integer. iMove := 0. function TfrMain. j] := 0. iOScore := 0. Page | 48 . end.1) * 3 + j . end.ItemIndex = 0 then sPlaySign := 'X'. 8 TLabel(FindComponent('lblCell' + IntToStr(k))). if rgPlayFirst. procedure TfrMain. k: integer.1.InitPlayGround. iOScore : Integer. implementation {$R *.Caption := ''. end. begin for i := 1 to 3 do begin for j := 1 To 3 do begin k:= (i . iOPos[i][j] := 0.ItemIndex = 1 then sPlaySign := 'O'. begin iXScore := 0. iXPos[i. var iScore : Integer.CheckWin(iPos : TXOPosArray) : Integer. // 0 .

if iScore = 3 Then Exit end. iPos[i. iWin : integer. if iScore = 3 then Exit. iPos[i.i]).//for i //top-left bottom-right diagonal? iScore := 0. if iScore = 3 then Exit. Page | 49 .//for i Result := -1.. end else begin iXPos[x. function TfrMain.j]). end. iWin := CheckWin(iOPos). for i := 1 to 3 do Inc(iScore. var x. //top-right bottom-left diagonal? iScore := 0.Inc(Result). for i := 1 to 3 do Inc(iScore. Inc(Result). if sPlaySign = 'O' then begin iOPos[x. Inc(Result). Inc(iMove). for j := 1 To 3 do Inc(iScore. iPos[i. x := (xo_Move Div 3) + 1. y := (xo_Move Mod 3) + 1. end. if iScore = 3 then Exit. iPos[j. y : 1. end.3. begin Result := -1. Inc(Result).i]). //columns? for i := 1 to 3 do begin iScore := 0.4-i]).y] := 1.y] := 1.GamePlay(xo_Move : Integer):integer. iWin := CheckWin(iXPos). for j := 1 to 3 do Inc(iScore.

var iWin : integer. end. begin if bGameOver = True Then Exit.8.TLabel(FindComponent('lblCell' + IntToStr(xo_Move))). lblXScore. if TLabel(Sender). ShowMessage(sPlaySign + ' . iWin := GamePlay(CellIndex). end. end. CellIndex : 0. bGameOver := True end. CellIndex := StrToInt(RightStr(TLabel(Sender). //mark victory if sPlaySign = 'X' then begin iXScore := iXScore + 1.Caption := sPlaySign. if sPlaySign = 'O' Then sPlaySign := 'X' else sPlaySign := 'O'.1)). lblOScore. Page | 50 .Caption := IntToStr(iOScore). end.. Result := iWin. end.Name. if iWin >= 0 then begin bGameOver := True. if (iMove = 9) AND (bGameOver = False) Then begin ShowMessage('It''s a Draw!'). procedure TfrMain. end else begin iOScore := iOScore + 1.Wins!'). Exit.Caption := IntToStr(iXScore).Caption <> '' then begin ShowMessage('Cell ocupied!').lblCell0Click(Sender: TObject).

procedure TfrMain.btnNewGameClick(Sender: TObject); begin if bGameOver = False then begin if MessageDlg('End the current game?', mtConfirmation, mbOKCancel,0) = mrCancel then Exit; end; InitPlayGround; end; procedure TfrMain.btnResetScoreClick(Sender: TObject); begin if MessageDlg( 'Reset the scores?', mtConfirmation, mbOKCancel,0) = mrCancel then Exit; iXScore := 0; iOScore := 0; lblXScore.Caption := IntToStr(iXScore); lblOScore.Caption := IntToStr(iOScore); end; end.

frMain.DFM

Select frMain, Select View As Text, Paste the text into Editor, Select View As Form.

object frMain: TfrMain Left = 292 Top = 237 Width = 400 Height = 299 Caption = 'About Delphi Programming: Tic Tac Toe' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText
Page | 51

Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object lblCell0: TLabel Left = 8 Top = 8 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell0' Color = clCream Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -21 Font.Name = 'Tahoma' Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter OnClick = lblCell0Click end object lblCell1: TLabel Left = 96 Top = 8 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell1' Color = clCream Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -21 Font.Name = 'Tahoma' Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter OnClick = lblCell0Click end object lblCell2: TLabel Left = 184 Top = 8 Width = 81 Height = 81
Page | 52

Alignment = taCenter AutoSize = False Caption = 'lblCell2' Color = clCream Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -21 Font.Name = 'Tahoma' Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter OnClick = lblCell0Click end object lblCell3: TLabel Left = 8 Top = 96 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell3' Color = clCream Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -21 Font.Name = 'Tahoma' Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter OnClick = lblCell0Click end object lblCell4: TLabel Left = 96 Top = 96 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell4' Color = clCream Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -21 Font.Name = 'Tahoma' Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter
Page | 53

Name = 'Tahoma' Font.Charset = DEFAULT_CHARSET Page | 54 .Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter OnClick = lblCell0Click end object lblCell7: TLabel Left = 96 Top = 184 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell7' Color = clCream Font.Color = clWindowText Font.Height = -21 Font.OnClick = lblCell0Click end object lblCell5: TLabel Left = 184 Top = 96 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell5' Color = clCream Font.Color = clWindowText Font.Charset = DEFAULT_CHARSET Font.Height = -21 Font.Charset = DEFAULT_CHARSET Font.Name = 'Tahoma' Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter OnClick = lblCell0Click end object lblCell6: TLabel Left = 8 Top = 184 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell6' Color = clCream Font.

Height = -21 Font.Height = -21 Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter OnClick = lblCell0Click end object lblCell8: TLabel Left = 184 Top = 184 Width = 81 Height = 81 Alignment = taCenter AutoSize = False Caption = 'lblCell8' Color = clCream Font.Charset = DEFAULT_CHARSET Font.Style = [fsBold] ParentColor = False Page | 55 .Name = 'Tahoma' Font.Color = clWindowText Font.Name = 'Tahoma' Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter OnClick = lblCell0Click end object gbScoreBoard: TGroupBox Left = 272 Top = 104 Width = 113 Height = 97 Caption = 'Score Board' TabOrder = 0 object lblX: TLabel Left = 8 Top = 16 Width = 33 Height = 41 Alignment = taCenter AutoSize = False Caption = 'X' Color = clBtnFace Font.Name = 'Tahoma' Font.Color = clWindowText Font.Color = clWindowText Font.Height = -21 Font.Charset = DEFAULT_CHARSET Font.Font.

Name = 'Tahoma' Font.Name = 'Tahoma' Font.Color = clWindowText Page | 56 .Charset = DEFAULT_CHARSET Font.Charset = DEFAULT_CHARSET Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter end object lblXScore: TLabel Left = 8 Top = 48 Width = 33 Height = 41 Alignment = taCenter AutoSize = False Caption = '0' Color = clBtnFace Font.Color = clWindowText Font.Color = clWindowText Font.Height = -21 Font.Charset = DEFAULT_CHARSET Font.Height = -21 Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter end object Label1: TLabel Left = 72 Top = 16 Width = 33 Height = 41 Alignment = taCenter AutoSize = False Caption = 'O' Color = clBtnFace Font.ParentFont = False Layout = tlCenter end object lblMinus: TLabel Left = 48 Top = 16 Width = 25 Height = 41 Alignment = taCenter AutoSize = False Caption = '-' Color = clBtnFace Font.

Color = clWindowText Font.Name = 'Tahoma' Font.Height = -21 Font.Charset = DEFAULT_CHARSET Font.Height = -21 Font.Font.Height = -21 Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter end object lblOScore: TLabel Left = 72 Top = 48 Width = 33 Height = 41 Alignment = taCenter AutoSize = False Caption = '0' Color = clBtnFace Font.Color = clWindowText Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter end object lblColon: TLabel Left = 48 Top = 48 Width = 25 Height = 41 Alignment = taCenter AutoSize = False Caption = ':' Color = clBtnFace Font.Name = 'Tahoma' Font.Style = [fsBold] ParentColor = False ParentFont = False Layout = tlCenter end end object rgPlayFirst: TRadioGroup Left = 272 Top = 8 Width = 113 Height = 89 Caption = 'First to play' Page | 57 .Name = 'Tahoma' Font.Charset = DEFAULT_CHARSET Font.

htm forum: http://forums.Player 1' 'O .com free newsletter: http://delphi.about.com Guide to Delphi Programming http://delphi.ItemIndex = 0 Items.Strings = ( 'X .Player 2') TabOrder = 1 end object btnNewGame: TButton Left = 272 Top = 240 Width = 113 Height = 25 Caption = 'New Game' TabOrder = 2 OnClick = btnNewGameClick end object btnResetScore: TButton Left = 272 Top = 208 Width = 113 Height = 25 Caption = 'Reset Score' TabOrder = 3 OnClick = btnResetScoreClick end end { ******************************************** Zarko Gajic About.about.com/library/blnewsletter.about.com email: delphi@aboutguide.com/ab-delphi/start/ ******************************************** } Chapter 11 Your First MDI Delphi Project Learn how to create a powerful "multiple document interface" application using Page | 58 .

usually called child forms. you might be interested in.one window. • Create New or Show Already Created Child Form? Assume. for the minute. Another task. I'll provide two more code samples you could find useful in an MDI application. that you have an MDI application with more than one type of child forms. you can proceed to "Creating a multiple document interface graphic file viewer". This article extends the topics described in the first part . To start working with MDI interfaces using Delphi. menus and some most important MDI parent form properties. MDI parent form would be the host to all your games developed as single form (window) MDI child forms. contains many other windows. a Memo component. Then. Inside the article you'll first find the definition of an MDI application. What I mean. Extending your MDI development knowledge Ok. Welcome to the eleventh chapter of the FREE online programming course: A Beginner’s Guide to Delphi Programming. in an MDI application. When you a ready.. more than one document or child window can be opened within a single parent window. In our scenario.Delphi. think of a situation when you have more than a dozen of various types of MDI child forms. It also provides a discussion on MDI parent/child relationship. is that you can have your Delphi MDI parent form host one child form designed to be able to display graphic files (TGraphicChildForm) and another form (TMemoChildForm) designed to display some text inside. for example. By now (I suppose you have read the above two articles!) you should be familiar with the key topics involved in developing MDI applications using Delphi. After you have createdyour first Delphi game.letting you expand your MDI application with some real code to open and display most commonly used graphic files (pictures). is how to store an MDI child in a DLL. why not create one "big" Delphi application to host all your games! Multiple Document Interface Applications In simple words. usually called the MDI parent or MDI container. Now. first read the "MDI Development in Delphi" article. It's time for your second Delphi project! This time we'll explore building MDI applications using Delphi. is the ability to decide whether a new instance of the specified child form is to be created or the previous instance should be Page | 59 . What you might want to have in your application. Now. you could start developing your own set of Delphi games. Learn how to create a "multiple document interface" application using Delphi.. The article then describes constructing multiple document interface application with Delphi. This is a common situation in applications such as spreadsheets or word processors .

Yes to create a new form instance. f:TForm. begin bCreated:=False. const sMDIChildFormCreated = 'Form "%s" already created.MDIChildren[i] as frm . var i:integer. The following code snippet solves the above "problem": procedure TMainForm.brought to front . end. Break. for i:= 0 to MainForm.'. Page | 60 .CreateMDIChild(frm : TFormClass).if one exists.MDIChildCount-1 do begin if MainForm. bCreated:=True.MDIChildren[i] is frm then begin f:=MainForm. Select OK to switch to it. bCreated:boolean.

mrCancel: //do notingg end.0) of mrOK: f.Show. end else begin case MessageDlg(Format(sMDIChildFormCreated.Create(Application). mbCancel].Create(Application). To call the above procedure you can use the following code: CreateMDIChild(TGraphicChildForm). //case end. mtConfirmation. [f. end. //or Page | 61 . mbYes. if not bCreated then begin frm. [mbOk.caption]). mrYes: frm.end.

you send to the CreateMDIChild procedure the name of the child form class as the parameter. Again.to "mark" that the form cannot be closed. procedure TMDIChild. but you should be able to understand the way it works. Now. the form only gets minimized. more or less a not_for_beginner type of code. on the other hand. one gets created.Sw_Hide). if the one is not found.SizeType=Size_Minimized then ShowWindow(Handle. If. able to set the Action parameter of the OnClose event method to caFree to really close it. begin Action:=caNone. end. However. You are however. the default behavior for MDI child form OnClose event is to become minimized.CreateMDIChild(TMemoChildForm). if you want to hide the form when it gets minimized you can use the next trick: procedure TMDIChild. the code looks for an already created MDI child form of the provided class. var Action: TCloseAction).WMSize(var M:TWMSIZE).FormClose (Sender: TObject. the instance (at least one) of the child form is already created. First. Let's see what the above code does. as stated. in the CreateMDIChild procedure. when you try to close an MDI child form. or even set to caNone . the message dialog asks the user whether to create a new instance or to bring to front that previously created form. Page | 62 . begin if M.. Then. • Hide MDI child form when minimized As you know by now..

As in all the chapters of this course. I've showed you how to design and develop a simple game using your Delphi skills ."Your First Delphi Game: Tic Tac Toe". This is what you could do: build an MDI application and make your Delphi TicTacToe game from the previous chapter to be the child form of the created MDI project.) Some exercises for you. Note 2: Even though this procedure relies on Windows Messages and handling them.develop your own version of the TicTacToe game and win one copy of the great Mastering Delphi 7 book. Write your own version of the TicTacToe game using Delphi Page | 63 . Delphi Programming Tic Tac Toe Contest . Note 1: You'll need to add the procedure header to the private part of the form type declaration: private procedure WMSize(var M : TWMSIZE). human version of the TicTacToe Delphi game. A chance to get awarded for your knowledge! It's time to show the World what you can do with Delphi! Two chapters "ago".. we are happy to organize an online Delphi Programming contest .. I'll provide an idea for you to try to use the gathered knowledge in a real situation. Message WM_Size. Chapter 12 Win a copy of Mastering Delphi 7 Page 1: The Delphi Programming TicTacToe Contest Welcome to the twelfth chapter of the FREE online programming course: A Beginner's Guide to Delphi Programming. don't be afraid to use it. Here's how you enter the contest: 1. 2.and give away 10 copies of the great Mastering Delphi 7 book. The truth is that you are *beginner* developer.end. Now. Your task is simple: build a computer vs. but you are trying to become an expert . Read the Official Contest Rules.

I simply write "MessageDlg" and hit Ctrl + Space + Shift: the list of all the parameters gets shown in a tool tip. Chapter 13 Code Completion in Delphi It's time to learn how to let Delphi help you code faster: start using code templates. . The answer is: Delphi Code Insight! Delphi.but NO third party components are allowed! You can even create this game as an MDI Delphi application. code insight. is that when you start a code line by typing the name of an object (Edit1. worth over 600 $ What to do to win? Use your Delphi knowledge to write your own computer vs. How to code faster and more efficiently So. properties and events to insert in your code depending on what you are doing. Delphi will display a list box with all the properties of the edit box you can pick. What this means.a set of tools available while you are working in the Code editor.you can then select the item and press Enter to add it to your code. In general. provides a very useful functionality called code insight . for example) followed by a period (dot). Submit your Delphi source code Sybex has been kind enough to provide 10 copies of the "Mastering Delphi 7" . shortcut keys.. it lists valid elements that you can select from and add to your code . neither do I tend to remember each functions parameter list. The Code Insight comprises a number of Delphi IDE Code editor features: Code Completion This handy feature automatically suggests methods. but whenever you need to add a try/finally/end block you write the entire "try finally end" command? Do you know that you can do the same by typing "tryf" and than hit Ctrl + J? And how about writing the MessageDlg function? Do you know all the parameters (and their order) this method expects? I do not know. You are free to use any Delphi version you have .10 Delphi developers will receive one copy of this great book! 10 copies. you've managed to develop several (great) applications using Delphi. Of course. This works for your own classes as well as standard methods etc.3. use your own imagination to add as many nitty features to the game as you can think of. from version 3. code completion.. human version of the Tic Tac Toe Delphi game. Page | 64 .

the code completion does not work! Now what? The message 'Unable to invoke Code Completion' usually indicates some type of syntax error in your code. for and tyr/finally/end statements) . You can press Ctrl.Caption:=" and hit Ctrl + Space. while. this feature can save you lots of keystrokes.Note: you can always invoke Code completion using Ctrl + Space. you can see "inside" Delphi). Almost always the problem does exist but you might try recompiling the entire project to see if syntax errors do exist. "forb" is a for loop with begin end. in the Code editor. a hint window tells where it is declared. Also.each statement has a shortcut. you can hold down the Ctrl key and click on any identifier in the list to browse to its declaration (if you have the sources of Borland Delphi units. point to the identifier in the code and click to move to its declaration. a list of arguments that are valid for the assignment is displayed. if you hover the mouse pointer over the identifier. eg. Code Templates As suggested above. When the code completion list is displayed. Another example includes the following situation: If you have defined several string variables and several integer variables in your unit. The list will contain (among others) string variables which you have defined. Page | 65 . You simply start a statement by typing several characters and press Ctrl+J and pick from a list of predefined code templates. "Unable to invoke Code Completion due to errors in source code"? Uops. but not the integer ones. when you start a command like "Form1. Templates include commonly used programming statements (such as if. It can also indicate that you have not defined the method you are working in.

you stop the compiler (enter debug). typing f. Tooltip symbol insight. a description of the parameters will be displayed. Symbol insight feature displays declaration information for any identifier by passing the mouse over it in the Code editor. and you can view the value of a variable by pointing to it with your cursor. Class Completion This is a "subset" of the code completion feature.Another great example includes pressing Ctrl+J on a blank line. designed to automate the definition of (new) classes by generating skeleton code for the class Page | 66 . To test expression evaluation while the program is running "under" IDE. as each parameter is input the next parameter to be input is highlighted in bold. Tooltip expression evaluation Great debugging tool. Code Parameters This tool enables you to see the arguments of a method call as you enter them into your code. After typing a method and a '('. Use Ctrl+Shift+Space to activate or reactivate if the tooltip disappears.the function skeleton code will be inserted automatically at the current cursor position. and double-clicking the selected function declaration .

... private fProp: integer.. When complete hit Ctrl + Shift + C. procedure SetProp(const Value: integer) .SetProp(const Value: integer). Code Insight Settings Options for turning Code Insight tools on and off are located on the Code Page | 67 .. end. public property MyProp : integer read fProp write SetProp.members.. procedure TForm1. then adds skeleton code in the implementation section. CTRL + SHIFT + C .. Delphi automatically adds private read and write specifiers to the declarations. This is what gets added by Delphi: ... //implementation . begin fProp := Value... This is how it works: You write a new property declaration inside a public section of the interface section of your class definition (Form1).

.a Primer Page 1: The place where forms are created... Hmm. simply start using Code insight features.Insight page of the Tools | Editor Options dialog. Note that all the Code Insight tools have lot more usage ways. We can set them up at design time using the property editors and we can write code to re-set them dynamically at runtime. However. Chapter 14 Making Forms Work . Page | 68 . we use forms to present and retrieve information from users. even with all the creature comforts built into Delphi. you will not believe how much time you can save in coding. In just about every Delphi application. Delphi arms us with a rich array of visual tools for creating forms and determining their properties and behaviour. and of course you can drastically reduce the number of bugs in your code. Some exercises for you.. The list can be found on Delphi Help under "Code Insight" when you click Help in the above dialog. Those of us who have used other visual programming languages such as Microsoft Visual Basic appreciate Delphi's many features for working with forms.

The line we are interested in is painted red: program Project1.res} begin Application. end. Over the next several months I will show you some of the simple and more complex tricks for making forms work more efficiently. Application. Application.as opposite to MDI (multiple document interface). The method CreateForm prepares the form to be displayed as the program's main form.there are many things we might want to do which cannot be solved by simply dropping a component onto a form and setting its properties. The form is not displayed until the next line Page | 69 . you start working in SDI application mode. By defualt. uses Forms. Starting a new Delphi project generates and displays the first form in the project file.Run. Unit1 in 'Unit1. every time you create a new (Windows) application in Delphi. from the IDE menu go to Project | View Source. To view the project file code. Form1). An SDI application normally contains a single document view . Starting Simply To get things rolling. let's start off at the simple end with SDI (Single Document Interface) forms.pas' {Form1}.Initialize. {$R *.CreateForm(TForm1.

Application.Unit3). This is not a problem with an application with a single form.CreateForm(TfrmEditCustomer. Application.Unit2) and edit customers (frmEditCustomer .Initialize.CreateForm(TfrmMain. change the name to 'frmEditCustomer' (leave the name of the unit to be 'Unit3'). To add two new forms in the project.CreateForm(TfrmAddNewCustomer. but if the project has many forms and they are all created at program startup you may run into low resource problems down the road. Application. Rename this form (using the Object Inspector) to 'frmAddNewCustomer'. frmAddNewCustomer). Your development computer probably has plenty of memory installed but the situation may be quite different on users' machines. Taking Control Let's look at the basics for controlling forms in a new project. Page | 70 . Executing CreateForm utilizes memory and system resources.Run. frmEditCustomer). where your application has to run with much more limited resources and in competition with other applications.executes: Application. This will create (and add) a new form named Form2 (+ Unit2) to the project. Application. Repeat the steps for the third form. frmMain). simply point to File | New | Form. The solution is simple: take control of form creation and destruction.Run. When you define the two subsidiary forms Delphi places the following code into the project file: begin Application. Imagine you have an application that has a main form (frmMain) with two subsidiary forms to add a new customer (frmAddNewCustomer .

.end Each Application. but it could be any name) is designated as the main form for the project and will be visible once Application.Show. line creates the form object specified by the variable in the second argument as an instance of the class specified in the first. select Unit2 (frmAddNewCustomer).e.CreateForm. Our program should create the Add or Edit form only when needed! For example. all three forms will be created in order.Run has executed. The first form in the list (named frmMain here. 'Unit2' is added to the implementation uses clause (just below the word implementation) of the Unit1 (main form).. If you leave the code as it is. let's see how to call some of those forms dynamically at run time. Note that after this action. to display the Add Customer form from the main form: From the Delphi IDE main menu. To show either of the other forms you would to apply code to some user-generated event to "show" it (i. //or frmAddNewCustomer.. File -> Use Unit. bring it to the top): frmAddNewCustomer. Ok.a Primer Page 2: Showing Modal forms .ShowModal. it makes no sense to keep them there hidden and using resources unnecessarily. Since we now know how to add more forms to a Delphi (SDI) project.. Page | 71 .where the application can't continue to run until the (modal) form is closed. so what are the diferences between the Show and ShowModal methods? Making Forms Work . Modal Delphi Forms Since it is very unlikely that this application would need to have all three forms showing at once.

frmAddNewCustomer).Remove the following line from the project file (delete it manually or use Project Options in the IDE): Application. The owner could also be the application itself. TCustomForm. Caution is needed with a Nil owner.cmdAddNewCustomerClick(Sender: TObject).Release. end. var f:TfrmAddNewCustomer. however. your program will crash later with an access violation.ShowModal. using the Free method. Using this variable. Page | 72 . This drops us down to the code editor were you would amplify the supplied code framework to show the Add New Customer form when the user clicks the button: procedure TfrmMain. begin f := TfrmAddNewCustomer. double click the left mouse button to generate an OnClick event. You must take care to destroy the form object yourself. the "Add New Customer" form can be initialized using the Create method of our form's ancestor. finally f.Create(Self).CreateForm(TfrmAddNewCustomer. If you try to use Release for a form (or any object) with a Nil owner. The single argument required by Create is the Owner of the form. end. The above example uses the Self keyword to make the main form the owner. Place a TButton component (Name: 'cmdAddNewCustomer') on the form. or you can specify Nil. whose type is TfrmAddNewCustomer. try f. The first thing needed is a variable (f. in our example) to create an instance of the "Add New Customer" form.

Then in the FormClose event for the Add New Customer form add the following (Action caFree frees up all resources for the form and destroys it): Page | 73 .Show . Ok. so placing the Show method into a try…finally exception block guarantees that the Release method is called and resources are released once the main form has terminated. the method ShowModal displays it in a modal state by using. Free releases the resources immediately the modal form closes. because Release is called right after showing the form. We can't use exactly similar code because the form would show briefly. makeing a safer call if the modal form is likely to be invoked more than once during the program. now we know how to add more forms to a Delphi (SDI) project. Making Forms Work . and even how to call a modal form.Once the form has been created..a Primer Page 3: Showing Non-modal forms . then disappear.Create(Self). During the time the form is shown and terminated there may be problems. A Non-Modal Form If the secondary form needs to be non-modal. begin f := TfrmAddNewCustomer..cmdAddNewCustomerClick(Sender: TObject).making them visible and bringing to the front of other forms on the screen. In contrast. let's see how to call some of those forms in a non-modal fasion. var f:TfrmAddNewCustomer . To correct this problem use the code shown below: procedure TfrmMain. f. use Show instead of ShowModal. end.

there is a slight problem with the code! Can you see the problem? Since the secondary form is non-modal the user can go back to the main form and press the Add button again. If so. begin iFound := -1. for example: procedure TfrmMain. create the form and then show it.FormCount -1 do if Screen.procedure TfrmAddNewCustomer. Whoops. The program tries to create another Add New Customer form with unfortunate results if you have not planned for it! To prevent this from happening first check to see if the form object already exists. if not. iFound. i:Integer .Forms[i] is TfrmAddNewCustomer then iFound := i. var f:TfrmAddNewCustomer .cmdAddNewCustomerClick(Sender: TObject). Page | 74 . begin Action := caFree . simply show it. end. for i := 0 to Screen. var Action: TCloseAction).FormClose(Sender: TObject). There are various ways to test for an object's existence.

Page | 75 . end else begin ShowMessage('Add New Customer form not found. with very little hand-coding. Caution: When defining forms for dynamic invocation you should be aware of the need to avoid any named reference to the properties of the object whose variable is declared in the interface section.Forms[iFound]. creating. but a delay is unlikely to be perceptible unless the called forms are very complex and/or your user has an unreasonably slow machine. will now show it') .') . end. That variable will never be assigned because the calling form uses its own local variable to invoke it. f. There is a slight performance trade-off with dynamically created forms. end. begin frmAddNewCustomer. These methods give your program much better control of resources than auto-created forms. f := TfrmAddNewCustomer..Top := Top + 12 .FormCreate(Sender: TObject).. Screen.Show .if iFound >= 0 then begin ShowMessage('Add Customer form already created.Create(Self) .Show . For example: procedure TfrmAddNewCustomer.

FormCreate(Sender: TObject). though. begin Self. If for some reason you need an explicit reference to the form object. The variable in the interface section of can be safely removed if the form is intended only for dynamic invocation.end. end. procedure TfrmMain. here is a method for showing a modeless form. var Page | 76 .cmdAddNewCustomerClick(Sender: TObject). end.Top := Self. It is scarcely worth doing. the reference to the variable frmAddNewCustomer would cause an access violation. For completeness. use the identifier Self in front of the property or method.Top + 12 . Using our example. procedure TfrmAddNewCustomer.FormCreate(Sender: TObject). since it will be optimized out when the project is compiled. begin Top := Top + 12 . The code below demonstrates how you need to work with properties of the secondary form procedure TfrmAddNewCustomer.

. read on and learn about some more from_the_battle_field situations. end. end. var f:TForm.Release else ShowMessage('Failed to find it') .. Once you are finished using the form it can be destroyed by using the following code: procedure TfrmMain.f:TfrmAddNewCustomer . Ready to code .. All set. begin with TfrmAddNewCustomer..cmdCloseFormClick(Sender: TObject). end. if f <> nil then f. Page | 77 .Create(Self) do begin Show. begin f := TForm(FindComponent('frmAddNewCustomer')) .

if FindComponent returns Nil. The variable iForm would be a private variable of frmMain which you would initialize during the OnCreate event of frmMain.Button1Click(Sender: TObject). Select a meaningful name and append an integer to the end of the name i.Making Forms Work . we are ready for some real world situations (and solutions). Provide another command button 'CmdCloseForm' to close the form. then closed. the second attempt fails! To get around this problem a unique name needs to be assigned to the child form. we typecast FindComponent's result to cast the object as TForm and assign a TForm variable to grab the result. Now click "cmdAddNewCustomer" twice followed by click "cmdCloseForm" twice. After we have added two more forms to a Delphi (SDI) project. Theoretically.a Primer Page 4: Form created? How to position a secondary form precisely! Almost done. andmodeless. Tidy Habits Use FindComponent to determine if the form exists or not. FindComponent returns an object (if it exists) of type TControl. the form does not exist .or does it? Try placing the two procedures above into a main form. 'AddCustomer_' + IntToStr(iForm) . Compile and run the project.e. and have displayed some of them as modal. begin Inc(iForm) . Provide a command button named 'CmdAddNewCustomer' to create the form. Here is the altered code for creating the subsidiary form: procedure TfrmMain. Click the 'CmdAddNewCustomer' button to create the form and then close it using the 'CmdCloseForm' button. Page | 78 . Since the desired type is TForm. On the first attempt the child form is found. var f:TfrmAddNewCustomer .

var f:TForm.cmdCloseFormClick(Sender: TObject).with TfrmAddNewCustomer. end.Create(Self) do begin Name := 'AddCustomer_' + IntToStr(iForm) . which can be used later to remove any instances of the form: procedure TfrmMain. if f <> nil then f. {The caption will be the name of the form given above} Show . end .Release else MessageDlg('Failed to locate AddCustomer_' + Page | 79 . This gives the next invocation of the form a name of AddCustomer_1. On the first call to this event iForm would be zero. begin for i := 1 to iForm do begin f := TForm(FindComponent('AddCustomer_' + IntToStr(i))) . then directly before creating the form we use Inc to increment iForm to one. i:Integer.

f:TfrmAddNewCustomer . var A. press F11 for the Object Inspector. R.Selected = nil then Exit.TreeView1DblClick(Sender: TObject). In this example the Add form is displayed when the user double clicks on the TreeView. First place a TreeView on a main form in a project. A := TreeView1. Page | 80 . select the property "Items" and double click the left mouse button. end. TheSelectedNode : TTreeNode. begin if TreeView1. Suppose you need to position the Add New Customer form directly on a node in a TreeView displaying accounts. GetCursorPos(P).ScreenToClient(P). select the TreeView. end. Finish up by pressing the "OK" button.[mbOk]. Right Time One more benefit from creating forms dynamically is the ability to position a secondary form precisely.0) . select the Events page of the Object Inspector while the TreeView is still selected. Right Place. Next. relative to a control on the parent form.IntToStr(i). Double click on the event OnDblClick and enter the following code (which I shall explain in another article): procedure TfrmMain. P : TPoint.mtError. Add several new items and sub-items (optional).

Left := R.Top := R. f. Its caption identifies the item selected in the TreeView. end.x. try f.y)). A. Run the project.TheSelectedNode := TreeView1.Create('Please click on an Item in the TreeView!'). finally f. What happens when you call (create) a non modal Form3 from Form2. Again.y). Next time.Create(Self) . more on working with forms.GetNodeAt(A. f.Text + '"' .. dynamic creation of forms can be of great service to you! I hope this chapter has given some insight into the techniques Delphi puts at your disposal for taking control of form creation and behaviour when developing SDI forms..y . P := ClientToScreen(Point(A. If you had centered the form on the screen.ShowModal .Caption := 'Add customer to account: "' + TheSelectedNode.x . have fun! Some exercises for you. The secondary form should appear with its top left corner positioned on the node which was double clicked. GetCursorPos(R) .A. f.x. Until then. the specific information concerning the item selected in the TreeView would not be accessible. and after that call (create) Form2 from Form3? Page | 81 . end. if TheSelectedNode = nil then raise Exception. f := TfrmAddNewCustomer.Release . Select a node in the TreeView and double click the left mouse button.

You can write some interesting code to accomplish this. lets the user do something with it. begin F := TForm2. ... Most commonly. you might want to know whether the user pressed the Save or Cancel button to close the modal form.ShowModal. Once these processes complete. F. Delphi supplies modal forms with the ModalResult property. but it does not have to be difficult. which we can read to tell how the user exited the form. then releases it.ShowModal Page | 82 . To check how the form was terminated we need to take advantage of the fact that the ShowModal method is a function that returns one of several ModalResult values. The example shown above just shows the form. we will display a form modally to isolate its processes from anything that might otherwise happen on the main form.Release.Chapter 15 Communicating Between Forms Page 1: Finding out how a modal form was closed Finding out how a modal form was closed Modal forms offer specific features that we cannot have when displaying non-modally. but the calling routine ignores it: var F:TForm2. The following code returns a result.Create(nil). Change the line F. F.

This new form will have a 'Form2' name. try if f. finally f.Create(nil).ShowModal = mrOk then We need some code in the modal form to set up whatever it is we want to retrieve.TButton has one too.Button1Click(Sender: TObject). Page | 83 . There is more than one way to get the ModalResult because TForm is not the only component having a ModalResult property . Start a new project. double click the new button and enter the following code: procedure TForm1.Release. Let us look at TButton's ModalResult first. Next add a TButton (Name: 'Button1') to the main form (Form1). begin f := TForm2. end. and add one additional form (Delphi IDE Main menu: File -> New -> Form).to if F. end. var f : TForm2.ShowModal = mrOk then Caption := 'Yes' else Caption := 'No'.

once back to the main form note that it's caption says "Yes". then the value is Page | 84 . and set it to mrCancel. begin Form := GetParentForm(Self). end. var Form: TCustomForm. press F4. Press the main form's button to bring up the child form again but this time press the Cancel button (or the System menu Close item or the [x] button in the caption area). How does this work? To find out take a look at the Click event for TButton (from StdCtrls. Delphi may prompt to save the files. select the property ModalResult. Give it two TButtons. labelling one 'Save' (Name : 'btnSave'. If you don't set TButton. inherited Click. Caption: 'Save') and the other 'Cancel' (Name : 'btnCancel'. It's as simple as that.Click. Caption: 'Cancel'). (Depending on your environment settings. The main form's caption will read "No". What happens is that the Owner (in this case the secondary form) of TButton gets its ModalResult set according to the value of the TButton's ModalResult. to show the child form.) Once the main form appears.pas): procedure TButton. scroll up/down until you find the property ModalResult and set it to mrOk. if Form nil then Form. Now press F9 to run the project. When the child form appears press the Save button and the form closes. Select the Save button and press F4 to bring up the Object Inspector.ModalResult. press the Button1 you added earlier.Now select the additional form.ModalResult := ModalResult. Go back to the form and select the Cancel button.

knowing whether the user wants to accept or reject what occurred on the child form.CloseQuery: Boolean.mrNone (by defaolt). which keeps checking for the variable ModalResult to become a value greater than zero. Events to look at for ModalResult (in Forms.Close. Let's see how.CloseModal.ShowModal: Integer... but you can also set the form's ModalResult property directly in code at run-time. To understand what goes on with the Forms ModalResult it is worthwhile reviewing the code in Forms.\DelphiN\Source (where N represents the version number). The last line then invokes the Click event inherited from its ancestor class. function TCustomForm.. mrOk = idOk. the calling form can react by using the information from the child form or ignoring it. You can set ModalResult at design-time. the calling form can react by using the information from the child form or ignoring it. Let's see how. Now.pas. mrCancel = idCancel.. Even if the TButton is placed on another control the parent form is still used to set its result.. knowing whether the user wants to accept or reject what occurred on the child form. Communicating Between Forms Page 2: Getting the values from another form Now. which you should be able to find in . When this occurs. procedure TCustomForm.pas): function TCustomForm.pas const mrNone = 0. directly after the form is shown. In TForm's ShowModal function. Page | 85 . procedure TCustomForm. as described above. ModalResult Constants from Controls. a Repeat-Until loop starts. the final code closes the form.

mrAll = mrNo + 1. begin f := TfrmSimpleString. var f:TfrmSimpleString . end.Text). mrYesToAll = mrNoToAll + 1. mrNoToAll = mrAll + 1. mrNo = idNo. The following example shows how to get the value stored in a TEdit (Name : 'Edit1') Text property if the user pressed the Ok button on the child form (Name: 'frmSimpleString').ModalResultdemo2Click(Sender: TObject). Sometimes you will need to get more than one piece of information back from a form. mrIgnore = idIgnore.Release.mrAbort = idAbort. mrRetry = idRetry. mrYes = idYes. To keep the example short we are just checking for an Ok response and ignoring negative responses.Edit1. When the user presses the OK button (its Page | 86 . finally f. but let's start simple.Create(nil). end. try if f.ShowModal = mrOk then ShowMessage(f. // Code for main form procedure TfrmMain.

var f:TfrmSimpleString . begin f := TfrmSimpleString.Release.ModalResultdemo2Click(Sender: TObject). We could have streamlined the code a little more by adding code to let the user choose whether to continue with closing the form or aborting back into the called form: // Code for main form procedure TfrmMain. try f. Edit1. on the called form and then destroys the form. ShowMessage(s). end.ModalResult is set to mrOk) the following code reads the value of an edit control. S:String . end.Create(nil).GetThatString(S). In a real application you might need information from several components on the called form. finally f. // Code for the called (child) form Page | 87 .

Button2: TButton. var frmSimpleString: TfrmSimpleString. end. implementation {$R *. private { Private declarations } public { Public declarations } procedure GetThatString(var aString: string). Edit1: TEdit.type TfrmSimpleString = class(TForm) Button1: TButton.DFM} Page | 88 .

else if ShowModal = mrRetry then .. The logic used to determine if the user wants to return information remains the same.GetThatString(var aString: string). begin case ShowModal of mrOk: aString := 'OK' . only the means of storing it varies. end. To show how this might be done. i. end.. you will need much more than a simple string.ELSE statements.procedure TfrmSimpleString. the Case statement is used rather than a chain of nested IF. On the called form we add a procedure GetThatString to interrogate the user modally to find out whether the user wants to continue or abort the current operation. a TList.. Retrieving a string is simple enough but. a StringList.e.. If ShowModal = mrOk then . Methods for getting a lot of information back from a called form include using anarray.THEN. mrCancel: aString := 'Cancel' . end.. I will use a record to store user input for retrieval once the user Page | 89 . For elegance.. else if ShowModal = mrCancel then . or records. often...

Let's use the idea to present a data entry form to a user. try if f.PersonRecord1Click(Sender: TObject). supplied the name of TPerson. This should give you a starting point to working with record arrays.Create(Self). The main thing to remember about the example is that we created a record type. Communicating Between Forms Page 3: Moving records of data between two forms Back in the "Records in Delphi" article. a sample code was presented demonstrating pressing a button to populate the array of records with dummy information.PersonCount > 0 then Page | 90 . allow data to be entered about several people before returning to the main form to process it. then created a local variable called MyPeople which is an array of type TPerson which can hold three (3) rows of information. begin f := TForm5.presses OK in the called form. we will use an array of recordsso that multiple pieces of information can be returned from the called form! Before digging into an example.ShowModal = mrOk then if f. Use the next piece of code to call the secondary form for the data entry: procedure TfrmMain. To make things interesting. var f:TForm5. lets go through a short lesson of record types for those programmers that may have not worked with records: "Records in Delphi". then display the records in the memo control.

Forms.Classes. end.Release. The variable PersonCount in the data entry form is incremented each time a new person is added to the array of records.FirstName + '" "' + f.Messages. the main form creates the data entry form. finally f.PersonArray[0]. The following code is placed into a simple unit (Delphi IDE Main Menu: File -> New -> Unit) so that any form in the project can see the People record along with a constant used to limit how many elements (records) can be used in the array of records. unit kg_Globals.LastName + '"').ShowMessage('The first person is' + #13 + '"' + f.SysUtils. shows it. then checks to see if there were any people entered into the people array. When the user invokes the event. const Page | 91 .FileCtrl. end. PersonArray[0].Dialogs. //saved as kg_Globals interface uses Windows.

Page | 92 . Email : String.ARRAY_SIZE = 5. ZipCode : String. Phone : String. State : String. Street : String. end. City : String. implementation end. {Could be a larger size} type {Keep each record member to strings to make the example code easy to understand} Tkg_People = Record FirstName : String. LastName : String.

..ClearEdits.. var i:Integer. public { Public declarations } PersonArray: Array [0. . .Text := '' ..In the public portion of the called form's declarations we declare an array of records and a variable for keeping track of how many records the user has entered. begin { sets each TEdit control's text property to an empty string } for i := 0 to ComponentCount -1 do if (Components[i] is TEdit) then TEdit(Components[i]). PersonCount: Integer. In the Create event of the data entry form the following code is called to clear all edit controls so that the form starts up with a clean slate. Page | 93 . Each time the user accepts a screenful of people information the ClearEdit procedure is triggered: procedure TForm5..ARRAY_SIZE] of Tkg_People.

PersonArray[PersonCount]. procedure TForm5.Text. { Once the maximim elements are used up.City := City. Page | 94 .FirstName := First. begin { Populate a record in an element in the array of records with current textbox values } PersonArray[PersonCount]. The next code fills a row of data in the people array and increments the row counter. PersonArray[PersonCount].end.State := State.Text. Inc(PersonCount). PersonArray[PersonCount].ZipCode := Zip.Text.Email := Email. The counter is checked to ensure that the number of rows keeps within the fixed boundaries of the array of records.Text. PersonArray[PersonCount].Text.Text. PersonArray[PersonCount]. PersonArray[PersonCount]. PersonArray[PersonCount].Text.LastName := Last.cmdAddPersonClick(Sender: TObject).Phone := Phone.Street := Street.Text.

disable this button. place focus on "First" name text control } if TButton(Sender). } TButton(Sender).SetFocus . The Constant indicates how many records can be accessed in the array.Enabled then begin ClearEdits.Enabled := PersonCount < ARRAY_SIZE. First. NOTE: ARRAY_SIZE is a user defined constant created for this demo. end else Page | 95 . { If we can still add more persons clear old entries.

I caught one in D4 after writing this article. Detour time The last thing a programmer needs when searching for assistance in a help file or manuals is an incorrect example of how to do a particular task. to do with "Passing additional arguments to forms".SetFocus . in either single or multiple rows. To recap. Using this example you can return just about any type of data. private public Page | 96 . OKButton: TButton.{ Exit time . end. listed under "forms" in Delphi help. Keep in mind there are other ways to accomplish returning information from modal forms. give them a hint by placing focus on the exit button } cmdCloseForm. procedure OKButtonClick(Sender: TObject). Shown below are the key pieces: type TResultsForm = class(TForm) ResultsLabel: TLabel. you can detect how a modal form was closed and get information back in several ways.

end.SecondButtonClick(Sender: TObject). begin case whichButton of 1: ResultsLabel. begin rf := TResultsForm. 3: ResultsLabel. procedure TMainForm.Caption := 'You picked the second button.'. end. Owner: TComponent). var rf: TResultsForm. self). end.Caption := 'You picked the first button.Free.constructor CreateWithButton(whichButton: Integer. This code was posted on Borland's news group as a solution for Page | 97 .'. Don't feel bad if you can not figure out what's missing/wrong with the example.CreateWithButton(2. end.Caption := 'You picked the third button.'.ShowModal. Owner: TComponent). constructor CreateWithButton(whichButton: Integer. rf. rf. 2: ResultsLabel.

OKButton: TButton. Page | 98 . case whichButton of 1: ResultsLabel. Instead of trying to figure out the errors. constructor TResultsForm. Owner: TComponent). begin inherited Create(Owner) .Caption := 'You picked the third button.'. Owner: TComponent). 2: ResultsLabel. 3: ResultsLabel.a posted question.Caption := 'You picked the first button.Caption := 'You picked the second button. look at the correct code: type TResultsForm = class(TForm) ResultsLabel: TLabel.'. private public constructor Create(whichButton: Integer. end. end.Create(whichButton: Integer. reintroduce.'.

Interbase or MySQL. end. The source units also expand some concepts beyond the scope of this chapter and provide more technical explanations. self). It may even be stored in an XML file. in terms of data-aware components. end. This time an easy one: download the example Delphi project for this chapter and try out the code without having to type it in yourself. Access. begin f := TResultsForm. try f.Create(2. procedure TMainForm. var f: TResultsForm . Delphi Personal edition comes with no database support.Release . "data world" isn't only about Paradox. finally f. Some exercises for you. It may be stored in an ASCII text file or a structured binary file.ShowModal. Hopefully.end.. Chapter 16 No DB support in Delphi Personal edition As you probably know. The data your application needs to operate on may not always be stored in a relational database. Page | 99 .SecondButtonClick(Sender: TObject)..

If you are only working with a small amount of data that is rarely updated then a flat-file database could be your choice. Various File IO articles and tutorials Including: Understanding what files are and choosing a Delphi file type. Although it is possible to make changes within text file. Building your own database system The next series of articles shows you how to use Delphi to create a simple "database" application that interacts with data in text (ASCII) or binary files:  Handling ASCII (text) files from Object Pascal code Simply put. etc).INI) with Delphi How a simple text file can beat Registry in storing a few pieces of application specific configuration data. and untyped. such as Double. Be sure to check our "Beginner's Guide to Delphi Database Programming"! Files from Delphi perspective Simply put a file is a binary sequence of some type. reading and updating your own types of files. MS SQL Server. However. NOTE: flat-file databases are not as scaleable (and safe) as the relational model databases (MySQL. jump around when processing information or add some data to the file other than at the end. Files with no structure (untyped files) Using Delphi to manage operations on untyped files . and write data back to the file as if the data were stored in a *real* database. it is advisable to use a text file only when we know that we are working with ordinary text and no such operations are necessary. your application can read data from a file (of *any* structure). Use Delphi to manage writing. if you are looking for a database for more frequent and heavy use then a relational database is probably more suitable. Writing and reading. In Delphi. Interbase.      Your own database Working with binary files from Delphi. Text files contain readable ASCII characters (organized into lines). add new "records".direct access to disk files regardless of type and structuring. update "fields". Untyped files are used when we want to impose the least possible structure on a file. text files contain readable ASCII characters. Changing and updating. files of record or untyped)? Accessing 'Configuration Settings' files (. What is a File? How are they stored? What format is best for my project (text.As you will learn from this chapter. text. Typed files are files that contain data of a particular type. there a three classes of file: typed. Integer or previously defined custom Record type. Page | 100 . Seeking and positioning. File Management Routines A list of Delphi's RTL functions designed to ease file management.

Welcome to the seventeenth chapter of the FREE online programming course: A Beginner's Guide to Delphi Programming. for example. create a simple Delphi project. In general. Creating and using your own code units. we've opened a discussion on Delphi units. Beside the source code that "drives" event handlers for the form and the component on it. compiled units are linked to create an application. The scope (visibility) of a Delphi identifier.Some exercises for you. Along the process we'll briefly discuss using Delphi's built-in routines and how to make all the units of a Delphi application cooperate.. a Delphi program is constructed from source-code modules called units. A custom procedure could be used. Chapter 17 Working with units Page 1: What is a Delphi unit? The structure of a unit. What is a Delphi unit? In the fifth chapter of this course. Each unit is stored in its own file (. The unit contains the source code for any event handlers attached to the events of the form or the components it contains. Page | 101 . these provide the responses to the user's actions. As stated. Each form in a Delphi project has an associated unit. forms are visible building blocks of a Delphi application. Here is an overview of the topics discussed in this chapter:     What is a Delphi unit? The structure of a unit. Much of the work done by an application is performed by event-driven procedures. DVD's. Using Delphi's built-in unit files (RTL/VCL routines).Delphi code files that contain logically associated functions and procedures... let's say some kind of database (with typed files) to store all your CD's. its source code can become very hard to maintain.. you can write custom procedures or functions within a unit that's associated with a form.pas) and compiled separately. While developing a (large) Delphi application. Make a plan. In this article you will learn about creating your own code modues . as program becomes more complex.

it's better to create a separate unit to contain those routines. When you start building libraries of useful routines. You can have any number of code units in your project so it is a good idea to split up your general-purpose procedures. variables) are specified that are available for use in other units } uses { The list of the unit names whose routines our unit wants to use } implementation { This section contains all the source code that defines all the types listed/defined Page | 102 . The idea is to have one unit for date checking routines. units don't have to be associated with forms. you can easily make your procedures and functions available to other projects. Structure of a unit I've already explained a structure of a Delphi unit (form unit and/or code unit) in the fifth chapter of this course. However. the next "illustration" summarizes what's already been stated: unit MyUnit. you will probably store them in a code unit. A "code unit" contains code that is called from other units in the project. If you want to reuse the routines that you write. another one for text-handling purposes and the third for dealing with databases. //unit name interface { In this section the routines (types. By creating stand-alone units that have no associated forms.to check whether a date entered in an edit box is valid.

such as freeing any resources allocated in the initialization part. you can add the cleanup code into the finalization section} end. If your unit needs to perform any cleanup when the application terminates. //unit end Now. Here we write the code we need to be executed when the form is removed from memory. it's time to see how to create Delphi programs that comprise a (larger) number of code units.to initialize any data the unit uses} finalization { This optional section is required only if we have the initialization section. note the uses section/clause of the interface (or Page | 103 . that you know (in theory) what goes in a Delphi unit. "A unit uses B unit" ?! Stop for a minute.in the interface section } uses { The optional list of the unit names with routines our unit wants to use } initialization { This optional section contains all source code needed to be executed when the unit is referenced for the first time .

..implementation) section. let's see how Delphi maintains the uses list automatically as you add components to a form. what exactly does that mean? Who maintains this list? How do you know what unit your unit needs to use? How do you know what exact unit you need to add to the list if you want to use the "MatchesMask" Delphi function? First. not enough for a Delphi beginner to start working on large sized applications. In the Code editor. the automatically generated form unit declares a new class type for the form and includes the code that creates the new form instance. Examining a form unit and its uses clause Every time you start Delphi (or create a new project).. This collection of units is referred to as the RTL (run time library).) our unit wants to use". This information is contained in various unit files that are a standard part of Delphi. Uh. let's see how Delphi generates and maintains a form unit source. what a tricky sentence. Before we move on to creating your own code units.. Page | 104 . variables . Developers who are new to Delphi often find that they are uncertain about which unit they need to "use" and how to "use" it.. such as buttons and edit boxes. the Delphi IDE displays a new form for you to customize. Only understanding the structure of a Delphi unit is unfortunately.. Using Delphi's RTL routines. a Delphi application needs a lot of background information. Working with units Page 2: How Delphi maintains a units source. Let's begin our examination of the uses list by looking at the autogenerated code: 01: unit Unit1. such as how to interact with the operating system and how to create forms and components. In order to run. "The list of the unit names whose routines (types.

14: implementation 15: {$R *. Dialogs. 04: type 06: TForm1 = class(TForm) 07: private 08: { Private declarations } 09: public 10: { Public declarations } 11: end. 12: var 13: Form1: TForm1. 03: Graphics. Messages. Classes.dfm} Page | 105 . Forms. Controls. SysUtils.02: interface 03: uses 03: Windows. Variants.

Suppose you add a (standard) button component to this form and write an OnClick event handler that changes the Caption of the form when the user clicks the button.. A question: should you need to know the exact name of every unit when you want to use some component? Luckily. All it does is display a blank form. StdCtrls. Recall that Delphi comes with more than 200 components for you to "drop on a form" (depending on your Delphi version). you already have a complete GUI application that you can compile and run. string handling. Although you haven't added any components to the form or written any code. Page | 106 . routines in the System unit implement file I/O. 02: interface 03: uses 03: Windows. Forms. Placing components on a form. The System unit and the SysInit unit are used automatically by every application and cannot be listed explicitly in the uses clause. Variants. Dialogs. floating point operations. 03: Graphics. Controls. and so forth. after all every thirdparty component (or the one you build on your own) comes "inside" its own unit. no. Classes. Delphi places all necessary units in the (interface) uses clause (line: 03).16: end.. When you create a new form (with its associated unit). Note: two more units are also "listed" in the uses list. The result might look like this: 01: unit Unit1. SysUtils. Messages. For instance. dynamic memory allocation. It's quite natural that all those components are not defined in only 10 units.

Page | 107 . procedure Button1Click(Sender: TObject). 16: implementation 17: {$R *.04: type 06: TForm1 = class(TForm) 07: 08: Button1: TButton.Button1Click(Sender: TObject). 19: begin 20: //enter code here: 21: Caption := 'Clicked'. 09: private 10: { Private declarations } 11: public 12: { Public declarations } 13: end.dfm} 18: procedure TForm1. 14: var 15: Form1: TForm1.

is that you. the StrUtils unit provides routines for string manipulation.Button1Click(Sender: TObject). Now. do not need know the exact name of the unit your unit needs to use. If you try to compile and run the application. you'll get the following Page | 108 . in the uses list. Delphi will add the name of the associated unit to the uses list! Note: If you remove that button component. or VCL routines are (general purpose) functions and procedure that are built into Delphi. begin Caption:=ReverseString(Edit1. Here's the code: procedure TForm1. provides a through example-reference to the RTL capabilities of Delphi. Using Delphi's built-in unit files (RTL/VCL routines) Run Time Library. What happened? Since the button (TButton) control is defined in the StdCtrls unit. suppose you have an edit box (Edit1) on a form. DateUtils includes routines for date manipulation.22: end. RTL reference. in many cases. When the user clicks a button.Text). Delphi added the reference to it. A section on this site. you just dropped on the form Delphi will not remove the reference to the "StdCtrls" unit from the uses list. For every (properly installed) component you drop on a form. What this means. For example. end. 23: end. the Caption of the form should change to a reversed string of a string specified in the edit box.

" pops up. is to browse through our "Delphi RTL reference" section. Dialogs. you need to manually add the unit "StrUtils" to the uses list. and how Delphi helps you maintain a forms unit source. Now that you have seen how Delphi maintains a form unit source (and its uses list). What this means is that the compiler could not find the given identifier (ReverseString) ... and what needs to be done in order to use Delphi's built-in routines. it's time to start creating your own collection of useful functions and procedures. you will find there is a routine that is declared in a unit that is not listed in the uses list. Working with units Page 3: Creating and using your own code units Now that you know the structure of a Delphi unit. 03: uses 03: Windows. Messages. StrUtils.. you are ready to start creating your own code units. you'll need to know the exact name of the unit in which they are defined. 03: Controls. Another way is to hit F1 (call Delphi help system) every time an "undeclared identifier. when using built-in routines. If you "forgot" to add a reference to a unit. Variants.error: Undeclared identifier: 'ReverseString'. Page | 109 . StdCtrls. Graphics. Forms. Classes. Delphi's Help system should tell you which unit you need to add. To fix the above error. but you simply cannot recall the name of the unit in which the function is defined? One way to help yourself.it might be from another unit that is not listed in the uses clause. Usually. the Delphi compiler display an error message and places the cursor at he point in the source code that it cannot process.. SysUtils. But how do you know that Delphi has the ReverseString function? And what if you *know* that there is a function called "MatchesMask". In other words.

Depending on your background. in order to create a new routine (procedure or function) in a code unit. followed by a valid identifier. defined in unit named MySuperUnit. Naming (saving) a unit The unit heading specifies the unit's name.you will need to change the call to any procedure inside that unit. followed by a semicolon. To save a unit under a different name.. in the Save As dialog box enter a valid file name and click ok. Page | 110 .) and a procedure name.. Unit names must be unique within a project. To add a general purpose routine (procedure or function) to a code unit. This is the reason why you should give meaningful name to units in the early stage of unit "development". since the name of the unit will no longer be MySuperUnit. creating and using code units can be easy to understand or may be confusing at first. The Code Editor will display the newly created unit and its skeleton code: unit Unit2. interface implementation end. New . consists of a unit name (MySuperUnit) followed by a period (. Creating routines in units I'll now quickly introduce the steps you need to do. It consists of the reserved word "unit". Caution: If you change the name of the unit after.Save As. Note that the call to a procedure SomeProcedureName. go to File .Unit from the main Delphi IDE menu. unit The simplest way to create a new unit for your project is to select File New . you'll need to change the source (uses list) of all the units that use this unit. This fact is very important! If in some stage of the development of your project you decide to save MySuperUnit under a different name .

end. StrUtils. var hello : string.do the following: 1. Page | 111 . procedure SayHelloTo(YourName : string). begin hello := YourName + '. 3. interface uses Dialogs. implementation procedure ReveredHello(YourName : string). hello!'. procedure SayHelloTo(YourName : string). ShowMessage(hello). Repeat the routine header in the implementation section and add the routine code Here's an example: unit Unit2. Make sure the units source is displayed in the Code Editor 2. Type the routine header in the interface section to make the procedure available to other units that will use this unit.

variables. (The obvious fact. If you define an identifier inside the implementation section. What this means is that any unit using this unit will only be able to call the SayHelloTo. or a component. ReveredHello(ReverseString(YourName)). the identifier is hidden to the outer world. The SayHelloTo accepts a string parameter and displays a "hello" message (using theShowMessage Delphi RTL function). If you define a variable (identifier) inside the interface section the variable will be "visible" to all units using this unit. ShowMessage(hello). the function is "private" to this unit. A code unit can be used to define you own class (or type. constants. hello!'. This procedure calls the ReveredHello procedure. Several routines in a code unit can share the same "set" of variables. begin hello := YourName + '. We have two procedures: SayHelloTo and ReveredHello. whatever you prefer). end. end. etc. When designing the overall structure of your application it is essential to have an understanding of the scope (visibility) of identifiers (routines. types) defined inside the unit:   Everything defined in the interface section will be available to all other units using this unit Everything defined in the implementation section is available only Page | 112 . the ReveredHello is hidden to the "outside world" The scope Code units are not limited to functions and procedures.var hello : string. Let's see what's "inside". making the procedure available to any unit using this unit. The header of the ReveredHello function is not added to the interface section. The header of the SayHelloTo is added to the interface section. but I needed to write it down).

.. This is why our uses clause (in the interface part) lists those two units (Dialogs. You'll need to add different standard Delphi units. The SayHelloTo procedure uses the ReverseString procedure (StrUtils Delphi unit). both procedures use the ShowMessage routine defined in the Dialogs unit. In general.dfm} uses unit2. This is how you would call the SayHelloTo (once again: Unit1 cannot call the ReversedHello function) procedure from the unit associated with our main form: . you'll need to add the name of your unit to the uses list. Only when identifiers from another unit are used in the interface section is it necessary to list that unit in the interface uses clause. //don't miss this procedure TForm1. StrUtils). you are responsible for listing the units your unit needs to use. according to which routine you are implementing in your unit. Calling custom routines from form units In order to let a form unit use the procedures defined in your own unit. add a reference to standard Delphi units in the interface section. begin Page | 113 . to your uses list In the above example.Button1Click(Sender: TObject).within the unit Using standard (RTL) units When you create your own units. implementation {$R *. add a reference to your own code units in the implementation section. Recall that you can place the uses list in the interface section and in the implementation section of a unit.

.. With the use of the appropriate inclusion statement (uses list). Problems? One thing that might not be so obvious is how to know where to place the variable declaration in order to make a variable public. or private to a unit. More on scope. Local.the inner workings of a unit file are for you to take care of. end... now you don't!" So. . another one comes immediately after displaying the reversed message. you've created your first code unit. We'll add another unit to our sample project. variables. all identifiers listed in the interface portion of a unit are available to any program using the unit.Unit2. Here's the code: Page | 114 . public? As you can see. routines. We'll now move to the last part of this article to see what happens if unitA needs to use UnitB and UnitB needs to use UnitA.SayHelloTo('Zarko Gajic'). advantages of using code units include code reuse and information hiding. Start by creating a new code unit (Unit3). or "now you see me. the first one comes from the SayHelloTo procedure. all of which can be hidden from the calling unit (defined in the implementation section). Let's start with an example. The calling unit needs only to know the interface syntax to utilize the public functionality contained within the unit . private. And this is the "output": As you can see two "hello" message boxes are displayed. A code unit can contain constants. user data types.

begin ShowMessage('You do not see me!'). interface uses Dialogs. (*ExposedRoutine*) end. Confusing? If you try to access an identifier defined in this unit from unit1. this is what you'll see: Page | 115 . end. procedure HiddenRoutine. procedure ExposedRoutine var Glob : string implementation var Privat : string. end. (*HiddenRoutine* procedure ExposedRoutine.unit Unit3. begin ShowMessage('You see me!').

create a simple Delphi project. please post to the Delphi Programming Forumwhere all the questions are answered and beginners are treated as experts. Make a plan. we've discussed using Delphi IDE's features like code templates. which a calling unit can use/call. the code editor): start using code navigation features .quickly jump from a method implementation and a method declaration.. That's it. Chapter 18 Code Navigation in Delphi How to be even more productive with Delphi IDE (precisely."take two" Back in the thirteenth chapter of this Course. and more. how many times Page | 116 . How to code faster and more efficiently . However. code completion.. locate a variable declaration using tooltip symbol insight features. code insight. and more.quickly jump from a method implementation and a method declaration.).. make your code as much reusable as you can. Welcome to the eighteenth chapter of the FREE online programming course: A Beginner’s Guide to Delphi Programming. I hope you are using all those great code editor features every day. locate a variable declaration using tooltip symbol insight features. You are now left on your own! If you need any kind of help at this point. the code editor): start using code navigation features ...Bravo Delphi! When you write a unit name followed by a dot (. Delphi will display a list of all identifiers defined in the interface section of a unit. How to be even more productive with Delphi IDE (precisely. try adding several code units. Some exercises for you..

Code Navigation The most common way to navigate your unit's source is with the mouse and navigation keys. Code insight feature displays declaration information for any identifier by passing the mouse over it in the Code editor. Once you are "inside" the code. Code Browser. including tracing calls into various units comprising the project. make it visible by clicking on View-Code Explorer menu item in the main Delphi IDE. methods. The Code Explorer represents a project unit's in a tree-like diagram that shows all the types. you could be tempted to jump to the item's declaration in the interface section. This is where code (or module) navigation comes handy.how fast can you locate the class implementation? The answer is: Delphi Code Editor Navigation! Code Explorer When you work on a project. you need to navigate around the source code for that entire project.were you scrolling the code editor window just to find one method's implementation? How about having more than one class declaration in the interfacesection . which enables you to navigate through your unit files. classes. the cursor moves to that item's implementation in the Code editor. While you are working your way through the unit. If you cannot see the Code Explorer window in the Code editor. additional tools called Code Insight help with coding. global variables. Page | 117 . properties. Delphi includes a great tool called the "Code Explorer" (docked to the left of the Code editor). Here are the icon descriptions: When you select an item in the Code Explorer. and global routines defined in a unit.

This keystroke combination comes very handy when used with class completion...Now try this: hold down the Ctrl key and move the mouse over an identifier. Some exercises for you. Page | 118 . hit the Ctrl + Shift + DownKey or Ctrl + Shift + UpKey to jump between the method declaration (interface section) and implementation. Note: you can even browse through the VCL source is you Delphi version has one. or by hitting the Alt + UpKey key combination. simply start using Delphi code navigation features. You get the same effect by choosing Find declaration from the editor's context menu. and of course you can drastically reduce the number of bugs in your code. Clicking on the hyperlink will take you to the identifier’s declaration. Module Navigation And finally. here's my favorite: While working on a method's code. you will not believe how much time you can save in coding. and the mouse cursor will turn into a pointing hand. Hmm. It will turn into a hyperlink.

You're Reading a Free Preview

Download
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->