HOME > > TUTORIALS TABLE OF CONTENTS > > Part Two of this tutorial - - - / - - / - - / - - / - - - Other material for programmers

Delphi tutorial

Click here if you want to know more about the source and format of these pages.

IGNORE ANY PERIODS (.) AT THE START OF ANY LINE

There is a search button at the bottom of the page.

This is still in a draft form.... it is probably mostly right, but I make no promises just yet!!!




Delphi Tutorial 3c... Part Three (version: 27 Dec 98)

In this part, we continue what we were doing in part two.... Now we need to create ConsiderNewScore.

After the first instance of...
procedure SaveHighScores;
(Not far below Type TDD04f1..)

... add ...
procedure ConsiderNewScore(Score:byte;Name:string);

...and just after...
implementation
{$R *.DFM}

... add ...
procedure TDD04f1.ConsiderNewScore(Score:byte;Name:string);
begin
{..}
end;

Developing this method is a little more tedious than what we've done before, because we want to call ConsiderNewScore from DD05. FOR NOW we will add some stuff to DD04 which will come out later. This stuff will be to get ConsiderNewScore debugged.

Add a button to DD04's form. Put it near the lower right of the form. Caption it 'Do it'. Make it's OnClick call ConsiderNewScore(4,'test');

Try running what ou have so far.

Now add to ConsiderNewScore, making it


procedure TDD04f1.ConsiderNewScore(Score:byte;Name:string);
begin
StringGrid1.cells[0,1]:=' '+IntToStr(score);
StringGrid1.cells[1,1]:=name;
end;


I'll skip the blow by blow account of how I developed the following finished ConsiderNewScore... once you've understood the above, replace it with...


procedure TDD04f1.ConsiderNewScore(Score:byte;Name:string);
var c1,c2:byte;
begin
c1:=0;
repeat
inc(c1);
until (StrToInt(StringGrid1.cells[0,c1])<=score) or (c1=10);
if (c1<10) or (StrToInt(StringGrid1.cells[0,c1])<=score)
then begin (*Insert new, push down old*)
for c2:=10 downto c1+1 do begin
StringGrid1.cells[0,c2]:=StringGrid1.cells[0,c2-1];
StringGrid1.cells[1,c2]:=StringGrid1.cells[1,c2-1];
end;(*c2*)
StringGrid1.cells[0,c1]:=' '+IntToStr(score);
StringGrid1.cells[1,c1]:=Name;
if OkToWriteToDisc then SaveHighScores;
end;(*push/insert*)
end;


Before we leave DD04, there is one other thing to do. Programs using DD04 will need to know the state of the 'OKToWriteToDisc' variable.

In the type section....

type
TDD04f1 = class(TForm)
StringGrid1: TStringGrid;
procedure FormCreate(Sender: TObject);
procedure SaveHighScores;
procedure ConsiderNewScore(Score:byte;Name:string);

... add ...
function fOKToWriteToDisc:boolean;

And near the bottom, add...

function TDD04f1.fOKToWriteToDisc:boolean;
begin
fOKToWriteToDisc:=OKToWriteToDisc;
end;

Remove the 'Do It' Button from the form. Remove everything between the begin and end of the second instance of procedure TDD04f1.BitBtn1Click. Run and stop DD04 one more time. Save it. Close it.

REMEMBER TO COPY the REVISED ddo4.dcu and dd04.dfm to the Delphi Lib directory, if the problem mentioned a long way above about setting the library path hasn't been resolved.

Now open DD05 again.

Replace the line which said...
dd04f1.stringgrid1.cells[1,1]:='Works!';

with the following which are a quick test that the two programs are working together:

dd04f1.ConsiderNewScore(50,'Test50');
dd04f1.ConsiderNewScore(150,'Test150');
dd04f1.ConsiderNewScore(20,'Test20');

(Remember... the scores must be <256 because we are using type byte variables for them.)

Once that's working, take out those three lines before you forget!

Now we'll build the game. Use Notepad to create the two data files, if you haven't already created them.

Next we'll write what is needed to get those datafiles into the program so it can use them. Add the following to the private section of DD05...
Right,Wrong:tstringlist;

And add to the var section....
bNRight,bNWrong,GameScore,RoundsDone:byte;
FirstIsRight:boolean;

(RoundsDone isn't to do with the stringlists, but I'm getting it out of the way here! GameScore and FirstIsRight will get used a little later.)

Add the following to the FormCreate handler. It loads the datafiles into two StringLists, and makes a note of how many sentences are available in each list...

Right:=Tstringlist.create;
Right.Loadfromfile('C:\dd05r.dat');
bNRight:=Right.count;
Wrong:=Tstringlist.create;
Wrong.Loadfromfile('C:\dd05w.dat');
bNWrong:=Wrong.count;
RoundsDone:=0;

Now add five labels to the form. Label1 & Label2 should be long and thin, Label1 above Label2. They will hold the two sentences, one right, one wrong. Make Label3's Autosize property false, and WordWrap true. Make the caption: 'Press H or J if the top sentence is right, press N if the lower sentence is right.'

Label4 is for the score. Initialise it's caption to 'Score so far:0'
Label5 is for the count of the rounds done. Initialise it's caption to 'Rounds so far:0'

Now we'll write a general 'Set up a problem' routine.
Just after...
private
{ Private declarations }
Right,Wrong:tstringlist;

... add...
procedure SetUpProb;

Just after...
implementation
{$R *.DFM}

...add...
procedure TDD05f1.SetUpProb;
begin
Label1.caption:=Right.strings[0];
end;

(as a first stage)

... and after...
bNWrong:=Wrong.count;

...(currently the end of the FormCreate procedure), add...
Randomize;
SetUpProb;

Run it. When that much is running, extend SetUpProb as follows...

procedure TDD05f1.SetUpProb;
var c1:byte;
sTmp1,sTmp2,sTmp:string;
begin
c1:=random(bNRight);
sTmp1:=Right.strings[c1];
c1:=random(bNWrong);
sTmp2:=Wrong.strings[c1];
(*Two sentences chosen. Now, perhaps, reverse the order*)
FirstIsRight:=true;(*prepare fro next*)
if Random(2)=1 then begin
(*Make second sentence the right one sometimes*)
FirstIsRight:=false;
sTmp:=sTmp1;
sTmp1:=sTmp2;
sTmp2:=sTmp
end;
Label1.caption:=sTmp1;
Label2.caption:=sTmp2;
(*N.B. Using a variable to carry a message a long
way within a program, as I'm using FirstIsRight, is
not in general a very good idea.*)
end;


In a moment we'll add an OnKeyPress event handler to the main form (DD05f1). The code will be presented in a moment. It will allow the user to say which sentence is the right one by pressing keys.

SET FORM's KEYPREVIEW PROPERTY TRUE, or the KeyPressed handler is useless.

Before you add the OnKeyPress handler, add the following to the form....

Panel1. Put it someplace out of the way, perhaps lower right. Make it's caption nothing.
Put an edit field on it.
Put a button on it; make the caption 'Done'
Put Label6 on it; make the caption 'Please type your name'

Add to FormCreate...
Panel1.align:=alClient;
Panel1.hide;
Button1.hide;
Edit1.hide;

Now add the following as the event handler for the form's OnKeyPress event. (See below for other things to do before testing)


procedure TDD05f1.FormKeyPress(Sender: TObject; var Key: Char);
begin
key:=upcase(key);
if (key='H') or(key='J') or(key='N') then begin
if ((key='H') or (key='J')) and FirstIsRight then
inc(GameScore);
if (key='N') and not FirstIsRight then inc(GameScore);
Label4.caption:='Score so far='+IntToStr(GameScore);
SetUpProb;
inc(RoundsDone);
Label5.caption:='Rounds done='+IntToStr(RoundsDone);
if RoundsDone=20 then begin (*A game finished*)
Panel1.show;
Button1.show;
Edit1.show;
Edit1.setfocus;
Edit1.text:='';
end;(*A game finished*)
end;(*H,J or N pressed.*)
end;


If you want to experiment with the game a bit, it may pay to set the number of rounds per game (currently 20) to something low, e.g. 8. (You do this at the 'if RoundsDone=...' test.)

Before that will work, you must also create the Button1 OnClick handler:


procedure TDD05f1.Button1Click(Sender: TObject);
begin
if edit1.text='' then edit1.text:='-- No name given --';
DD04f1.ConsiderNewScore(GameScore,Edit1.text);
GameScore:=0;
Label4.caption:='Score so far='+IntToStr(GameScore);
RoundsDone:=0;
Label5.caption:='Rounds done='+IntToStr(RoundsDone);
SetUpProb;
Panel1.hide;
Button1.hide;
edit1.hide;
end;


N.B. The call to ConsiderNewScore!

Well! 95% done! All that remains is to arrange for DD04 to save the current state of the High Score Table when it is terminated.

>>> FROM HERE TO THE ===s below is my first attempt to take care of the SaveHighScores need. It seems the more elegant solution, but it didn't work. Anyone know why?

Save DD05. Close that project.

Open DD04. Add the following as the handler for the form's OnDestroy event:

procedure TDD04f1.FormDestroy(Sender: TObject);
begin
if SaveHighScores;
end;

Run DD04 to get it compiled.
Stop it.

REMEMBER TO COPY the REVISED ddo4.dcu and dd04.dfm to the Delphi Lib directory, if the problem mentioned above about setting the library path hasn't been resolved.

You can test the latest improvement without shutting down DD04. Just double click on DD05.exe in the File Manager (Win3.1) or Windows Explorer (win9x)

=== End of the SaveHighScores approach which didn't work.

Alternate solution:

Make DD05f1's OnDestroy event be...

procedure TDD05f1.FormDestroy(Sender: TObject);
begin
if DD04f1.fOkToWriteToDisc then DD04f1.SaveHighScores;
end;

A few final thoughts...
It is easy enought to change properties of the DD04 object at run time. For example (though I haven't tried it) I'm pretty sure you could move the DD04 Window around the screen with DD04f1.top:=50;, etc.

However, suppose you wanted to set one of the DD04 properties at design time? You could, for instance, add a property to say whether or not to OFFER the option of saving the datafile. This would need to be set before the OnCreate of DD04 was executed to give an elegant solution. With a normal, registered, Delphi component, setting properties at design time is simple. (You just use the object inspector.) If there's a simple way to alter initial property settings without registering a component, I haven't thought of it!

Registering the component would probably get you around the messy bit of creating the function to access the contents of OKToWriteToDisc, too.



   Search this site or the web        powered by FreeFind
 
  Site search Web search
Site Map    What's New    Search


Click here if you're feeling kind! (Promotes my site via "Top100Borland")
Ad from page's editor: please visit my freeware and shareware page?

Editor's freeware, shareware page.


Link to Tutorials main page
Here is how you can contact this page's author, Tom Boyd.


Valid HTML 4.01 Transitional Page WILL BE tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org


If this page causes a script to run, why? Because of things like Google panels, and the code for the search button. Why do I mention scripts? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....