A simple Delphi programming example, with details applicable to any Delphi project.
__________
This example assumes you know something about programming.
It really isn't much use unless you have a machine running Delphi to 'sing along' with the instructions. You should be able to work through the example in about half an hour. I work in Delphi 1, Win 3.11... apologies if you find confusion with different versions or Win95.
__________
The program will give a simple arithmetic test. It is not polished to make everything as nice as you would want it to be. The instructions concentrate on just the essentials.
__________
a) Choose the name you want on the final .exe file. For the example, the name is TMA26. The various names I will derive from that are not required by Delphi, they are just my way of keeping track of what everything is.
b) Again, not REQUIRED by Delphi, but my recommendation. Create a folder (directory) for the project. Name: TMA26
c) Start Delphi, click File|New Project
d) Change the name property of Form1 to TMA26f1.. To do this, you use the Object Inspector, which was probably put on-screen when you started Delphi. F11 should bring it up if it isn't showing. The Object Inspector has two tabs at the bottom of the form: Properties and Events. There's also a listbox at the top, though at the moment, there's only one object in the list. From now on I'll say things like 'Change the name of Form1 to...' as a shorthand version of 'Use the object inspector, properties page, to change Form1's name property to...' (Events? We'll deal with them in a moment!)
e) Do File|Save Project As.., and
. i) Move to the directory you created for the project
. ii) Save Unit1 as TMA26u1.PAS
. iii) Save Project1 as TMA26.dpr
f) That has you started. From now on, you just....
Repeat
. Repeat
. Repeat
. Work on program, i.e. add code or modify earlier efforts
. Run program to see effect (within Delphi)
. Until nervous about amount of unsaved work
. Save project
. Until out of time for this work-session
. File|Close Project
. Go about the rest of your life until ready to resume programming
. File|Open Project
Until happy with program.
g) Next, you will 'Put a label called lHello on Form1'. I'll say how to do that in detail this time, but you'll have to learn the basic idea from this one blow-by-blow account.
i) On the Delphi toolbar (I hope that's what its called... the thingie with the 'File, Edit, Search...' menu) click on the 'Standard' tab of the 'Component Palette'. If you put your mouse pointer over the 'A' icon and wait a moment, a hint saying 'Label' should pop up. Click the icon (nothing much appears to happen.) Move your pointer onto the TMA26f1 form. Move it to about 1cm below and right of the upper left hand corner. Drag open a box that takes you to about 1 cm from the right edge of the form and 3cm down from the top. Release mouse button. You should see a label saying 'Label1' on your form. Click on the object inspector's listbox. You can see that you now have two objects. Label1 was already selected by the object inspector; leave it selected. Go down to the autosize property. Make it 'false'. Go down to the Name property, change it to lHello.
j) Change lHello's caption to 'Hello, welcome to my program.' Set alignment to taCenter.
k) Click somewhere within lHello on the Form. Change the size and position a bit, just to see that you can!
l) This would be a good time to check that File|Save Project works. You won't see much if it does... but if you get error messages sort out why.
m) Now run your program. There's a green pointing-to-right triangle on the toolbar for this, just left of two parallel bars, which are currently greyed out. You can press F9 if unsure of the right icon.)
You have now got far enough to get caught up in some tangles that have annoyed me from time to time.
While your program is running, you cannot do further work on it. To stop your program, you can do alt-F4, or (Win 3.x) click on the small box with the horizontal 'slot', upper left, which should give you a menu including Close, or just double click that little box.
If, when you try to run your program, you get 'Source has been modified. Rebuild?', click No. The program should run, but it may not incorporate changes you've made recently. Stop the program (as above, Alt-F4, or alternate), then you will be able to run it, and your changes will be incorporated.
If, when you run your program you get 'STOP: Project ... use Step or Run to Continue', just click the provided 'OK'. You may get another error message, or you may get taken to the text that makes your program do what it does. (The 'source code', TMA26u1.pas in the example.) Just click on the 'Run' green arrow and click OKs until you get to the point where you can stop you program (Alt-F4, etc), then edit, try again.
n) Now: Add two more labels, lower left of screen, one above the other, big enough to hold the text which appears. Set autosize false for both. Name them lNum1, lNum2. Make the caption of each 2
o) Add one more label: Lower right, autosize false. About 3cm high, 6cm wide. Name lRemark. Caption: What is the sum of these numbers?
p) Add an edit box. (The hint just says 'Edit'.) Put it beneath the two boxes lNum1 and lNum2. Autosize false, name eAns. (This would be another good place to save project!) Also, try running it. Your 'program' won't do much yet, but it shouldn't give rise to any error messages.
___
So far, we have just been creating the form which will appear when you run your program. The edit box we put on it is all that is needed for getting things into the computer... now this is how to make use of them....
___
q) Select the edit box (eAns). Click on the Events tab of the Object Inspector. Double-click in the listbox field just to the right of 'OnChange' at the top of the list of possible events. The screen will alter as TMA26u1.pas comes to the fore, and the following will have been added, in a suitable place:
procedure TTMA26f1.eAnsChange(Sender: TObject);
begin
end;
After the End and it's semicolon, add
(*of TTMA23f1.eAnsChange*)
It should come up in a different color and font, probably blue italic
On the blank line between the Begin and the End put
lRemark.caption:='Hey!';
and try to run the program. With the program running, click on the edit box. (It says eAns at the moment. Press a key, say 'x'. As soon as what is in the edit box changes, i.e. OnChange, the bit of program you wrote is executes, and the caption of lRemark becomes 'Hey!'. Not very educational, but a start! The effect of the line you wrote was, 'When the computer comes to do this, change the caption property of the object lRemark to Hey!'.
r) Now let's make things more educational....
Stop the program (If you haven't done so already. You always have to before making changes.)
Replace lRemark.caption:='Hey!'; with:
. if eAns.text='4' then lRemark.caption:='Hey!';
That still won't 'work' to help people learn adding, but play with the result... you should find that lRemark remains 'Good Luck' until you cnage the contents of the edit box to 4. Bear with me... this program will eventually do most of what it should... I simply want to get there a step at a time.
s) Replace your previous effort with... (leaving the Begin and End; (*of TTMA23f1.eAnsChange*) from before)
if eAns.text='4' then begin
. lRemark.caption:='Yes';
. end (*no ; here*)
. else begin
. lRemark.caption:='I don''t think so';
. end;
(BTW: the following is very useful, once you've practiced it a few times so you remember to use it: To select some text, either:
i) drag the mouse over it, or,
ii) use the cursor keys to get to one end. Hold down shift. Use the cursor keys (shift still down) to move to the other end.
Once you have text selected, ctrl-c will copy it, ctrl-x will cut it. Once you have copied or cut, you can paste with ctrl-v. If after making your first selection and copying or cutting, you make a second selection before pasting, the second selection will be replaced by whatever you paste. You can copy something from this text, then use the mouse to move to the program code window, and paste there.)
(Also BTW: If you already know Pascal, you will see that two Begin/End pairs above are not needed, and a semicolon or two. Don't worry about it... I had my reasons! And yes, I do know about StrToInt)
Semicolons: In general: If in doubt, stick one in. Don't, however, just before an 'else'... and the exception is rare enough that I usually put the '(*no ; here*)' reminder in on the relevant line.
Apostrophes: You can see the answer to a problem in 'I don''t think so'. If you want an apostrophe in a string, just do a double apostrophe.
___
This would be a good place to save project and take a break.
___
t) Now... Just before
procedure TTMA26f1.eAnsChange(Sender: TObject);
Add
procedure PickProb;
begin
TMA26f1.lNum1.caption:='5';
end;
Try running the program, no effect should be apparent yet, but there should be no error messages, either!
u) Use the Object Inspector to display TMA26f1's properties and events. Click on the Events tab. Double-clcik on the OnCreate even. Put the following between the Begin and End pair
PickProb;
Run the program. Other than saying that 5+2 is 4, all should be well.
v) Add to PickProb to make it:
procedure PickProb;
begin
TMA26f1.lNum1.caption:=IntToStr(random(9));
TMA26f1.lNum2.caption:=IntToStr(random(9));
end;
AND add to TTMA26f1.FormCreate to make it:
procedure TTMA26f1.FormCreate(Sender: TObject);
begin
Randomize;
PickProb;
end;
(Without that randomize in FormCreate, you get the same problems each time. You can find out more about individual Borland provided functions and procedures by putting the cursor in the name and doing ctrl-F1)
When you run the program, you should get different numbers to add, even though '4' is still always the 'right' answer.
Save project again!
w) About a third of the way down TMA26u1.pas, you'll find
var
. TMA26f1: TTMA26f1;
On the next line add
. sAns:string;
Also, in procedure PickProb, just before its 'end;', add
. sAns:='5';
Also, in procedure TTMA26f1.eAnsChange, make the first line say
. if eAns.text=sAns then begin
And run the program. Now the 'right' answer is always 5, once you have everything correct.
x) Change the sAns:='5'; in PickProb to
. sAns:=IntToStr(StrToInt(TMA26f1.lNum1.caption)+StrToInt(TMA26f1.lNum2.caption));
At last, the program should only say 'yes' for the right answer!!
y) Add a button to the form (icon has 'ok' on it.) Name it bGoOn, make caption say 'Click this to go on'. Add the following to TTMA26f1.FormCreate
bGoOn.hide;
Add the following to TTMA26f1.eAnsChange just after lRemark.caption:='Yes';
. bGoOn.show;
Make the OnClick event of bGoOn be
begin
bGoOn.hide;
PickProb;
eAns.setfocus;
end;
(The program will run without the eAns.setfocus, but you have to click on eAns before each answer.)
+++++++++++++++++++++++++++
There you have it! A working program. (And I didn't even massage this text to get the step lettering to come out so well.)
An overview of EVERYTHING (I hope) that goes into a minimal Delphi package!
__________
This discussion is more philosophical than most of my Tutorials. It gives you background, without much 'How To' stuff.
After you have made a start on even a tiny Delphi project, at least 7 files will have been saved on your disc. More on these files in a moment. BTW, in researching this tutorial, I allowed Delphi to use the names it liked for things.
When you are at work on a Delphi project, your main attention will be on two things:
. The form you have created, and..
. The code that 'drives' that form.
More on these in a moment.
______________________
You will likely NOT be particularly aware of another element, the .dpr file. However, I am going to start with it, because it is in overall charge. It is, you might say, the 'package' within which everything else is held.
(Remember to ignore .s at the starts of lines)
For a simple project, the .dpr file (in both Delphi 1 and 2) looks like...
.program Project1;
.
.uses
. Forms,
. Unit1 in 'UNIT1.PAS' {Form1};
.
.{$R *.RES}
.
.begin
. Application.CreateForm(TForm1, Form1);
. Application.Run;
.end.
(You can examine .dpr files (and .opt, .dof, and .pas) files simply by opening them with Notepad.)
That may be the last time you look in a .dpr file for some time... but remember it is there, for the future, in case it is involved in some mystery you are wrestling with.
In general, it is unwise to 'tinker' with the contents of the various files Delphi creates, except through the mechanisms provided by Delphi.
Well! We've made a start!
______________________
Now we'll deal with some odds and ends, just to be thorough. Stuff which is more useful follows.
After a progject has been run once, there is an .exe file. This is 'the program', it is what you give to people who you allow to use the fruits of your labours.
(If you are using one of the free copies Borland puts on magazine cover discs, you may find that the .exe file won't work on someone else's computer. Ditto if you are using one of the inexpensive 'Learn Delphi...' packages.)
In Delphi 1, there will be an .opt file, in Delphi 2 a .dof file. I think they hold the options you have set up for the project's development environment.
There is a .res file. I think this holds, or indexes, the projects 'resources'.. a term with a specific meaning in Windows programming.
For each form in the project, there is a .dcu file, a .dfm file and a .pas file. (Simple projects have only one form. Projects with more than one form are not used only by advanced programmers.)
I don't know what the .dcu file is for. :-)
You will encounter a number of extensions starting with a tilde, e.g. .~fm, .~as. I BELIEVE (but can't promise!) that these are previous versions of files which Delphi can in some circumstances resurrect, should you need to revert to an earlier version of your work.
______________________
Now we get to the meat!
The .dfm file holds everything Delphi needs to know about the parts and appearance of the form which your customer will see.
In Delphi 1, you can use View|Form to see the form in the 'normal' manner. Alternatively, you can use File|OpenFile, change the file type to .dfm, and then open the Unit1 form. You will get a text based description of the form. In Delphi 2, you right-click on the form and select 'View as Text' or 'View as Form' as required.
Usually, you'll want to view forms as forms, and edit them with the mouse based tools central the the RAD philosophy. If you want an ink-on-paper back-up of a project, you need to print out the project's .dpr, the text version of each unit's .dfm, and each unit's .pas. Far better to have machine readable back-ups of the project! Use File|Save Project As... and change just the folder specification, i.e. where the project will be saved.
___________________
The .pas file holds what I, an old-timer, think of as 'the program'. In the Good Old Days, it would have been..
10 FOR X=1 to 10
20 PRINT'HELLO'
30 NEXT X
Of course, nothing could be so simple with Windows. This isn't Delphi's fault!
You probably know that Delphi derives from Pascal? In Pascal, the program above would be:
. program hi;
. var c1:byte;
. begin
. for c1:=1 to 10 do writeln('Hello');
. end.
All right, I admit, it is a little longer... but worth it for various reasons connected with why programming in Pascal is a such a pleasure.
Now... Before I seem too critical, I must admit, the overheads I am about to describe DO bring certain benefits in their wake. I am, for instance, writing this in a wordprocessor, checking what it looks like with a web browser, and checking various things in Delphi from time to time... all on one computer, without doing anything tiresome to switch from application to application.
When you write for Windows, you have to remember a bunch of things, if you programmed on simpler systems in the past.
1) You do not have exclusive use of the machine. Your program is only one of many sharing the machine, even when no other user launched applications are running. Your program has to fit within the framework organised by Windows. In older terms, your program is almost like a procedure which is only only one of several being visited in turn by an outer loop.
(An aside: While you would probably get away with the equivalent of...
. FOR X=1 to 10: PRINT 'Hi': NEXT X
... it would be a bad thing to try. If for some reason the program got stuck in the loop, you would bring Windows crashing down. (Where have we had that experience?). Always put
. application.processmessages;
inside any loop which may take even tiny amounts of time to complete, or which could POSSIBLY fail to complete.... and remember that just 'cause you haven't notice why it isn't going to complete doesn't mean that it won't! For example, the following won't 'work':
SIMPLE DELPHI PROGRAM.....
. var c1,c2:byte;
. begin
. c2:=0;
. for c1:=1 to 500 do c2:=c2+c1;
. end.
Yes... I know you can see why not. But variable declarations are not normally so nicely close to variable mis-uses, are they?
(end of aside.)
2) (another thing to remember when working with Windows) It isn't easy (or often desireable) to set things up so that your user is marched through a process in quite the same orderly way that used to be the rule. It may help you to think of almost any Windows application as a video recorder. It is an object (that word! No coincidence) which has a certain appearance. (The appearance is defined by your form.) It behaves in certain ways. If you push the rewind button, it does that, for instance. Your program code ('for c1:=1 to 500 do c2:=c2+c1;', etc) is what determines the object's behaviour.
__________________
So far so good, I hope?
Don't panic (Mr. Mannering) when you see the next bunch of stuff. You'll know your way around it eventually. Furthermore, most of it is written for you by Delphi. Indeed... it is generally a bad idea to tinker with it WITHOUT allowing Delphi to assist your efforts.
That's the good news. The bad news is that the following is the 'core' of every unit's code... and almost nothing but core!
.unit Unit1;
.
.interface
.
.uses
. SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
. Forms, Dialogs, StdCtrls;
.
.type
. TForm1 = class(TForm)
. Label1: TLabel;
. procedure Label1Click(Sender: TObject);
. private
. { Private declarations }
. public
. { Public declarations }
. end;
.
.var
. Form1: TForm1;
.
.implementation
.
.{$R *.DFM}
.
.procedure TForm1.Label1Click(Sender: TObject);
.begin
.label1.caption:='Clicked';
.end;
.
.end.
END SIMPLE DELPHI PROGRAM!!
This program would need a simple form. The form would have a label called Label1, which initially said 'Hi'. When you run the program, clicking on the 'hi' would change it to 'Clicked'!
To write such a program using Delphi, the programmer would set up the form, and then add the single line
.label1.caption:='Clicked';
Prior to the programmer's typing 'efforts', clicks of his/her mouse (object inspector, label1 events, OnClick) would have added (near the bottom) the....
.procedure TForm1.Label1Click(Sender: TObject);
.begin
.
.end;
... and (near the top), the....
.procedure Label1Click(Sender: TObject);
The 'Label1: TLabel;' would have been added when the label was added to the form.
All of the rest of what you see in the 'Simple Delphi Program' listing is common to all Delphi units! It is the 'lines' on a 'blank' page.
___________________
And that's it! You now have a pretty good overview of the parts of any Delphi project. Developing an application is 'nothing more' (!) than building on the framework described. As your work progresses, from time to time, you will 'break' something. I hope that by giving you a clear picture of the overall structure I will have prepared you find and fix errors more quickly.
One strength... and one irritation... of Pascal (on which Delphi is built) is that it is quite fussy about the program's structure. Understand the syntax rules, and you will often find your mistakes easily. The fussiness does help you to build robust applications.
___________________
Future tutorials will address two related topics:
1) How you can add things to the basic framework. (For now, try not to be too adventurous.... Delphi helps you add things correctly... if you let it!) (Level 2: Adding Things To A Unit)
2) More detail on the Pascal syntax. (You can find lots of information on this in the Delphi Help files... don't overlook this valuable, if sometimes patchy or frustrating, resource.
--------------------------------------------------------------------------------
You shouldn't need to debug your programs!! (So why is it that I always have to debug mine?) If a program is written in a disciplined, careful manner it won't need debugging. I make this perhaps obvious, perhaps sanctimonious observation to encourage you to AVOID "poke and hope" programming. Almost always, if I try to "fix" something with a little bit of somehting that hasn't been thought throuh carefully, I end up with a mess that takes longer to get working than if I'd just worked a little more deliberately in the first place.
--------------------------------------------------------------------------------
Delphi offers great debugging tools. Master them, soon. In the meantime, just putting things like...
sTmp:=IntToStr(bMyVariable);
sTmp:='The value in bMyVariable at the moment is:'+sTmp;
showmessage(sTmp);
... in your code will often open your eyes to what your program is REALLY doing. (As opposed to what you thought you told it to do!) Choosing the right spot to put the little message sender is an art you will master. (The fancy alternative is called a "breakpoint", and you'll want to master "stepping through" and "tracing into" your code... but the message sending system described above will help until then!) (If you were to put the above into a program, it would need to have sTmp declared as a string, and not needed for other things at the moment, and you'd have a variable of your own devising and declaring called bMyVariable in use. IntToStr is built into Delphi.)
If a bug halts your program after it has started to run, you can use Run|Evaluate to check what values are in variables. Run|Evaluate can also be used for cheking your hex/decimal conversions, looking up ascii values, etc... even simple calculations: $10+5 gives 3 because $20 means 20 base 16 is 32, and 32 plus 5 is 37. ord('A') gives 65 because the Ascii code for 'A' is 65. (Purists: don't attack me. This is a BEGINNER'S tutorial!)
--------------------------------------------------------------------------------
Delphi, from it's roots in Pascal, is a very orderly language. The basis of that order is the "block".. a concept that rewards study. The Delphi environment helps you enormously when it comes to adding things to your code in an orderly manner. Suppose you've put a button on your form. Now you want to write the code to be executed if the button is clicked. Click on the button, if it is not already selected. Go to the Object Inspector. Click on the events tab (bottom of Object Inspector window). Click on the OnClick line... and Delphi does lots for you:
procedure TForm1.ButtonClick(Sender:TObject);
begin
end;
(and some other stuff in another part of the code!)
You jus ttype in the "special" stuff, mostly between the procedure's "begin" and "end". E.g.: For a button to close the application down, put application.terminate; in.
--------------------------------------------------------------------------------
I spoke a bit about variable naming in the Pascal Tutorial on debugging. Delphi, because of the complexities inherent in Windows, has more to contend with, but life isn't impossible, even so.
Try to be in the habit of naming ovbjects as soon as you put them on your form. The rules for naming them are the same as the variable naming rules. I tend to use the following prefixes:
For labels: la
For buttons: bu
For memos: m
For menues: me
For edit boxes: e
For panels: pa