HOME - - - - - - - TUTORIALS INDEX - - - - - - - - - - - - Other material for programmers

Delphi: State Diagrams for Programming Success


Thank you Wayback Machine!

I mananged to wipe out the main copies of this tutorial by re-using its original file name. Happily, the good people of the Wayback Machine saved my bacon, and thus, thanks to them, this material is available to you once again. Whew.

And thank you, nice person from www.Baltissen.org, who alerted me to the problem. You might enjoy a visit to that site, if you are interested in retro-computing... Don't be alarmed when, for a moment, it looks like your system has dropped into a command line environment!

This tutorial aims to help you understand State Diagrams. If you use them, your programming will proceed more smoothly. You will be able to stay in charge of your application, rather than it getting out of comprehension or control. Etc. They are a Good Thing. (They give the programmer in an event driven environment a replacement for the flowcharts and structure diagrams which were so important in "the good old days" when programming was simpler.

This tutorial has Good Stuff for programmers of any event driven language, by the way. The tools explained here can be applied to more than Delphi.

This tutorial is meant for people with some experience of Delphi, as it is a tool about how to plan your application, not about writing the code that will make your application do what it should.

Just before we start, please be advised that my pages are browser friendly. Make your browser window as wide as you want it. The text will flow nicely. It is easier to read in a narrow window... and the rest of your screen will be free for your ooBase exercises! Hold down the control key ("ctrl") and press the plus sign, the minus sign, or zero to change the size of the text in Firefox and other good browsers. This and another good hint explained on my Power Browsing page!

Where we're going -

To illustrate the use of state diagrams, I will create a simple geography drill. I will be using Delphi 4, but I know of no reason that it would not work the same way with other Delphi versions.

The point of this tutorial is NOT the finished application.

Some elements of the demo application will seem "excessive" for the modest application that it is. They are there because...

What the application will do -

There will be two ways to start the application:

Simple start-up scenario: If the "simple" start is used, the application will ask the user for his/her name.

Fancy start-up scenario: If the administrator has set up a shortcut with a CLP (more anon), the application will start up with the user's name already known to the application.

The user will be asked something like "What is the capital of France?" In the application built for the tutorial, the questions will be hard-coded. They will be in an array which is filled inside the application. It would be easy, and essential to a "serious" commercial drill/practice program, to arrange for the questions to come from a data file. But the details of implementing that are not necessary to the points this tutorial is making.

The user then tries to answer the question, pressing "Enter" to signify his answer is complete.

The answer is assessed, feedback is given, the user's score is updated.

And so on, until five questions have been answered, at which time the application shuts down.

At almost any time during the exercise, the user can save his score. This is a bit pointless in the exercise implemented, but important to showing you a "trick". At the time I was inspired to write this tutorial, I was working on a program which can remember a user's performance on individual questions, and, after the user has spent time with the application, mostly present questions that the user frequently gets wrong. There is a "save" button in that program which saves the computer's current record of the user's proficiency.

I said "at almost any time during the exercise..." Again, just to show you a "trick", the user cannot save his score before answering the first question. Nor can he save it again after saving it once until he has answered at least one more question.

Right... let's use a state diagram to define our plan -

We're going to write this application twice. The first time we will concentrate on essentials, and skip many details. The second time, we will do all of what was originally promised.

The point of this tutorial is NOT the finished application. so what IS the point?

Have a look at the following figure. It is the point of this tutorial! And it is the overall plan for how our application is going to do what I said the application would do. It is NOT a traditional flow chart, by the way... don't be fooled by the similarity.

State Diagram- Overall plan

The colors are of limited significance. They are merely there to differentiate between the two "paths" to the state called "Awaiting User's Answer".

We'll go through the diagram many times. Start by noticing the five boxes...

These boxes represent the STATES the program can be in. Note well: they do NOT, directly, relate to any program code.

As you use any program, it passes from state to state. For instance, when I started my text editor to create what you are reading, at first the text editor was sitting on my screen "empty". I then said "start a new document", and the editor moved into a "ready and waiting with empty sheet" STATE. I then typed some text. The editor could be described as being in a "holding some unsaved text" STATE. I then saved my work so far, and the STATE changed to "holding some saved text". If I chose to, I could ask the editor to create an ink-on-paper copy of my text. That would involve moving through a "Getting information for printing" STATE, passing to a "Printing" state, and then returning to a "Waiting to see what the user wants next" STATE.

Years ago, someone told me that I could manage my Windows projects if I used State Diagrams. I doubt that what I am presenting in this essay is exactly a "state diagram" in the sense taught in "proper" programming courses... but I'm going to call it a "state diagram" anyway. The diagram above shows the states the geography test application can be in. We'll go through the diagram more carefully in a moment.

Note that there are also lines on the diagram, connecting the boxes which represent the application's possible states. Those lines indicate what state transitions are possible. You can, for instance, as the application has been planned for the purposes of this essay, go back to "Awaiting user's answer" from "Eval Ans (etc)"... but you can't (as the program has been planned) go back again to the beginning and specify a different user. The lack of any arrows for such a transition between states tells you this.

THE PURPOSE of the diagram is to help you pin down exactly what your application should (and should not) be able to do. It doesn't give you too much help with how the application is going to do what you want... but it does give you a firm statement of the planned possibilities. A sound plan is the bedrock upon which applications are developed relatively painlessly into reasonably stable products.

In the good old days, we had flow charts. They were so easy. They worked so well. The following is roughly speaking a flow chart for the application we are developing...

Initialize things.
Get User ID
Repeat....
   Ask a question
   Read an answer
   Evaluate: Right or wrong
   Give Feedback
   Update scores
Until five questions have been done.

That may seem terribly close to what is in the earlier diagram. Sadly, with Windows, due to its event driven nature, things are more complicated than at first they seem. But not impossible. Especially when you master the planning tool this tutorial is all about.

In a moment, using the state diagram, we'll write the code for a crude version of our geography test program.

Before we go on to writing our code, I need to explain the diagram a bit further.

There are 5 boxes with square corners in the state diagram. They each stand for one of the states the application can be in while it is running.

The "Start" lozenge tells you where we come from when the application is made to run. The "End" lozenge is the "exit", the path to "application no longer running."

The box with rounded corners, "On eAns has complete answer" identifies an event. More on this later.

Going back to the boxes depicting states. You'll notice that some of the state boxes are split by vertical lines into several compartments. The first is always the name of the state the box stands for. If there are more than one compartment in a state box, each of the lower compartments identifies a condition. From each one a line is drawn. Each line leads to a state you will change to, from the current state, when conditions are as described in the box. So.. in the full version of the application, from being in the "Initializing" state, we can pass either to the "Awaiting ID" state, or to the "Awaiting user's answer" state. The latter will happen if the ID was given in a CLP.

Now... I apologize for the fact that I cannot explain the following with absolute rigor, but even so, I can tell you that the matter is critical.

Look at the "Awaiting user's answer" state box. It has no arrows leading away from it. I believe that every Windows application must have at least one such a state.... I could be wrong about this, but take the idea as a working hypothesis. There may be more than one such box in some programs. The double lines on the sides of the box have been used to show that it is one of the special boxes. We'll look at this some more later on.

All the other boxes identify states through which the application will pass relatively quickly. Admittedly, it will get "stuck" in the "Awaiting ID" box if the user doesn't supply an ID, but there's "a place to go" immediately after an ID is supplied. There is no such "onward destination" for the "Awaiting user's answer" state.

Without such a "destination-less" state, the application must either be very, very simple.... e.g. Print "Hi"; Print "Nice day"; Print "Bye", or you end up with a difficult "hall of mirrors" situation, in which, say, you call "Ask Question", which call's "Get and Process Answer", which then calls "Ask Question".... which is something that might start well enough, but where does it end? How would you code that? How would you end the movement down the hall of mirrors?

As I said... we'll return to the "destination-less" states again later. Even so, what follows should, I hope, help you to see some very useful things.

Some code, please! -

Fetch this zip file (DD77simple.zip). Unpack it. It it a crude, simple, first "attempt" at the application I said we were going to write.

Before we talk about the application's code, a quick word about the window which users will see. That is another tool for building applications relatively easily: Keep a clear plan in your mind (and maybe on paper) about what the user sees when the application runs.

The application will have just one form. On it the user will see the following. The name in brackets won't be known to the user.


Label (laUser): Displays the user's name.
Label (laQuestion): Displays the question, e.g. "What is the capital of France?"
Edit Box (eUsersAnswer): Where users type what they think the answers are.
Label- laMessages. For things like "Last question answered correctly".
two more labels (laQsDone, laScore): Display how many questions have been done, and the user's score so far.
Button (buQuit): Click this to terminate application.

Before anything else, let's get a minor item dealt with. Double click on the "Quit" button. Delphi will generate a skeleton buQuitClick procedure. Between the Begin and the End insert....

application.terminate;

Don't fall to the temptation of leaving this out... we "need" it for more than the obvious quick way to quit the application... You'll see below that what may be present in the program to handle a button click event can have other uses, too.

I trust, gentle reader, that you are conversant with the "FormCreate" procedure which is part of every Delphi application? (I did say that this tutorial is best read when you've mastered the early part of the learning curve.) Don't worry too much if you don't know about FormCreate... just double click in a "neutral" part of your form, and Delphi will create a skeleton "FormCreate" handler for you. This procedure is called as the application fires up.

For the simple version of our testing program, FormCreate will need the following...

iScore:=0;//Start the user's score at zero.
bQsDone:=0://Start the tally of how many questions answered at zero.

Another thing that we want in FormCreate is a line to set eUsersAnswer.enabled to false. (Of course, we could also do that with the design tools, if you are worrying.) This is to prevent a user from putting in any "answer" before there's even been a question. Not a likely thing for a user to do, but it could cause problems if one did.

Also within FormCreate, there will be the following call: GetID. "GetID" will be a procedure which we will write in a moment. It would be more sophisticated to use a function call, but I've done things the bumbling way to avoid what could be a distraction for some readers.

Still within FormCreate, after calling GetID, we will call another procedure, also written by us, called PrepQ, for "Prepare the question, put it on the screen."

Look again at the diagram. See how it really isn't a traditional "flow chart"? By the time FormCreate has finished... and it DOES finish, we COME BACK from both GetID and PrepQ.... we will have reached the "Awaiting user's answer" state.

Just a little aside here, to go through what is in the two procedures....

GetID consists of....

sUserName:=InputBox('GetID', 'User name?', '');
laUser.caption:=sUserName;
(I suppose you could call it "GetAndDisplayUserID".)

PrepQ consists of....

(By the way, a more sophisticated state diagramming system would include notes about what variables are changed during states, and as the application passes from state to state.)

Now we'll look at events and their handlers -

All the time that the computer has been doing the things required of it by the code in our FormCreate procedure, it has been "watching" various things... the keyboard, the mouse, the time of day, etc, etc.

Once PrepQ enabled the eUserAns edit box, the computer started watching that. Every time what's in it changes, an eUsersAnswerKeyPress event "fires"..... and if we've provided an event handler, computer will do what we've specified.

Here's the eUsersAnswerKeyPress handler we need. The "if key=chr(13)" is to see if key just pressed is an "Enter", which is when we do lots of things. (If the key wasn't an "Enter", the event handler does nothing.)

procedure TDD77simpleF1.eUsersAnswerKeyPress(Sender: TObject;
  var Key: Char);
begin
if key=chr(13) then {has no else clause} begin //1a
    if eUsersAnswer.text=sRightAnswer then begin //2a
    laMessages.caption:='Right! Good!';
    iScore:=iScore+20;
    inc(bQsDone);
    end//no ; here    2a
  else begin //2b
    laMessages.caption:='No. Answer was: '+sRightAnswer;
    inc(bQsDone);
    end;// 2b

//The following lines implement the two ways of leaving
//  the "Eval Ans/ Give Feedback...." state....

  if bQsDone<5 then PrepQ //no; here  (<5 because the count of q's
       //done goes up AFTER this point in the code.
    else buQuitClick(self);

  laQsDone.caption:=inttostr(bQsDone);
  laScore.caption:=inttostr(iScore);

  PrepQ;

end;//1b... here ends the things done if key=chr(13)
end;

Note that our planning diagram doesn't, exactly, refer to the eUserKeyPress handler. Rather it refers to a special case of change in the edit box's contents... it is when the user presses "enter" to say "there it is, there's my whole answer" that the application proceeds to begin going through the heart of the EvalAns code which is found in the eUsersAnswerKeyPress procedure, just given.

I hope you can see the part of the code which tells the user whether the answer given was right, and tally the result.

Next, still within the eUsersAnswerKeyPress procedure, we see if 5 questions have been done. If not, we call PrepQ... the same procedure we called earlier. That will execute, and we will return from the procedure call, and the execution of the eUsersAnswerKeyPress procedure will be complete. And, without any further ado, with no "Goto" or sub-routine call, we "fall" back into the "Awaiting user's answer" STATE. Magic. I'm sure the elegance of all this deserves more words, but I don't know what they are. Just appreciate the "magic."

What about the other case, when we HAVE done 5 questions? The plan is, because it illustrates something, that the application will then just shut down. There will be some frills in the fancier version, such as saving the user's score first, but at the moment we're working on the crude version, and the crude version just shuts down.

It does it by calling the buQuit procedure. Notice the messiness? We're shutting down the application with a call within a call. When the application hits "application.terminate", both "EvalAns" and "buQuitClick" are still executing. Untidy, but I don't know a better way to accomplish what we need. And I'm pretty sure that the necessary things to deal with our messy exit are built into Delphi. More complex "messinesses" can lead to memory leaks... but what we're doing here is "okay", I believe.

Returning briefly to the "Awaiting User's Answer" box on the state diagram. This is a genuine state... there will be times when we are in this state. The state in special in the ways already mentioned, and in another way. No code is needed in our application in respect of this box. When we enter the other states, usually things happen, and it takes code to make things happen. Or things happen to take us out of the states. Half of me would like to just do away with the "Awaiting User's Answer" box... but it might make things a little too abstract. Also, we need destinations for the various arrows leading out of earlier states, with their "what we do to leave previous state" information.

Remember: There was a link further up the page to let you download a zip file with the finished application, and all of the source code, etc., needed to compile it yourself.

Now we'll move on, after an excursion, to writing the more complete version of the geography test application. Most of what we've built already will remain, but we'll some frills... frills which illustrate ways to do the things you will probably want to do in serious applications.

A recap of the marvels and method of state diagrams -

So... at this point I hope you've grasped the basics of my program design tool, a use of state diagrams to facilitate describing what can happen in an application running in an event driven environment like Windows. I believe it would work just as well with Java. (I hope so, because I really, really want to do more with Linux!) (If any reader can point me to authoritative online texts which also discuss this "wheel" which I expect I've only imperfectly reinvented, I'll be delighted to hear from you!)

The state diagram may look like a flow chart, but it isn't your father's flow chart.

There will be a start point. When the system described by the state diagram is turned into a Delphi application, the application will invoke the FormCreate procedure will be invoked just after the "start" lozenge of the state diagram, and do some or all of what must happen during the "initializing" state, which will normally be the first state, the one the "start" lozenge points to. In some programs, there will be no need for FormCreate to take us beyond the initial state, as described by the state diagram. (More on this in a moment).

What about the end point? Here my state diagrams indulge in a fudge. Even the simplest of Delphi applications responds to the generic Windows "close", resulting from clicking the little "x" in the upper right hand corner. If you don't write code to exploit the services of the CloseQuery function, then, if you wanted to be rigorous, you would have to add a condition box at the bottom of every state box on the diagram. In that condition box would be "Windows Close invoked", with an arrow to the "End" lozenge in your state diagram. I think we can take those elements for granted, can't we? But we will include on our state diagrams any extra ways to shut down the application which we may have programmed into it.

Flow charts (and the very useful structure diagrams which did similar work) had one entry point, one exit. Not so state diagrams. The introduction of event driven operating environments robbed us of that nice simple world.

To cope with the event driven environment, we accept the fact that our state diagram may have multiple entry points. There can even be "dead ends"... states from which there are no apparent "next states".

A short excursion to work through another example-

Let's look briefly at a different, very simple application, that great classic of introductory computer programming courses, the temperature conversion application.

In our version, there will simply be a main form, with two edit boxes, plus a few static labels. One edit box will be labeled "Fahrenheit", the other "Celsius". Users can change the number in either box. As soon as they start to change one of the numbers, the other edit box will become empty for the moment. When the user presses enter, the other box is filled with the temperature expressed in the other units. (This would be an excellent exercise for you, by the way! Have fun with trapping invalid inputs!)

The state diagram you'd need.....

State Diagram- Temperatures Conversion program

... has two of those boxes with double lines on the vertical sides. In this very simple program, the special case represented by that kind of state becomes more clear. If, after "doing some stuff", you reach a point where the program can just sit quietly on the screen until some event triggers activity, then you have reached one of those "double line" boxes. A double line box arises when there are no lines out of a state, i.e. there's no "next state" tightly bound to the state in question. Single line boxes will also often have one or more condition boxes, so that what state we move to next can await some condition which is coming, and we can have more than one potential destination state. Sometimes... as in the "Awaiting ID" box of the first example... the condition that leads to moving to the next state doesn't need to be spelt out.

Note that the text in the state boxes usually has a word ending "-ing". The state boxes' labels describe what is happening, or how things stand, while the application is in a particular state. The "Eval Ans/ Give Feedback/ UD scores" box might better have been labeled "EvaluatING answer/ givING feedback to the user/ updatING the scores."

Going back to the temperature conversion application for a moment.

If you fetch this zip file (DD77letters.zip), it will give you a little application built on the structure diagram of the temperature conversion application. Instead of temperatures in Celsius and Fahrenheit, the application accepts strings of characters. When you press enter, the characters are converted to their upper and lower case forms. (The temperatures application would work the same way, but you'd have some complex details to deal with because users could enter anything, and how do you convert "Celsius" "XYZ" to the Fahrenheit equivalent? Etc.)

The better version of the Geography application -

Now turn your thoughts back to the simple geography test application. The plans called for a way to save the user's score. The coding isn't difficult, but it makes a nice example of a few things you'll do if using the state diagrams to stay manage the development of an application. It also provides an example of a useful "trick" for turning sundry features on and off. This is another instance of something I've said a couple of times: Saving "the score" is pretty pointless in the application as it stands. We're looking at a simplified example of something that would be useful in a more complex form.

Close anything you happen to have open in Delphi, download and unzip this code (DD77best.zip), and run it.

You'll see something quite like what you had before. There have been some cosmetic changes, and some extensions.

There's a button called buSaveScore, and it will work... in certain circumstances. More on that in a moment.

The GetID procedure has been altered so that if there is no user ID in a CLP (more on THAT later, too), the user will be "FromHardCode". (You could easily change the application back to allow users to put in their names. (Just look inside GetID.) Having to endlessly enter a name gets annoying while you are de-bugging other things!)

Before we start, an explanation of the "ID in CLP" and "No ID in CLP" and "Awaiting ID" stuff.

What is "the ID"? While the application is running, it will have the user's name on the screen. When scores are saved, the name of the user will be saved in the scores file. the user's name is "the ID"

We'll keep the user's name in a variable named sUserName while the application is running.

In the advanced version of the application, there will be two ways of filling sUserName with the user's name. It will be possible to use a CLP in a shortcut (more on this later), or, we will be able to go the more obvious route of typing the name on the keyboard.

Another change (which you may welcome!) has been made to make de-bugging less tedious. For now, the "right answer" to each question is just the first letter of the true answer, and that you don't need to use upper case. You do still have to press enter after typing the letter. (See the PrepQ procedure if you want to put the application back to requiring the full true answer.)

To our earlier state diagram, we could, if we wanted to be uber-thorough, add the following. Just before you look at that, notice that our application's main form has gained a button called "buSaveScore"...

State Diagram- Saving

What's with the "MAYBE saving score"? When the user clicks the Save Score button, the program will enter the "Maybe Saving Score" state. Usually, the score will be saved. In any case, once the score has been saved, we're done. Perhaps puzzling to the reader who might think are we going to be stuck (maybe) saving the score for evermore? Hopefully, the double lines on the box's side say that once the saving is done, everything connected with the buSaveScore event handler is finished, and now the program has gone "back to sleep", back to awaiting some event to trigger the execution of some code. The "Maybe Save Score" state arose "on top" of other things.... and now it has gone away, returning us to whatever was going on before the Save Score button was clicked. Note the subtle differences between the two double lined boxes we have met. The "Maybe saving score" state may never arise. The application will always "sink down into" the "Awaiting user's answer" state because, "upstream" of that state is the "Start" lozenge.

"MAYBE save score": When you look at the code for buSaveScoreClick you will see why that part of the state diagram was called "MAYBE save score". If the player hasn't answered a single question yet, the buSaveScore button's click is "handled", but the score isn't saved. Not a big deal in terms of this illustrative application... but in real world work you will often find things that will only happen in selected circumstances.

Now we'll turn to a new matter related to buSaveScoreClick. The "MaybeSaveScore" example is here because it also shows you that sometimes something which may be executed to handle an event, e.g. the clicking a button, may also be called other ways.

After we do our last question, the application (as written) goes straight to the closing down state. As we enter that state, we're (maybe) going to save the score again, using the same code as was used by the buSaveScoreClick event handler. Having one lot of code deal with multiple situations not only saves you time, but it limits the number of places bugs can hid. And it makes revising things easier. Suppose, for instance, you wanted to change the name of the file to which the score is saved. The way we've written the program, you'd make one change. In a program with separate procedures for saving the score ...

... it would be easy to forget to change one or the other if a change to all saving was wanted.

Moving on.... The Save Score button is going to be used to illustrate another thing you may want to do!...

It would make no sense to save the score before the first question has been answered. It also makes no sense to save the score again if the user has saved it recently, and not yet answered any more questions! So: not only will there be a test within the SaveScore code, but the Save Score button will not be enabled until a question has been answered. Why do we need two "locks" on the saving? What if we only turned the button on when a save was appropriate, and didn't bother with the check within the code? How else could the application try to save the score at an inappropriate moment? (Try to answer that question for yourself before reading on.)



v



v



v



v



Get it? I hope so. Answer: If a user clicks the "Quit" button before even the first question has been answered, then when, as part of the quit process, we try to save the score, we'd be saving the score of someone who hasn't answered any questions yet. Which brings me neatly to the code connected with the "Closing" state, which is within buQuitClick.

Look at the buSaveScoreClick code (not the SaveScore code) to see the test that prevents the application from saving the score before any questions have been answered.

The other locking/unlocking is done as follows:

In FormCreate, I added: buSaveScore.enabled:=false;

In eUsersAnswerKeyPress, I added: buSaveScore.enabled:=true; (This will be done again and again, when in fact it may seem that it is only needed once, but the repeated execution will do no harm. A remark with the line of code saves confused programmers from investigating the curious inefficiency. Complex code to achieve "only do this when it is needed" just clutters up the program, giving bugs places to hide. That isn't to say that you should never care about superfluous execution of lines. If something is inside a loop that will execute many times each time it is entered, you may need to take trouble to eliminate unnecessary lines of code.)

And, lastly, in buSaveScoreClick, I added: buSaveScore.enabled:=false;

... in order to prevent users from saving their scores again when they've just saved them. Once that is in place, the "extra" executions of buSaveScore.enabled:=true in eUsersAnswerKeyPress are NOT superfluous.

And so, with just three assignments to buSaveScore.enabled, we've installed some elegant process control.

One last bit of code -

Finally, we come to the code connected with the application's closing.

Initially, we had a simple buQuitClick handler which was invoked if a user clicked the Quit button, and which did "double duty" as the way we moved from the "EvalAns..." state to the Closing state.

We're going to enhance buQuitClick, so that it invokes the SaveScore in some circumstances. The code used to consist of just the one instruction...

application.terminate;

Now it consists of....

if buSaveScore.enabled=true then buSaveScoreClick(self);
application.terminate;

Notice how the state of the buSaveScore button (enabled or not) tells us everything we need to know? A well planned program, which hasn't has clumsy "fixes" recklessly stuck on will usually be neat and elegant like this. Notice that we are essentially using the "enabled" property of the button as a boolean variable. There's no need to maintain "copies" of the information in "everyday" variables.

The buQuitClick event, and it's handling could be turned into another diagram like the one we did for buSaveScore pressed. While I would certainly make a note of some sort about the presence in the application of those buttons, I'm not sure I would be pedantic and draw out the diagrams for those elements of the COMPLETE state diagram.

That's about it -

You've seen the buSaveScore button turned on and off in various places. In anything bigger than the tiny demonstration application we've explored here, I'd be strongly inclined to make the whole state diagram on one "row"... In other words, in this example, I wouldn't put the On eAns... stuff underneath the other, as I did in the diagram at the start of all of this. The reason I would write the whole diagram on "one line" is that under the various states I would make notes about the variables and control properties which would or could be changed while the program was in each state. For example, I'd mention that bQsDone will always be changed as the application passes through the "Eval Ans/ Give..." state, and that the iScore variable may be changed.

I would also, separately, maintain a list of the variables used in the program, or at least add rems to their declarations in the source code. (See the note beside iScore:integer;, for an example.)

Although there would be no point in this program, there are a few other things I do to remain in charge of code while I write it:

I try to avoid using global variables more than is actually necessary. Or if I do use them, I use them very carefully. They can often be avoided. I make an exception for things with "Tmp" in their name... e.g. bTmp, sTmp (byte and string variable, respectively, in the naming convention I use.) A variable which can be used to hold something just for a moment, temporarily, is so frequently useful, it is silly to create separate ones for each procedure or function. Watch out, though... you may start using a variable to hold something "temporarily", and then, as the code develops, accidentally rely on its value not changing when it does. Suppose for instance, you're doing....

bTmp:=b1;
b1:=b2;
b2:=bTmp;

Fine... and a common enough thing to do. But what happens if you want to modify the contents of b1 and b2 at the same time as you are swapping them... and you decide (quite wisely) to use a call to a function written by you....

bTmp:=bMyfuntion(b1);
b1:=bMyFuntion(b2);
b2:=bTmp;

That will work fine, too... unless bMyFuntion is something like....

function bMyfuntion(bIn:byte);
begin
bTmp:=bIn*20;
if bIn+15>bTmp then bTmp:=bIn;
result:=bTmp;
end;

If I AM using a global variable, and changing what it holds within a procedure, unless the fact of the change is blindingly obvious, I will probably mention the fact that the variable's value gets changed in rems at the start of the procedure. In the present program, if you wanted to do something like this, you might put....

//eUsersAnswer.text emptied out during the execution
//of this procedure if key pressed was the Enter key.

... at the start of the eUsersAnswerKeyPress procedure.

The other thing that I do arises if there data files involved in the application's execution. (Of course, our geography test application has a "data file"... but it is so utterly trivial, there'd be no point in the following). The other thing I do is to keep very clear notes as to what's in each data file, where it is, how the data is encoded, etc., etc.

I've always done those two things, tracked variables and been careful about my data files. However, until now, since moving to programming for Windows, my recording and analysis of the states of the application, and the routes between them has been done subconsciously. I've been more "artist" than "engineer" in my programming... and I don't think it is the way to go. Now that I have at last started to perceive the beginnings of a states/ state transition tool, I look forward to using it, and to getting bigger and better applications out the door with much less hassle.

It was long, long ago (1976) that Niklaus Wirth so helpfully titled his book "Algorithms + Data Structures = Programs". In our event driven world, perhaps we should say "Algorithms + Data Structures + State Diagrams = Event Driven Programs".

User name from CLP -

One last little detail; you can skip this if you wish...

Our original plan said that the name of the user could be specified either by the user, with the keyboard, at the start of the application's execution, or the name could come from a "CLP".

First of all: What is a CLP?

"CLP" stands for Command Line Parameter. It is some information the application will use which is supplied "tacked on" to what starts the application running in the first place. Ordinarily, in windows, we don't use a "command line". However, if (as is wise) you use shortcuts to start applications, there is a command line invocation buried beneath the user friendly surface of the Windows interface.

To use a CLP, first set up a shortcut to the application.

Once you've "caught your shortcut", right click on it and click on "Properties".

Add Fred Brown, in quote, to the end of the target, in other words, make it...

...DD77best.exe" "Fred Brown"

(Yes, you leave the " which was after .exe in the original shortcut target, AND you put quotes around the Fred Brown. The quotes around Fred Brown make windows ignore the space. Without them, windows would see two CLPs... "Fred" and "Brown".)

Now we are providing the application with a CLP. To get it to use it, change GetID to....

procedure TDD77bestF1.GetID;
begin
if paramcount=0 then begin //Does this if there is no CLP
sUserName:='FromHardCode';
//sUserName:=InputBox('GetID', 'User name?', '');
end //no ; here
else begin //Does this if there IS a CLP
sUserName:=paramStr(1);
end;
laUser.caption:='User''s name: '+sUserName;
end;

(paramcount and paramStr are words which are built into Delphi.)

(GetID is shown above in it's debugging- friendly "Don't ask for a name if there isn't one in the CLP" form. You ONLY need to take out the "//" in front of...

sUserName:=Input.... 

... to restore the program to it's "normal use" form. Of course, the preceding line (setting sUserName to FromHardCode) would then be pointless... but harmless.



Wikipedia has some good notes on State Diagrams, most of which are relevant to their use as I have suggested above.

The diagrams for this tutorial were done with Open Office's drawing module, using the "flowcharts" elements and some connectors. It is almost the first time I've used ooDraw... pretty user friendly if a new user can get such work done, I'd say! (I used Serif's PhotoPlus to crop and slightly massage the charts, and export them to .gifs after their creation in ooDraw.)

I wrote another essay with an emphasis on states. That is published as a .pdf. It doesn't go into state diagrams as a planning tool, but does look at how an application may be understood by thinking about states. While it has some specifics about a burglar alarm and some 1-Wire sensors and actuators, if you skim some sections, but study others, as you've read this essay down to here, I think it is safe to say that there is Good Stuff For You in the other essay.



I hope that has been interesting and seems as if it may be useful to you. The best thanks you could give would be to visit my freeware and shareware pages from the link below!



            powered by FreeFind
  Site search Web search
Site Map    What's New    Search This search merely looks for the words you enter. It won't answer "Where can I download InpOut32?"


Click here if you're feeling kind! (Promotes my site via "Top100Borland")
Ad from page's editor: Yes.. I do enjoy compiling these things for you. I hope they are helpful. However... this doesn't pay my bills!!! Sheepdog Software (tm) is supposed to help do that, so if you found this stuff useful, (and you run a Windows or MS-DOS PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!
Click here to visit editor's freeware, shareware page.

Link to Tutorials main page
How to email or write this page's editor, Tom Boyd


Valid HTML 4.01 Transitional Page 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 .....