Anda di halaman 1dari 338

Delphi and Pascal Programming Tutorials Table of Contents

HOME - - - - - - - - - - - - Other material for programmers

Delphi and Pascal Programming


Tutorials
This site offers write-ups of how to do specific things in Delphi or Pascal. Feel free to use them in
programming courses, but a credit of the source would be appreciated. Speaking of which... the following
was a great help to my own programming: 'Borland Delphi How-To', from the Waite Group, by Frerking,
Wallace and Niddery, ISBN 1-57169-019-0. Its approach suited my needs, and helped inspire the form of
these tutorials: Most are a self-contained explanations of how to accomplish a specific task, or use a
particular component of the language.
There are more notes at the bottom of the page about other offerings, my editorial philosophy, a button to
email me, and a search engine to help you find things in my site.
The 'How To...' items at the bottom of the menus for some levels will take you to information on specific
little odds and ends.

Table of Contents, Delphi and Pascal Tutorials:


Delphi.....
Level Zero:
If you are not only new to Delphi, but also new to programming, you might want to study Pascal a little
first! There is a free product which you could use for that. What you learn with it will all contribute to
getting going easily with Delphi. Working with Pascal first lets you master one group of issues (which
will matter in Delphi programming, too) before you contend with them AND some issues that are
involved with any Windows language.

Click here for my Pascal course.

Level 1 Tutorials:
(At the moment, there is also some Level 1 stuff in the Level 2 tutorial called 'Adding things to a unit')
Start Here This takes a complete beginner through a first project, covers points that apply to any project,
and covers some points about conventions used in the other tutorials.
The Whole Picture An overview of the parts of any Delphi project. This is more 'philosophical', less 'how
to', than most of my tutorials.
Making it work: Tips and advice on debugging. Also more 'philosophical', less 'how to', than most of my
tutorials. (See also the Pascal debugging information in the Pascal section below.)
Level 2 Tutorials:

http://sheepdogguides.com/tut.htm (1 of 9) [1/28/2005 3:43:39 PM]


Delphi and Pascal Programming Tutorials Table of Contents

Level 2 Tutorials:
How to..... Make a 'beep' or other noise.
How to..... Blank the monitor by turning it off.

Keeping the customer satisfied... How your program can determine your user's wishes (Pt.1. See also Pt
2, in level 3). THIS TUTORIAL COMES "RECOMMENED": check it out, please, even if determining
user's wishes wasn't the main thing you were looking for?

Menu, "About" page and Quit option in menu... How to add them to a project.
File Handling... How to read data from files on disc, and write to such files. (A long tutorial)
Re-using a project... A short guide to building a new project from an earlier, similar, one.
Adding Things To A Unit... Where put things. Things that matter. Matters of scope.
This tutorial is full of Good Stuff... but very untidy, badly organized at the moment. I will try to sort it
out, but for now: You have been warned!
Syntax Notation... how to read important stuff.
You will learn more from the Borland "Help" files once you master the information in this tutorial.
Command Line Parameters....... PLEASE have a look at this... it is quite short. You will be shown a way
to achieve some of the benefits of .ini files and the registry... without presuming to write things onto your
customer's systems.
Using the TTimer component....... This not only gets you started with using an important component, but
it may also help you refine your aptitude for working in the event driven environment of Windows.
An example- Reading Skill Exerciser....... This comes with complete sourcecode for you to peruse. It
illustrates using the OnChange event of an edit box to respond to user input. It also uses a timer to
display a list of words on the screen for a time-limited reading opportunity. The use of simple Try...
Except blocks is also shown, in the handling of an EConvertError exception.
Principles of programming, and Scrollbars, GetTickCount, etc...... This also comes with complete
sourcecode for you to peruse. It shows ScrollBars in action, but it also "digresses" to cover a number of
general points like nesting procedure (or function) declarations, using TabOrder, and setting up enables.
The useful GetTickCount gets a mention, too.
Use the events, Luke....This tutorial started as an introduction to string grids, and it does introduce them.
However, while I was working on it, I "discovered" more than I'd known about using an event driven
operating system. The tutorial also illustrates well good incremental development. Recommended to
everyone, not just those looking for help with string grids. Not terribly long. It also leads on to an even
more important Level 3 tutorial.

Level 3 Tutorials:
Quite a few of the things assigned to this level are not complex, but they were put here anyway as
they were not essential to Delphi programming in general. Some others are also pretty simple, but
come without much supporting tutorial material.

Keeping the customer satisfied... How your program can determine your user's wishes (Pt.2. See also Pt
1, in level 2).

http://sheepdogguides.com/tut.htm (2 of 9) [1/28/2005 3:43:39 PM]


Delphi and Pascal Programming Tutorials Table of Contents

Creating an array of Edit Boxes... the tricks explained here would work with other components, too.
Introduction to Graphics... MoveTo(100,10);DrawTo(300,300); seems simple enough... but it isn't
enough to make a line which will still be there after you minimize then restore the window. This tells you
how to create persistent graphics, and talks briefly of loading bitmaps.
Creating something to be used by many programs... This is a long tutorial covering many points in the
course of creating a High Score Table. It does not take you all the way to registering a component so that
it becomes part of the Delphi Component Palette. It does show you how to create something which can
be used to speed up the development of a number of programs which share a common element.
A start on a typing tutor game... Unfinished at present. Illustrates development of an application.
How to access database files... It is remarkably easy to write a program in Delphi which allows you to
view and edit files shared with Paradox, dBase, Access, etc. Learn how here!
Playing .WAV files with MediaPlayer... Whether you want your program to SAY "You have new
mail...", or just need a superior "Zapp!", here's how. And what you learn here probably works for playing
other media, too.
Reading the joystick... doing it in Delphi 2 and above. Revised and expanded May 04. A stopwatch
program is created as an illustration. See also the level 4 joystick tutorial. Sourcecode supplied.
Help Files... making the link between them and your program. (A short tutorial)
A control program dissected... A program with checkboxes and boolean variables working together is
analyzed. Downloadable sourcecode supplied.
Images and File Access... Display .bmp images on your form. Access all the files in a given folder on
your disc, using that as the basis for a "Can you recognize..." exercise. Tutorial has rough edges, but full
source listing of working program given.
Using DLLs. Also: Accessing Port Hardware... this tutorial shows you how to call functions hidden
inside a .DLL, and tells you about a freeware DLL for sending messages to and from electronics of your
own devising attached to your PC via the parallel port.
Printing- a line at a time... this tutorial shows you how to send text to a printer a line at a time. There are
no complex concepts, but the need isn't universal, and the help is minimal.
A Word Search Program... You won't need the program, but maybe some of the techniques used to
complete it will be of interest! Sourcecode and .exe provided. Little hand-holding regarding how to make
Delphi work, just comments on and in the finished product.
Pick a cell, any cell.Ostensibly, this tutorial is about using code to select a cell of a string grid at run
time. Along the way, some more generally important material arises concerning using references to
Delphi created objects, e.g. the object in "sender" arising from Delphi created event handlers.

To write a screensaver:A screensaver is not very different from any other Windows application. Mark
R Johnson has prepared an excellent discussion in the same style as my tutorials, and I see no reason to
re-invent that wheel. (He's even made the source code available.) I've put this in Level Three because of
some tedious odds and ends that you must address. What you have your screensaver do can be very
simple. (I found Mark's helpful guide through Heiko Webers' extensive links collection.)

A favor, please? If you know of a good Windows screensaver which satisfies the following, please let
me know? (I only need the .exe, not the source code.)

http://sheepdogguides.com/tut.htm (3 of 9) [1/28/2005 3:43:39 PM]


Delphi and Pascal Programming Tutorials Table of Contents

Shareware, registration less than $20.


Displays rotating cube.
Pictures on face of cube user-defined... hopefully by
some VERY SIMPLE means. Best of all: Screensaver just
uses the six images in a known location. In my perfect
world, changing the contents of one of the files would
change the image on the cube. I don't mind being
restricted to fixed image file names.
Editor's email address. Suggestions welcomed!
My thanks to the kind reader who pointed me to Xara's rotating cube screensaver. It has been running on
my machine for a few months now with no problems. It even meets my "Change display by changing file
contents" requirement, I think. It shades the faces as they turn... an essential "frill" to achieve best effect,
I believe. Info and program at Xara's site.

Level 4 Tutorials:

Customizing a standard control... Complete the Level 3 tutorial 'Creating an array of Edit Boxes' before
attempting this one.
File Modification... Not complex, but presented assuming some fluency on part of pupil. Replaces a file
with a modified version of itself. Backs up original file.
A worked example... A program for decoding simple substitution codes. This builds on the previous
tutorial.
Navigating backing store... Re-creates parts of the Windows Explorer. Also illustrates multiple windows.
Uses filelistbox, directorylistbox and drivecombobox.
Color Graphics. Dynamic resizing... How to draw in the color of your choice. How to make things on
your form change size if the window's size is changed.
HTML generator... the beginnings of a program to generate online photo albums.
Angle display... a small circle with an arrow in it. The arrow can point any one of 16 directions.
Originally developed to show the direction a wind vane was pointing. No "crucial" skills in this tutorial...
but it is a good one, with some nice bits of elegance in the coding. Some intermediate event handler
techniques illustrated. It also illustrates a use of the tag property.
Another worked example... This is bigger and moves along faster than some of my tutorials. It shows
how I extracted data for a given day from a bunch of files, each holding records for many days.
Windows messages, joysticks and a stopwatch... This covers several topics, including responding to
messages generated elsewhere within the computer, messages from a Windows API. There's a simpler
way to read joysticks explained in a Level 3 tutorial. It comes with sourcecode.

Level 5 Tutorials:

The stuff relating to using Dallas Semiconductor MicroLan, also known as 1-Wire, chips has been
moved to here.

Sit at my elbow... while I write a program that is bigger than a typical Tutorial program. Sourcecode

http://sheepdogguides.com/tut.htm (4 of 9) [1/28/2005 3:43:39 PM]


Delphi and Pascal Programming Tutorials Table of Contents

available for download. Illustrates the development sequence. Illustrates some file handling and graphics
programming.
RS-232 comms (serial i/o)... A start on a home brew simple Hyperterminal. (Delphi 2)

Pascal .......

(If you are interested in links to others' work, bookmark this page so you can get back to it, and visit my
page with links. Of course, almost everything that anyone ever wanted to know is already on the web in
Prof. Salmi's superb FAQs. Download his zipped FAQ (also available here ), unzip it, look in
TSFAQP.IDX for the FAQ's table of contents. Don't know how to unzip? Time to learn! Alternatively,
use newsgroups, via Google's Groups to obtain an answer to your question.)

Pascal Tutorials:

Pascal for those who know Basic... Some notes from me for those who know Basic, and who haven't
done much Pascal.
Making it work... Help with debugging.. and on preventing the need for it.. Also useful to Delphi
programmers.

Editorial Philosophy
I dislike 'fancy' websites with more concern for a flashy appearance than for good content. For a pretty
picture, I can go to an art gallery. Of course, an attractive site WITH content deserves praise... as long as
that pretty face doesn't cost download time. In any case....
I am trying to present this material in a format which makes it easy for you to USE it. There are two
aspects to that: The way it is split up, and the way it is posted.

The way it is split up...


I have tried to split it up into 'bite-sized' pieces, and to indicate which pieces are basic and of general
importance, and which address more specific issues which also happen to be complex, or require
understanding of more fundamental issues. In other words, I try to show you how to walk before
worrying about running. The 'Level 1' tutorials cover the basics. If you have no experience, start with the
level one tutorials. If you decide to jump in at a more advanced level, and things are not clear, it might be
an idea to skim the level one topics if only to learn about my way of expressing the concepts. See also,
below, the 'difference' between Delphi and Pascal.

http://sheepdogguides.com/tut.htm (5 of 9) [1/28/2005 3:43:39 PM]


Delphi and Pascal Programming Tutorials Table of Contents

The way it is posted...


This archive of tutorials stretches back some way towards the dawn of the internet. Now, most of us have
HTML capable wordprocessors, and newer tutorials make more use of HTML code than older ones. Is
this a problem? You could save the pages from a browser, and re-load them to the browser from your
hard-disc later, off-line. OpenOffice (the excellent, FREE, office suite for Windows AND Linux from
www.openoffice.org) takes HTML in its stride. With WordPerfect, you can load the .htm file, select all,
copy to clipboard, start a new WordPerfect document, then paste in the text, mostly intact and cleansed
of HTML.
You should be able to read the tutorials on-line without difficulty. However, you should ALSO find it
easy to capture them for off line use, including editing for your own purposes. The following should
work. I would suggest that you create a folder for the tutorials so that you can retain my filenames with
no risk of clashes:
On-line, use your browser to view the tutorial you want to capture.
Use the browser's File|Save As... to save the web-page to your disc. At this point you can log off, or visit
other pages, perhaps saving them, too.
When you have logged off, just use your browser's File ! Load command to view the material. If you
want to edit the files, try using your usual wordprocessor. Failing that, start Notepad (or Wordpad, or
anything you like, but then you're on your own <g>). Load the file you saved. Turn word-wrap on.
(Notepad: Edit|Word-wrap.)
Snip off the html header and footer. Re-save the document, changing the extension to .txt or .doc
Depending on the tutorial, there will be more or less HTML code within the body of the text. With luck,
your wordprocessor will cope with this. Give OpenOffice a try if not! Otherwise you can use global
search and replaces to remove most of the tags fairly quickly.
________
This would seem to be the place for a plug for Textpad. It is much more than Notepad, while not being
all that a "wordprocessor" is... but it DOES have features that you will soon come to love, if you do much
work with text files.... especially programming or HTML coding. All of my web pages are created with
it, and much of the other text work I do is done with it, too. It has a spell check. It has syntax
highlighting. I turn to my wordprocessors (Ami Pro, for legacy work, and OpenOffice Writer for new
work) only when I want to produce a letter- formatting and font options are not extensively supported in
TextPad. However, it does have many, many, very neat touches which make it a joy to use for many
things. I particularly like their answer to "autotext", and the fact that the user can configure how it
displays different classes of documents. Here is a link to their site. Shareware: YOu can try it for free,
and it is not expensive to register for continued use.
________
Filenames: I've tried to be organized: Names start Pt or Dt for Pascal/ Delphi Tutorial. Next is a digit, for
the level, then I've used letters one after the other, e.g. Dt1a, Dt1b, Dt1c. The letter doesn't mean much...
it just shows when I got around to that particular topic! DST files are some of those relating to the Dallas
MicroLan.

http://sheepdogguides.com/tut.htm (6 of 9) [1/28/2005 3:43:39 PM]


Delphi and Pascal Programming Tutorials Table of Contents

The difference between Delphi and Pascal


Delphi is based on Pascal. It is for writing programs for Windows, using Pascal.. with a lot of
enhancements from those wonderful people at Borland. If you are very new to programming, you might
make progress faster if you start with a non-Windows Pascal... there are free ones around, details of one
can be found in my free Pascal tutorials, which I would commend to Delphi users with little experience
with Pascal.
In the Delphi tutorials here, you should find all you need for Delphi programming. However, even if you
never intend to program for anything other than Windows, if you are new to programming, looking at
some of the low level Pascal tutorials might help you to grasp important ideas for your Delphi work.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


The search engine is not intelligent. It merely seeks the words you specify. It will not do anything
sensible with "What does the 'could not compile' error mean?" It will just return references to pages with
"what", "does", "could", "not".... etc.
In addition to the tutorials for which this page serves as Table of Contents, I have other sites with
material you might find useful.....

Some pages for programmers.


Using the parallel port with programs written in Delphi.

And now for some links to other peoples' pages you may find useful, in no particular
order. They will open in a new window.

The links were tested at 25 Jan 04, re-tested 3 October 04 and working except as noted. (The numbers in
brackets indicate the site was in the list and tested on these dates. "LS" Means the site was already known
as Long Standing back on 1/04. WBM mm/yy indicates that the page was known to the Wayback
Machine at mm/yy.)
Please don't ask for a link to your own site unless a) it already has a link to this site, and b) the Wayback
Machine will show me that your site has been up for more than two years.

Borland The home of the people who provide us with Delphi. (LS, 1/04, 10/04)
Delphi Resource Center (LS, 1/04, 10/04)
Delphi Central (10/04)
Delphi Land- Online Delphi tutorials for beginners, tips, source code. (LS, 1/04, 10/04)

http://sheepdogguides.com/tut.htm (7 of 9) [1/28/2005 3:43:39 PM]


Delphi and Pascal Programming Tutorials Table of Contents

Frank's Delphi Lessons (LS, 1/04, 10/04)


Marco Cantu's Essential Pascal tutorial... read online, or download text. (LS, 1/04, 10/04)
Delphi Super Page.... an archive of material, some with sourcecode. (LS, 1/04, 10/04)
Swiss Delphi Center In English, German, and French. Programming tips, Downloads, Links, Etc. (LS,
1/04, 10/04)
Delphi Apostle- Matlus Site with straightforward tutorials dealing mostly with building using Delphi 6
Enterprise. Includes tutorials on Webservices, ISAPI, TCP/IP work, and more! (LS, 1/04, 10/04)
Merlin's Delphi Forge: Delphi/Kylix portal with FAQ answers, downloads, links, forums. (LS, 1/04,
10/04)
Programmer's heaven: vast resource of ... I think you can guess! (LS, 1/04, 10/04)
MAS Delphi page: Delphi-components, applications, tools, code examples, links. All freeware, I'm told!
(LS, 1/04, 10/04)
Unofficial Newsletter of Delphi Users (WBM 11/98, 10/04)

=====
I had a link to a Delphi page within the Lycos site. The link was bad when I checked it at 1/04, but of
course you should look in the various directories- Lycos, Yahoo, etc.
Yahoo home
Lycos home

Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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 Sheepdog Software (tm) freeware, shareware pages.

And if you liked that, or want different things, here are some more pages from the editor of these
tutorials....
Click here to visit the homepage of my biggest site.

Click here to visit the homepage of Sheepdogsoftware.co.uk. Apologies if the "?FrmTut" I added to that
link cause your browser problems. Please let me know, if so?
Click here to visit editor's pages about using computers in Sensing and Control, e.g. weather logging.

Link to editor's oldest homepage.

http://sheepdogguides.com/tut.htm (8 of 9) [1/28/2005 3:43:39 PM]


Delphi and Pascal Programming Tutorials Table of Contents

To email this page's editor, Tom Boyd....


Editor's email address. Suggestions welcomed!

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.
....... P a g e . . . E n d s .....

http://sheepdogguides.com/tut.htm (9 of 9) [1/28/2005 3:43:39 PM]


Contents: Sheepdog's Other Kennel

Contents: Sheepdog's Other Kennel

Freeware, Shareware, from this site's editor. (IBM-type PCs)


...... New products ->-> Arithmetic Word Problems, for Windows environment, and
..........Matching Pairs game, and
............. 'Right One': A Windows quiz program.
Tutorials for Delphi programmers, and about Pascal. Introductory material and more.
A page for genealogists. (Includes my hunt for Boyd, Glover and Lunham relations.)
Ideas, Info, Links for MS-DOS / Windows Programmers... especially Delphi & Pascal
Electronics for schools or hobbyists
Helpful Hints.. mostly for new users of pcs, Windows, the internet

.... AND THAT's NOT ALL.... see below...

New stuff!...................................
Your entry point for my pages about hardware and software aspects of working with the Dallas Microlan,
ala 1-Wire, e.g. the iButton devices.
Advertising for my Delphi (and Kylix) tutorials Also links for Delphi and Kylix programmers.
Software I like: Advertising for TextPad, Cancer Cure distributed processing project, other useful
Windows freeware, shareware and recommended software.

Other goodies...................................
Do it yourself map making: Fun for individuals. Useful exercises for schools.
Ideas for programming class or club assignments, competitions- with (free) supporting software!
Numbers you can use to build a good solar system model, for teachers or community leaders.
Information on silhouette art, and opportunity to commission your own.
Some books I recommend.... investing, electronics, fiction, etc!
What Sheepdog Software has to offer you... and other good stuff!
'Good Cause' promotions... Misc. worthy causes you might like to know about.
Information for people near Chichester, Sussex, England.
Links, etc, for stock market investors (US and UK)
Complaints naming (and shaming?) people, organisations.
Odds and ends awaiting incorporation into "proper" place.

http://www.arunet.co.uk/tkboyd/index2.htm (1 of 3) [1/28/2005 3:43:44 PM]


Contents: Sheepdog's Other Kennel

Search this site powered by FreeFind

Find! Site Map

Site Map What's New Search

Click here to find out how I added the search engine to my site. It was easy and free, and gives an
indication of traffic, and what people are looking for. Please note that it cannot answer questions like
"Where can I find dahlias?". It merely looks to see if the words you enter appear on any page in this site,
so "dahlias" might be worth trying, if that's what you're after.

This site is called the Sheepdog's Other Kennel because it came after my first website, which still has
material you won't find here. N.B. The search engine on this page will not search the first website. The
site you are looking at now is my 'main' site. There is some overlap.
Go to Sheepdog's First Kennel... more stuff from same editor

(A bit dated, but worth celebrating...) Safe for now,


hurrah!
Forgive me leaving this here, ven though now dated. It is still great news!

For 78 years, in England there has been a remarkable school exploring fascinating alternatives to
traditional education. Our wonderful 'We Know Best' and 'Everyone Must Do Things Our Way' (parent's
wishes be d***ed... despite explicit laws granting parents rights) government was, in effect, trying to
stamp this remarkable institution out of existence. They seemed intent on either changing it out of
recognition, or closing it. Now- if they were using their expertise to alert the parents to 'terrible' things
going on at the school, and letting parents decide to stop paying the fees, I wouldn't mind. But that's not
the story. If it was a school funded out of the public's pocket, then it ought to be answerable to someone.
If the school was one of the many unknown, second rate, dumps which ought to be exposed and wither, I
wouldn't mind. But this isn't. This is a school that I had to study as part of my teacher training 25 years
ago... and parents are still paying to send their kids there... but they won't have that option much longer if
something isn't done to tell the politicians to pXss oXX.

PLEASE VISIT....
Summerhill School website to learn more, or
Centre for Self Managed Learning, where you can read an independent report on the school and the
inspection issues.
(Remember to come back here afterwards, please?!)

http://www.arunet.co.uk/tkboyd/index2.htm (2 of 3) [1/28/2005 3:43:44 PM]


Contents: Sheepdog's Other Kennel

(Also dated, but still true...) Danger!


If you have not heard all about the CIH, or Chernobyl, virus, PLEASE read....
Danger to your computer from a well distributed type of virus. Losing your data is bad enough. Did you
know that some viruses can trash some motherboards beyond repair?
I know, virus warnings are about as boring as Y2K... but THIS ONE IS DIFFERENT! Suspect (as you
should!) a trap or hoax? Use Google, ask for +symantec +chernobyl and read what you get.

I was a teacher for 20 years. Much of the material here is for kids, parents, teachers. (Especially for the 8
to 13 year old range.) However, I've done more than teach. You will find things for other audiences, too:
investors in Wall Street or the City, birdwatchers, etc, etc!
Here is how you can contact this page's editor.

Why does this site access an image you can't see? I have my web-traffic monitored for me by
eXTReMe tracker. They offer a free tracker. If you want to try it, check out their site

--------- sheepboyd page ends -------

http://www.arunet.co.uk/tkboyd/index2.htm (3 of 3) [1/28/2005 3:43:44 PM]


Ideas, Info, Links for Programmers

HOME

Ideas, Info, Links About Programming


This page is a mildly groomed collection of things I've found useful as a programmer. If you are not
interested in programming, read no further! If you are, I hope things here will interest you and be helpful.
Back to main page, for non-programmers

(Very little of what follows will be of interest to Mac programmers.)

Ad from our sponsor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However..
this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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.

Table of contents for this page:

Programming for Windows: General Points


Shareware Authors: Ideas for you
Free: Operating Systems, Compilers, Interpreters
Pascal Programming
Delphi Programming: THE way to go!! (Editorial bias? Moi?)
Object Oriented: General Issues
Class or Club: Fun (I hope) ideas to challenge classes or clubs
Miscellaneous: You guessed it: I couldn't make up my mind

Search this site powered by FreeFind

Find! Site Map

Site Map What's New Search

Programming for Windows... general points...


Click here if you want information on creating help files.

http://www.arunet.co.uk/tkboyd/prgmr1.htm (1 of 9) [1/28/2005 3:43:48 PM]


Ideas, Info, Links for Programmers

For shareware authors...


WinZip from www.winzip.com will create self extracting files, or... there's

Some versions of Delphi come with a version of InstallShield. Give it a try... quite comprehensive and idiot
proof, if you have it! or, there's...

.... another alternative: I (TKB) haven't tested this one myself; what you see are edited comments from
someone who emailed me.

From Gentee Software...

Download size is 150K. Produces SFX's, (self extracting archives), with competitive compression, handles
multi-volume disk installs, is designed so that you can integrate it into a batch file for automating a mail-out
registration process, straightforward (doesn't require you to learn a scripting language), and it only costs $38.
(Does not provide any support for the BDE.)

Click here to visit Gentee Software's site. Let me know what you think... as I said: I haven't tried this myself.

If you want to 'package' Windows 3.x programs for delivery to customers in a self installing file, I can
recommend Kurt Herzog's Install/Setup. Trouble is... I can no longer find it on the net! It handled my needs
very well, behaved well on my system. Since I did my testing, he has improved it to install into Win 95
environments, too. Let me know if you find it?

Free or shareware OS, Pascal, etc compilers...


(See the entry in the next section about Pascalite for a very simple compiler and simulator for use in
microcontrollers)

Want DR-DOS, with personal netware? (Like MS-DOS + Novell) Want other NON-MS stuff, reasonable
prices, free or as shareware? How about giving Pascal (the underpinning of Delphi) a try.. for free?!
Alternatively, why not try your hand at something new, say Logo.
Click here for details of these opportunities, and others. (Sick of Bill Gates running everything?)

=========
One sometimes sees requests in newsgroups for online sources for the Delphi or Turbo Pascal
compiler/IDEs. For those who don't realize: These are both commercial, copyright products. As you can see
from the above, there are a number of free or inexpensive ways to program in Pascal for DOS. I don't know
of any free Pascals for making Windows programs. In any case, I was highly amused by the way one person
responded to a 'Where can I download..?' enquiry:

"You must go to the computer store and download the product manually from their shelf. In addition, before
you can store your downloaded box, you must first upload cash from your wallet to the cashier."

STOP PRESS!!Now you CAN obtain Turbo Pascal for free... from Borland, so it would seem legal. Click
here for details

http://www.arunet.co.uk/tkboyd/prgmr1.htm (2 of 9) [1/28/2005 3:43:48 PM]


Ideas, Info, Links for Programmers

(The gem above the "stop press" was by Lauren, click here for his homepage, which features his CD Player
which can display lyrics as your CD is being played. Lyric Files can be downloaded from this site and
copied to your Lyrics folder, so fans of a particular band can share files.)

Pascal programming.... see below for Delphi specific items, but there
may be overlap
I've come across a really cool product called "Pascalite". You can download (free, and only about 500kb) an
editor/ compiler/ simulator package. If you like that, you can buy a microcontroller which is programmed
with the software you already have. Click here to hear more from me about this, and a similar, BASIC based,
device.

Before you have looked very far on the internet for help with Pascal, you should encounter Timo Salmi. Try
Groups Google, or example. He has, for a long time, been indefatigable in helping everyone. If there's
something you need to know which isn't in his Common Turbo Pascal Questions FAQ, I would be surprised!
I make no apology for making reference to his resources in several places here.

===
J.R. Stockton's Delphi page

===
Click here for 'Pascal Central' for Pascal technical information, Pascal source code, and Pascal-related
internet links. Many references to Macs, but general stuff, too.

=== Click here for Programmer's Heaven, a collection of source code, advice, tutorials, and program
examples, in Pascal, Delphi, and many other languages.

=== Click here for SWAG, a collection of source code and program examples.

===
Turbo Pascal stuff.... Start at www.xs4all.nl/~remcodek

===
Pascal 'How to', etc from John Stockton

Click here... (and try his other P*.htm pages, e.g.


Pascal Language Tutorial

===
Some links, etc for Pascal programmers

For 5.7k (12-98) zipped file, with help on using mouse for in a Pascal program, see

http://www.arunet.co.uk/tkboyd/prgmr1.htm (3 of 9) [1/28/2005 3:43:48 PM]


Ideas, Info, Links for Programmers

Click here
and there's material in Timo Salmi's faq,
Common Turbo Pascal Questions and Timo's answers (149k (12-98) zip ftp)
...including help with reading where the mouse was (x, y) when the mouse was clicked.

===
There is a general problem with the Borland Turbo Pascal 'DELAY' procedure. It won't work properly on
fast PCs. Fixing this is easy, see Timo Salmi's FAQPAS3.TXT,

67) If Delay procedure does not work properly, how do I fix it?

You get the FAQ as part of ftp://garbo.uwasa.fi/pc/ts/tsfaqp41.zip

In a nutshell... What you need is harder to explain than to do...

1) Get some freeware. (Timo's FAQ probably says what, where)


2) Put a 'unit' in the right place in your system.
3) Include
USES ();
near the start of your program.
4) Replace DELAYs with something else. I use WAIT. I.e. where
my program used to have DELAY(50), I now have WAIT(50); and
it works the way DELAY(50) was SUPPOSED to.
===
More Pascal links and sources for beginners: Click here

===
Beginner's tutorial and other material:

320779 Oct 19 1992 ftp://garbo.uwasa.fi/pc/turbopas/tpr-book.zip


tpr-book.zip Electronic Turbo Pascal Reference freeware book, E.Mitchell

Not outright in the form of exercises, but with a lot of source


code, tips and explanations.
===
Using Soundblaster in Turbo Pascal:

Documentation called sblast09.zip offered by Carl Codere, who does Pascal and asm programming, from his
homepage at
Click here

or from the ftp site


x2ftp.oulu.fi
Said to contain documentation, and some example code.
___
Also...

http://www.arunet.co.uk/tkboyd/prgmr1.htm (4 of 9) [1/28/2005 3:43:48 PM]


Ideas, Info, Links for Programmers

Try soundlib from


Click here
(source code and 6 demos)
___
OR...
smix,
Click here
(If that doesn't work, go to Click here and search for smix in the dos section.)
=====
Remember the searchable archives of articles posted to newsgroups, e.g., comp.lang.pascal.delphi.announce,
available from those wonderful people at groups.google.com. If you re not familiar with newsgroups, I have
written about them at my newsgroups page.

Delphi programming.... see above for general Pascal items, but there
may be overlap. Feedback from you on which of these are most useful
would be welcome!

I've started a set of Delphi tutorials with one which should take a beginner through a first programming
session, and a second covering the basics of menu creation.... and BEYOND... My tutorials

===
Delphi tutorials

===
www.delphifaq.net/Merlin's Delphi Forge: Delphi/Kylix page with FAQ answers, news, downloads, links,
forums and more.

===
Click here for Delphi information

===
Delphi tutorials, links, chat room, etc Click here

===
Dolphi for Delphi
___
Click here for different URL which seems to end up in the same place? Weird?

===
KStringGrid component editor and several other freeware Delphi components were added on Korzh
homepage of freeware and shareware programming tools, at
Click here

http://www.arunet.co.uk/tkboyd/prgmr1.htm (5 of 9) [1/28/2005 3:43:48 PM]


Ideas, Info, Links for Programmers

===
Big link list for Delphi programmers from www.geocities.com/~franzglaser/

===
Delphi Super Page has various useful things, including "Tftw", a file tree walk component. Encapsulates
'Findfirst ... Findnext' and passes all files that correspond to your search pattern to your "onvisitfile" event
function.

===
Click here for yet more Delphi stuff... perhaps better.

===
Gauges, dials, etc components from Abaecker. Some free demos.

===
Bunch of good Delphi links... Curt's Delphi Pages

Object Oriented programming....


===
Click here for cetus/software

===
Click here for prestwood.com

Ideas for programming class assignments, club competition....


Click here for another page from the author of this site with two ideas you might have fun with. At the page
this leads to, you'll also find two free programs, one with source code.

Miscellaneous programming....
For years, I've used Notepad very extensively... these web pages were put together with it, for a start. I'm not
clever enough to stay on top of all the good things some programs offer. I just like the simple life.

Nonetheless!

I've become a delighted user of TextPad, which is sort of a super Notepad. It is still simple... but has a
sensible wealth of good features...

Spellcheck
Syntax highlighting... user configurable, but html and pascal (Delphi) syntax rule files were already there,

http://www.arunet.co.uk/tkboyd/prgmr1.htm (6 of 9) [1/28/2005 3:43:48 PM]


Ideas, Info, Links for Programmers

the ones I wanted. There are also rule files for C and many other things.
Easy management of multiple files I'm working concurrently on 15 web pages at the moment.
A clipboard for multiple frequently needed things, with subtle features. For instance, I put in the tags for
underlining that simply by highlighting it and double clicking on the "underline" item in the clipboard
resources list. Clever! But simple to use! The clipboard resources are user configurable
Shareware, and registering is not expensive. ($25, I think it was... worth it for the spellcheck alone!)

Here is a link to www.textpad.com.

===
Wotsit's Format: Quoting from the site: "The complete programmer's resource on the net. This site contains
file format information on hundreds of different file types and all sorts of other useful programming
information; algorithms, source code, specifications, etc."

===
More ideas, etc for programmers, www.midnightbeach.com... Click here

===
www.inquiry.com, a site for programmers.

===
www.experts-exchange.com for lots of good stuff for programmers. (tkb's opinion)

===
www.efg2.com: Lots of good specific, technical stuff for programmers, esp. in.... Image processing, Color,
Graphics, Mathematics, Fractals, Science & Engineering.

And lastly....

There is material on microcontrollers, including their programming, on my electronics pages, click here for
them.
This isn't really the best place for this... but it is the place I can do today! I want to bring to your attention a
resource on the web... sort of a search engine, I suppose. In their (snipped) words:

As a collaborative filtering site, PHOAKS exists to help us all help each other find appropriate and relevant
web resources.

Here's how it works. People post their opinions of web resources in Usenet Netnews (you can too). Around
the clock, PHOAKS reads, classifies, abstracts and tallies those opinions automatically. PHOAKS' pages
here reflect the results.

Once you enter PHOAKS, you can use keyword search or a hierarchical index to find your way around. For
each thematic newsgroup, check out the most frequent, most recent, or top contributor's web resources. You

http://www.arunet.co.uk/tkboyd/prgmr1.htm (7 of 9) [1/28/2005 3:43:48 PM]


Ideas, Info, Links for Programmers

can view snippets of the source opinions and related FAQs.

PHOAKS filters out most spurious and signature references. PHOAKS does not read .announce, .answers,
.jobs, or .binaries groups since these specialized types of groups are not sources of opinions.

And... hurrah!! They offer a 'Lo-Fi' option: No tables, no graphics. (And a hi-fi option for those who don't
have to pay for their own phone bill.)

Click here to visit PHOAKS.!

A little bit of humor for you. I've cut a few that I didn't find as funny as the rest. If everyone did this, the
jokes we see circulating would get better and better, wouldn't they?!

TOP 12 THINGS LIKELY TO BE OVERHEARD IF YOU HAD A KLINGON PROGRAMMER:

12. "Specifications are for the weak and timid!"

10. "You cannot really appreciate Dilbert unless you've read it in the original Klingon."

9. "Indentation?! -- I will show you how to indent when I indent your skull!"

8. "What is this talk of 'release'? Klingons do not make software 'releases.' Our software 'escapes' leaving a
maimed trail of designers and quality assurance people in its wake."

7. "Klingon function calls do not have 'parameters' -- they have 'arguments' -- and they ALWAYS WIN
THEM."

6. "Debugging? Klingons do not debug. Our software does not coddle the weak."

5. "I have challenged the entire quality assurance team to a Bat-Leth contest. They will not concern us
again."

4. "A TRUE Klingon Warrior does not comment his code!"

1. "Our users will know fear and cower before our software. Ship it! Ship it and let them flee like the dogs
they are!"

*****

(The Klingon jokes were from a post by Tim Pierce, twp@rootsweb.com, previously published by
RootsWeb Genealogical Data Cooperative, RootsWeb Review: RootsWeb's Genealogy News, Vol. 2, No.
25, 23 June 1999. RootsWeb: http://www.rootsweb.com/)

This page is fairly new. What has appeared so far is the result of which notes to myself I
could find in an untidy office. Material will be added (and what is here will be tidied up!!) as
time permits... feedback on what is here so far could influence the page's direction!

http://www.arunet.co.uk/tkboyd/prgmr1.htm (8 of 9) [1/28/2005 3:43:48 PM]


Ideas, Info, Links for Programmers

Back to main page.

I also have a set of pages where I accumulate bits and pieces prior to incorporating them into pages like this.
Click here to visit the index for those pages.
Here is how you can contact this page's editor.
Why is there a hidden graphic on this page? I have my web-traffic monitored for me by eXTReMe tracker.
They offer a free tracker. If you want to try one, check out their site. Neither my webpages nor my programs
incorporate spyware.

http://www.arunet.co.uk/tkboyd/prgmr1.htm (9 of 9) [1/28/2005 3:43:48 PM]


Pascalite Programming Tutorials

HOME

Pascal Programming Tutorials


(With examples tailored to the free package "Pascalite")
This site offers write-ups of how to do specific things in Pascal. You don't need to pay for a compiler: the
tutorials are based on a good free one. (No, "good" and "free" are not mutually exclusive!) The material
should be of general use, but is, I hope, especially useful for those who have the Pascalite
microcontroller. Feel free to use the tutorials in programming courses, but a credit of the source would be
appreciated. You do not have to have the Pascalite hardware to do everything in these programming
tutorials. IF YOU DO have the hardware, especially if you have just obtained it, PLEASE have a look at
my Using the Pascalite Hardware It has details of how to access various features of the splendid
Pascalite.
Pascalite is two things: A Pascal software programming package which you can download for free, and
an inexpensive but capable microcontroller, which is remarkably capable. The software includes not only
the compiler, but also a splendid integrated working environment including editor, debugging tools and
simulation of the Pascalite hardware. The download was only 482kb in late 2002, but don't be fooled into
thinking that it can't be very capable in so "few" bytes. It simply wasn't written at Microsoft!
Click here to visit the Control Plus site, which gives away the software and sells the hardware. By the
way, this site and the tutorials were created without payment from or affiliation to Control Plus. I just
thought the product deserved publicity, and liked the fact that I could teach Pascal without requiring
expenditure by my pupils. I have also done an overview of the Pascalite for you.

The exercises work exactly as presented if you are using Pascalite. However, it (mostly) obeys the rules
of any good Pascal and they will need little modification to run in other dialects of Pascal.
What you learn here will help you if you ever set out to learn Delphi, the outstanding way to program
Windows. It will also help you if you set out to learn Kylix, which is virtually "Delphi for Linux".
There are more notes at the bottom of the page about other offerings.
To search THIS site.... (Go to my other sites (see above) and use their search buttons if you want to
search them.)...
Click this to search this site without using forms, or just use......

Find! Site Map powered by FreeFind

Site search Web search

http://sheepdogsoftware.co.uk/pltut.htm (1 of 5) [1/28/2005 3:43:52 PM]


Pascalite Programming Tutorials

Table of Contents, Pascal / Pascalite Tutorials:


Level 1 Tutorials:

Start Here This takes a complete beginner through a first project, covers points that apply to any project,
and covers some points about conventions used in the other tutorials.

Second tutorial: Going loopy.

Third: Introducing variables.

Fourth: More on variables.

Fifth: Let there be light!

Revolution counting: What has that hamster been up to?

Arrays: Super variables

User Defined Procedures: Make your own language! (Part 1)

Level 2 Tutorials:

Not a tutorial. The rest! (Miscellaneous features introduced)

User Defined Procedures: Make your own language! (Part 2- parameters)

Generalised Rules of Program Structure: Let's have some backbone! (A hard and not ESSENTIAL
tutorial covering some basics)

Program Structure Suggested by Pascalite Default: (Not essential, but may help if you want to use
default.)

Things You Could Do: Sketches of some ways to use a Pascalite

Level 3 Tutorials:

User Defined Procedures: Make your own language! (Part 3- more on parameters)

Generalised Rules of Program Structure: More backbone!

http://sheepdogsoftware.co.uk/pltut.htm (2 of 5) [1/28/2005 3:43:52 PM]


Pascalite Programming Tutorials

An Overview of Binary Mostly theory.

Other Tutorials by me, not integrated with the above:

Introduction to Dallas 1-Wire... Overview and links to tutorials with source code for accessing 1-Wire
(aka MicroLan) devices, as used in iButtons. Dallas is now part of Maxim. ("1-Wire" is a registered
trademark. The Pascalite hardware can access at least some 1-Wire devices, at least a little. I would guess
that more functionality will be forthcoming in due course.)
Pascal for those who know Basic... but who haven't done much Pascal.
Making it work... Help with debugging.. and on preventing the need for it. Also useful to programmers
using other languages.

Editorial Philosophy
I dislike 'fancy' websites where there's more medium than message.... especially if that means I have to
wait while multiple little items get downloaded. For a pretty picture, I can go to an art gallery. (Of course
an attractive site with content deserves praise... as long as that pretty face doesn't cost download time.) In
any case....
I am trying to present this material in a format which makes it easy for you to USE it. There are two
aspects to that: The way it is split up and the way it is posted.

The way it is split up...


I have tried to split it up into 'bite-sized' pieces and to indicate which pieces are basic and of general
importance, and which address more specific issues which may also be more complex, or require prior
understanding of other issues. In other words, I try to show you how to walk before running. The 'Level
1' tutorials cover the basics. If you have no experience, start with the level one tutorials. If you decide to
jump in at a more advanced level, and things are not clear, it might be an idea to skim the level one topics
if only to learn about my way of expressing the concepts.

The way it is posted...


PS.... I wrote the following before getting into the nitty gritty of what I intended. Implementation has
proved to be a pain, and I'm experimenting with different solutions. You'll find some tutorials are heavily
infested with HTML code. Is this a problem? You can still save the pages from a browser, and re-load
them from your hard-disc later, off-line. At least with WordPerfect, you can load the .htm file, select all,
copy to clipboard, start a new WordPerfect document, then paste in the text, mostly intact and cleaned of
HTML. (Hard to describe, easy to do.)>

http://sheepdogsoftware.co.uk/pltut.htm (3 of 5) [1/28/2005 3:43:52 PM]


Pascalite Programming Tutorials

You should be able to read the tutorials on-line without difficulty. However, you should ALSO find it
easy to capture them for off-line use, including editing for your own purposes. The following should
work. I would suggest that you create a folder for the tutorials so that you can retain my filenames with
no risk of clashes:

On-line, use your browser to view the tutorial you want to capture.

Use File|Save As... to save the web-page to your disc. At this point you can log off or visit other pages,
perhaps saving them, too.

When you have logged off, start Notepad (or Wordpad, or anything you like, but then you're on your own
:-) ). Load the file you saved. Turn word-wrap on. (Notepad: Edit|Word-wrap.)

Snip off the html header and footer. (In one 'solution', you will also have to remove all <br>s and /<br>s
from the text. (Wordpad can to this.)

Re-save... you should now have the tutorial in a nice tidy, mostly uncomplicated text file. There will be
some things left over from the text's HTML origins, e.g. the <br>s and the </br>s, but you can weed
them out with normal editing tools.

Filenames...
I've tried to be organized: Names start "plt" or "pt" for Pascalite / Pascal Tutorial. Next is a digit, for the
level, then I've used letters one after the other, e.g. ptl2a, ptl2b, ptl3a. The letter doesn't mean much... it
merely shows when I got around to that particular topic!

The connection between Delphi and Pascal:


Delphi is based on Pascal. It is for writing programs for Windows, using Pascal with a lot of
enhancements from those wonderful people at Borland. If you are very new to programming, you might
make progress faster if you start with a non-Windows Pascal... such as Pascalite, the subject of the
tutorials this page is the table of contents for ! ! ! (Isn't that handy!)

In addition to the tutorials for which this page serves as Table of Contents, I have other sites with
material you might find useful.....

Delphi Programming Tutorials

Using a Windows / DOS pc's parallel port with programs written in Delphi and other languages.

Some pages for programmers.

http://sheepdogsoftware.co.uk/pltut.htm (4 of 5) [1/28/2005 3:43:52 PM]


Pascalite Programming Tutorials

And now for some links to other peoples' pages you may find useful.... Don't forget to
come back here?? :-)

Zip of Prof. Salmi's superb FAQs... almost everything that anyone ever wanted to know! When you've
downloaded the zip by clicking on the link, unzip it, and look in TSFAQP.IDX which is the FAQ's table
of contents. Don't know how to unzip? Time to learn! It really isn't hard, and it is an important skill. And
here's a second place with the zip of Professor Salmi's FAQs.

Borland Once user unfriendly, but not last time I looked. Certainly worth a visit. The registration
information they ask for is less presumptuous than many sites. Free copies of not primitive versions of
the excellent Turbo Pascal are sometimes (legitimately) available.
Delphi Land- Delphi tutorial, tips, source code. English or Nederlands
Programming Tutorials Webring... content of variable quality
Frank's Delphi Lessons
Marco Cantu's Essential Pascal tutorial... read online, or download text.
Babilon Tutorial written for beginners, but with some intermediate level tricks, too.
Lycos selection A list of links for Delphi programmers from Lycos
Delphi Super Page.... an archive of material, some with sourcecode.
Swiss Delphi Center In English, German, and French. Programming tips, Downloads, Links, Etc
Links organised for you into topics
www.matlus.com Site with straightforward tutorials dealing mostly with building using Delphi 6
Enterprise.
Excellent, straightforward tutorials dealing mostly with building SOAP/Webservices using Delphi 6
Enterprise.
Delphi Resource Center

Alternatively, use newsgroups,

via Google's Groups to obtain answers to your questions! (New to newsgroups? See my introduction.)

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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 editor's (Arunet) homepage


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

http://sheepdogsoftware.co.uk/pltut.htm (5 of 5) [1/28/2005 3:43:52 PM]


Delphi tutorial, Start Here (Level 1).

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial, Start Here (Level 1)


This has good information, and a search button at the bottom of the
page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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


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!)

http://sheepdogguides.com/dt1a.htm (1 of 8) [1/28/2005 3:43:56 PM]


Delphi tutorial, Start Here (Level 1).

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

http://sheepdogguides.com/dt1a.htm (2 of 8) [1/28/2005 3:43:56 PM]


Delphi tutorial, Start Here (Level 1).

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

http://sheepdogguides.com/dt1a.htm (3 of 8) [1/28/2005 3:43:56 PM]


Delphi tutorial, Start Here (Level 1).

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,

http://sheepdogguides.com/dt1a.htm (4 of 8) [1/28/2005 3:43:56 PM]


Delphi tutorial, Start Here (Level 1).

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, making it what appears below. N.B. I said "Add to"... Do not type all of what you
see here, just the new bits.

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;

http://sheepdogguides.com/dt1a.htm (5 of 8) [1/28/2005 3:43:56 PM]


Delphi tutorial, Start Here (Level 1).

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;

http://sheepdogguides.com/dt1a.htm (6 of 8) [1/28/2005 3:43:56 PM]


Delphi tutorial, Start Here (Level 1).

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

__________

Was it of any use? Please send an email, at least. (If you would be interested in more tutorials like this,
say so. I'll try to remember to notify you if they become available.)

Even better, download a piece of my software, try it and pass it on to someone?

Cheers, Tom Boyd

www.arunet.co.uk/tkboyd/offers.htm

<
Notes on editing names, link bewteen object inspector and source code.

Notes on removing superfluous proc skeletons

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

http://sheepdogguides.com/dt1a.htm (7 of 8) [1/28/2005 3:43:56 PM]


Delphi tutorial, Start Here (Level 1).

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt1a.htm (8 of 8) [1/28/2005 3:43:56 PM]


Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial, The Whole Picture (Level 1)


This has good information, and a search button at the bottom of the
page,
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

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;

http://sheepdogguides.com/dt1b.htm (1 of 7) [1/28/2005 3:44:00 PM]


Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00

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

http://sheepdogguides.com/dt1b.htm (2 of 7) [1/28/2005 3:44:00 PM]


Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00

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

http://sheepdogguides.com/dt1b.htm (3 of 7) [1/28/2005 3:44:00 PM]


Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00

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.

__________________

http://sheepdogguides.com/dt1b.htm (4 of 7) [1/28/2005 3:44:00 PM]


Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00

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'!

http://sheepdogguides.com/dt1b.htm (5 of 7) [1/28/2005 3:44:00 PM]


Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00

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.

=====================

Was the above of any use? Please send an email, at least. (If you would be interested in more tutorials
like this, say so. I'll try to remember to notify you if they become available.) For my idle curiosity...
Where are you, please? (City, state, country)

http://sheepdogguides.com/dt1b.htm (6 of 7) [1/28/2005 3:44:00 PM]


Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00

Even better, download a piece of my software, try it and pass it on to someone?

Cheers, Tom Boyd

www.arunet.co.uk/tkboyd/offers.htm

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt1b.htm (7 of 7) [1/28/2005 3:44:00 PM]


Delphi tutorial, Debugging.. and avoiding the need. (Level 1).

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial: Debugging.. and avoiding the need


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

This has good information, and a search button at the bottom of the
page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Almost all of the Pascal Tutorial on debugging on debugging also has material that applies to working in
Delphi. The section on sending yourself messages about the state of variables, using writeln, is presented
in a Delphi version below.
This page is a "work in progress"... I've run out of time on the day's work, and needed to leave
SOMETHING here to hold to spot. Email me to say "We hate "site under construction" pages, and I'll get
back to this sooner for you!

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

http://sheepdogguides.com/dt1c.htm (1 of 3) [1/28/2005 3:44:03 PM]


Delphi tutorial, Debugging.. and avoiding the need. (Level 1).

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

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search

http://sheepdogguides.com/dt1c.htm (2 of 3) [1/28/2005 3:44:03 PM]


Delphi tutorial, Debugging.. and avoiding the need. (Level 1).

Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt1c.htm (3 of 3) [1/28/2005 3:44:03 PM]


Delphi: How To: Make 'beep' or other sound.

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi: How To: Make 'beep' or other sound


This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Making a beep....

It was so easy in pre-Windows days!

It is easy (within the Windows meaning of the term) again in post Delphi1 days... more on this later.

But what's a poor Delphi1, no soundcard, user to do? Fear not... help is at hand!

I obtained what I needed for this from the excellent 'Waite Group Borland Delphi, How To' book, ISBN
1-57169-019-0. It clearly states that this 'solution' is not very robust. If it doesn't work on your computer
don't be too surprised, or waste too much time on it. You may want to check that
DEVICE=SOUND.DRV (or similar) is in your CONFIG.SYS file. If you have a soundcard, Delphi2 and
Win95, use the better alternatives.

Making a sound on such a system is almost easy....

You can almost just do..

iTmp:=OpenSound;
SetVoiceSound(1,9800000,400);
StartSound;
CloseSound;

Unfortunately, you should...

a) Test iTmp after the first line, and deal with problems.
... and you must

b) Arrange for CloseSound NOT to happen immediately, but TO happen eventually.

These needs are met in the following code. Once it is entered into a program, calling 'Beep' will make a
beep on the speaker.

_________________________

http://sheepdogguides.com/dt2g.htm (1 of 5) [1/28/2005 3:44:05 PM]


Delphi: How To: Make 'beep' or other sound.

Extracted essential bits....

(The 'uses' clause needs nothing special, apart from the usual SysUtils, etc)

Somewhere in the 'type TForm1 = class(TForm)...' declaration, you need to add

procedure Beep;

I put it down at the bottom of the Delphi created declarations. In my case that was after...

procedure FormClose(Sender: TObject; var Action: TCloseAction);

... and after

implementation

{$R *.DFM}
.... you need....
var boSoundVoiceInUse:boolean;

procedure TForm1.FormCreate(Sender: TObject);


begin
boSoundVoiceInUse:=false;
end;

procedure TForm1.Beep;
var iVoice:integer;
const freq=150;(*Sets pitch of tone. MIGHT be APPROX Hertz*)
dur=350;(*Sets duration of sound. MIGHT be APPROX milliseconds.
The tiBeep mechanism for calling SoundClose will ensure
that the sound does not last longer than dur ms. If you
are getting too short sounds, multiply the reference to
dur in the call of SetSoundVoice by something suitable.*)
begin
iVoice:=OpenSound;
if iVoice<1 then
showmessage('Unable to do sounds at this time. '+
'Either some other program is using the relevant '+
'resource, or it is not available. (Making it '+
'available might be more of a pain than it is worth!)');
if iVoice>0 then begin
SetVoiceSound(iVoice,freq*655360,dur);
StartSound;
(*If you simply put CloseSound here, the
sound will cease virtually immediately... too

http://sheepdogguides.com/dt2g.htm (2 of 5) [1/28/2005 3:44:05 PM]


Delphi: How To: Make 'beep' or other sound.

quickly to even hear it start. In 'the old days',


you could put a loop to waste time here and then
CloseSound... but in the Windows environment that
is A Very Bad Idea. MAKING the sound is easy....
dealing with letting it continue, and then tidying
up afterwards is the messy bit! The CloseSound will
happen if..
i) We close the main form, or
ii) The tiBeep timer says that the beep's allotted
time has passed*)
boSoundVoiceInUse:=true;(*This is needed so that
we can check in Form1.OnClose that a CloseSound
isn't needed.*)
with Form1 do begin
tiBeep.interval:=dur;
tiBeep.enabled:=false;
tiBeep.enabled:=true;
end;(*with*)
end; (*iVoice was >0*)
end;

procedure TForm1.tiBeepTimer(Sender: TObject);


(*'How to..' (ISBN1-57169-019-0, pg.546) says
that calling CloseSound won't hurt, even if
sound not open... but such sloppiness is
if the timer is only enabled after an OpenSpound
occurs.*)
begin
CloseSound;
boSoundVoiceInUse:=false;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);


begin
if boSoundVoiceInUse then CloseSound;
end;

... and that should do it!!

======================================================
On a system with Win98 and Delphi 2 and a soundcard.....

The following worked on the system just described. I expect it would also work in a Win95 machine.
This information comes to you from the combined efforts of....

http://sheepdogguides.com/dt2g.htm (3 of 5) [1/28/2005 3:44:05 PM]


Delphi: How To: Make 'beep' or other sound.

...the also excellent 'Teach Yourself Delphi Two in 21 Days', ISBN 0-672-30863-0
...help from an internet newsgroup, found with www.deja.com
...and from about an hour's exploration of the issues. (Not hastened by several crashes of my machine as I
tried trivial things!!!)

Start a project. Put a button on it. Make the button's OnClick handler be simply

playsound('C:\windows\media\tada.wav',0,snd_sync)

(The C:\windows\media\tada.wav must describe a file present on your system.)

AND (the book and help file forgot to mention this!!) add mmsystem to the unit's 'Uses' clause. (Without
it, I got 'playsound: unknown identifier'.. even though pressing f1 gave me lots of information about this
'unknown'... but the f1 information didn't mention that mmsystem was needed, either!!) Oh well, got
there in the end!

If you run the program click the button, the .wav file should play. No joy? Be sure your speaker is
switched on, etc! How many hours have we all lost to simple things like that? The Win95+ volume
controls never cease to confuse me. Try using some other .wav player to check out that all SHOULD be
well, and that any problem is in your Delphi program.

The book also said that

playsound('SystemStart', 0, snd_async or snd_nodefault)

was worth knowing about. Well.. it did work.. sort of. Unfortunately, I closed the form before the sound
finished playing, and that froze the system. It wouldn't even respond to ctrl-alt-del, but it did persist in
playing and replaying a very short segment of 'The Windows Sound'. Also, I couldn't discover a list of
the 'known' sounds that I could use where 'SystemStart' is, but I got indications that they would be highly
specific to individual machines... not very useful if you want others to use your software.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows

http://sheepdogguides.com/dt2g.htm (4 of 5) [1/28/2005 3:44:05 PM]


Delphi: How To: Make 'beep' or other sound.

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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2g.htm (5 of 5) [1/28/2005 3:44:05 PM]


Delphi: How to blank monitor

HOME - - - - - Delphi Tutorials TOC - - - - - - - - - - - - Other material for programmers

Delphi: How to blank monitor


This addresses how you can turn the monitor "off".... if you're using Win 9x, not NT or descendants. The
"off" I refer to is not truely "off", as in unplugged... but it is more than an "on" monitor displaying black!
It is the same state that the Windows power save option allows you to invoke.

I start with thanks to groups.google.com and Charles and Luis for their posts in
borland.programming.delphi.winapi of May 17 2001. Groups.google.com is always a good place to go if
you need help with "How do I..." or "Why does my computer..."

Start a project. I called mine DD41

Be a little careful as you develop this application... it is quite easy to get the screen OFF with no way
(short of a power cycle!) to turn it back on again!

Create variable boMonitorOff

In FormCreate set it false

Optional, but maybe wise: Put an ink-on-paper announcement on your monitor saying "Move mouse to
turn monitor back on" You'll just have to hope your user sees that before turning the computer or monitor
OFF thinking he/she is turning it ON!

To start with, we're not going to turn the monitor on and off. We'll write code which will do that with
very little modification AFTER other bugs have been eradicated!

To that end, add a lable to the form. Call it laMonitorState, and use the Object Inspector to initialise its
caption to say "Monitor On"

Create a button, call it buMonitorOff. Make it's OnClick handler....

boMonitorOff:=true;
laMonitorState.caption:='Monitor Off';
You can run the program now. Clicking the Monitor Off button should change the MonitorState label....
but once it says "Monitor Off", there's nothing in the program to reverse the action. Aren't you glad you
didn't really turn the monitor off!

Add a OnMouseMove event handler to the main form. Make it....

if boMonitorOff then begin


boMonitorOff:=false;
laMonitorState.caption:='Monitor On';

http://sheepdogguides.com/dt2j.htm (1 of 3) [1/28/2005 3:44:08 PM]


Delphi: How to blank monitor

Now the program should be doing almost everything it should.

===
For the final bits.... (When you test this, don't be alarmed if the monitor doesn't spring to life instantly
when you move the mouse. It may take a moment (less than 20 seconds, though!) to warm up! Also: in
the early stages, you have to move the mouse far enought to bring the (at that time invisible!) pointer
outside of the button that you clicked to blank the screen.

Add to FormMouseMove, just after "if boMonitorOff then begin", ...

sendmessage(application.handle,WM_SYSCOMMAND,SC_MonitorPower,-1);
Add to buMonitorOffClick...

sendmessage(application.handle,WM_SYSCOMMAND,SC_MonitorPower,0);
That should do it!

One last refinement:

In the Object Inspector, drill down to buMonitorOff's OnMouseMove event. Click the downward
pointing arrow at the right hand end of the field to the right of "OnMouseMove". You should see
"FormMouseMove". Click on it. Now the FormMouseMove event handler should trigger as soon as you
move the mouse, even before it leaves the button's face.

And now for the bad news....

I suspect the main use for this material would be in some form of
blank-screen-if-there's-no-user-action-after-a-time-inteval scheme. If the program blanking the screen
does not happen to have focus at the time the screen blanks, will moving the mouse be "seen" by that
program so that the screen-restore code can be invoked? I suspect there's some way to pass a "I saw the
mouse move" message to all running apps.... but maybe this needs a little careful consideration/ research.
I'm sure answers will be available within a screensaver tutorial somewhere.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


The search engine is not intelligent. It merely seeks the words you specify. It will not do anything
sensible with "What does the 'could not compile' error mean?" It will just return references to pages with
"what", "does", "could", "not".... etc.
Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

http://sheepdogguides.com/dt2j.htm (2 of 3) [1/28/2005 3:44:08 PM]


Delphi: How to blank monitor

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... 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 an MS-DOS or Windows 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

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.
{end}

http://sheepdogguides.com/dt2j.htm (3 of 3) [1/28/2005 3:44:08 PM]


Delphi: Getting Input From Your Users

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

Delphi: Getting Input From Your Users


This page is information rich, and a has search button at the bottom
of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

PLEASE NOTE: This is a late draft of a tutorial which I hope you'll


like, and find useful. However, it has NOT has the "final polish"
which it will eventually get, so don't moan about the little loose ends
which remain for the moment, please! It IS essentially complete.
QDo: REFINE headers, titles, meta tags.

QDo: Intro- what this holds, general and specific...

QDo: link to DD46's tut.. dt3o, input via tailored dialog)


I sit down to write this tutorial for you on 17 December, 2004. It will be my 50th tutorial on Delphi for
you. In the collected tutorials, you will find a wide variation of quality and approach. In this tutorial, I am
attempting to pull together the experience of writing those other tutorials. I may well repeat things that
appear scattered through the others. This is a "Level 2" tutorial, so I hope you would expect more "hand
holding" that would be given in tutorials from the more advanced levels.

The tutorial will show you how to set up a RadioGroup to get input from users. In the example
developed, users choose one of three colors.

When people turn to computers to get help with something, they can rarely just start the appropriate
program running and leave it at that. Usually, users need to give the program instructions, indicate their
needs, make choices, etc. For example: I frequently send mail from the UK to the US. I have a little
program that tells me how much postage is needed. Even that simple little program needs to know
something: How heavy is the parcel I'm sending?

Windows provides programmers and users with almost too many ways to deal with the problem of letting
the program know the users needs, the problem of obtaining input. (If only things were as easy as they
are made to seem in the film Short Circuit!) (And if only there were many Stephanies decorating the
planet. But I digress!)

Novice programmers need to attack the problem from both ends: They need to think about programs that

http://sheepdogguides.com/dt2l.htm (1 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

have been written by others, and think about the ways input is collected by those programs.

The other "end" novice programmers can attack from is their current stock of skills. They must be
patient! They will (eventually) be able to "run", but even while they are still "walking", most things can
be done, even if a little crudeness sometimes creeps into a program until necessary skills are learned or
discovered.

This tutorial will show you a really simple way to get input which will suit SOME needs. It will also take
you gently by the hand, and try to tell you almost everything you need to know. It won't tell you
everything about Delphi, but it will try to tell you everything you need to know to create the program the
tutorial is about.

An important rule for programmers: Keep a very clear idea in your head of exactly what users of your
program should encounter. It is easy to get distracted by the minutiae of the program's internals, and then
start writing a program which isn't the one you had in mind when you started, and before you know it,
parts of your program don't "fit together".

Having said that, I should also admit that sometimes you need to re-consider your goals as the project
progresses. This is fine... just be sure that you do think carefully about the overall picture, from the user's
perspective, any time you decide you need to re-define your goals.

The sort of input which can be obtained by the techniques explained in this tutorial is limited to things
like....

yes / no
north / east / south /west
red / green / blue
... in other words, the user will be selecting one alternative from a limited list. The programmer will
define what the choices are, and the user will not be able to extend that list. In the colors example, yes,
there are other colors... but only the colors put in the list by the programmer will be available to the user.

Well! (Almost) enough theory... let's move on to creating a program.

This tutorial assumes you have Delphi set up on your computer. I am using Delphi 2, on a Win98
machine. I am assuming that you have a working Delphi installation, but I'm not assuming any extra
features.

Some of the things I tell you to do below are simply the only way you can achieve the result. Other
things are more open to choice. Sometimes I'll discuss options, other times I'll just give you one of
perhaps several things which work.

You don't need to be online for any of what follows. You probably accessed this tutorial via the internet
(http://sheepdogguides.com/tut.htm, or search with Google for "sheepdog delphi tutorial"). Just use your
browser's File | Save, and you can access the document while offline.

http://sheepdogguides.com/dt2l.htm (2 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

I said I'd cover basics: You can have Delphi AND the internet browser of your choice (I like Opera)
running at the same time. I find it easiest to work with multiple programs by having everything in the
"restored" state, i.e. not minimized, not maximized. When they are like this, you can have one app, say
Delphi, with it's upper left corner in the screen's upper left, and the other app, say your internet browser,
with this tutorial in it, with it's lower right corner in the screen's lower right. Neither should be stretched
to fill the screen, of course. Like this, whichever app is on top, there's still a bit of the other peeking out.
Click there, and you can see the other.

Still on the subject of multi-tasking: Of course, there's also the option of using the buttons on the task bar
to switch between active applications. If you knew all this, thank you for your patience. IF YOU
DIDN'T: Please make an effort to try working with Delphi and your browser "at the same time". Once
you get the hang of it, it is very useful. At the moment, I am generating the text of this page in a text
editor called Textpad, saving my work to disc from time to time, and then looking at what it looks like in
my browser before going back to working on the text.

So! You're sitting there, computer ready, Delphi ready.

There may be things left over from earlier Delphi jobs. Just do File | Close All. If nothing was open, no
harm done.

Do File | New Application. A form should appear on the screen. (Form (in this context): A rectangle
covered in a grid of dots, with a Windows bar across the top with the Delphi logo and "Form1" at the left,
and three small square buttons at the right, the usual ones: One for "minimize", one which will be for
"maximize" at the moment, but will change to the one for "restore" if clicked, and one for "close". (Don't
click the one for "close" at the moment... (If you do, just press F12 to get it back.)

Here beginnneth a lengthy section on "Working With Delphi To Create An Application". Even if you're
sure you know the basics, please work through this section, as a few things will need to be in place for
later parts of this tutorial. However, if you are in a big hurry, know quite a bit already, you can click here.

Even if you can't see all of them at this moment, there are (at least!) four windows which are typically on
a Delphi programmer's screen, and we will tour them now.

Typically long and not tall, and across the top of the screen is the main Delphi interface. Below the title
bar of that window is the Delphi menu....
File | Edit | Search | View.... etc

Below the menu there are some buttons on the left, and a tabbed control on the right.

Here's where half of you will love me, half will hate me. For reasons that half of us understand, I don't
like putting graphics in web pages. This does entail a cost, though, which we're about to endure.

"The buttons on the left", on my machine, are in two rows, and consist of three groups of four buttons. I

http://sheepdogguides.com/dt2l.htm (3 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

use only two of them regularly, and we'll come back to what they are, and what they do, in a minute. All
of the buttons are just a quick way to accomplish things which you could also do via the menu.

Turning to "the tabbed control on the left": I'm speaking of the "component palette". The tabs on my
machine are "Standard", "Additional", "Win 95", "Data Access", etc. On each tab, there are a number of
buttons with icons. ("BitBtn"s, in Delphi-speak... which in many cases derives from MS-speak. Don't
forget as you work through this, that Delphi has an extensive "Help" file, and if you know the right term,
e.g. BitBtn, you can often learn useful things from the help file.) At the left, on every tab, there's an
arrow icon that looks like a standard mouse pointer. We'll come back to this in a moment, calling it "the
component palette's pointer button".If you have a Delphi window active, and hover the mouse pointer
over any of the other buttons of the component palette, then a tooltip will pop up to tell you what that
icon stands for. So, for example, on my component palette's "Standard" tab, the buttons are for: Main
Menu, Pop Up Menu, Label (icon is letter "A"), "Edit"(box), Memo, Button (Icon is button with "OK") (I
keep saying "on my..." because menus, component palettes, button sets, etc can be customized, and they
change between Delphi versions. I hope that you will find your environment close enough to mine that
you can figure things out.)

Click (i.e., press and release the left hand mouse button while the mouse pointer is over...) the Label icon
of the component palette. The "button" of the Label icon should "go" down, and "stay" down. Move the
pointer to the middle of Form1's window, and click again.

You should see two things: First, a label saying "Label1" should appear on the form. (For the moment the
selection marks around it will make it a little hard to read.) Second, and less obvious, the button on the
component palette for labels has "popped up", and the pointer icon is re-selected. If you want to place
another label on the form, you have to click on the Label icon in the palette again first.

Reading about it is tedious, but you'll soon get the hang of using it; it is pretty intuitive.

Now click on the button icon of the component palette, and then click somewhere on Form1. I.e., click
somewhere in the window which is displaying Form1: the rectangle of dots with "Form1" at the top. This
is where we can see what your application is going to look like. As your programming skills grow, you
will find that an application may have more than one window, and how any of them appear can be
changed as needed... but for now, things are as simple as I hope they seem.

Try moving the label or the button. Try changing the button's size and shape. (Don't bother with the
label's size and shape, for now.) All done "the usual Windows way", and if you have no luck, it doesn't
matter!

Double click on the button you put on the form. Weird things will happen. You should see....

procedure TForm1.Button1Click(Sender: TObject);


begin

end;

http://sheepdogguides.com/dt2l.htm (4 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

end.
You are seeing it in the third of our four important Delphi programming windows: The Code Editor. (The
first two were the window with the form, the one you put the button on, and the main Delphi interface,
the one with the menu, buttons, and component palette.)

Programming in Delphi is a little weird, depending on your background. Delphi itself types a lot of the
"stuff" needed in your program. What we're doing with the button is an example. We're about to tell the
program what we want to happen when the button is clicked when the program is running. All that
"procedure TForm1.Button1Click(Sender..." stuff is standard and necessary, and as such, we don't have
to hassle with it... hurrah!

The cursor will already be in the right place. Type.... application.terminate; on the line just after the
"begin" that Delphi put in for you. In "application.terminate;", there are no spaces, and there is one dot,
one semicolon.

Now use the main Delphi interface to invoke Run | Run.

Your "program" will be compiled, and, absent any typos, you will see the same form as before... minus
the dots, to show you the program is running, not being designed. Click on the button, and the program
will stop running, and take you back to being in Delphi, all set to make further changes to the program.

Congratulations! You did it! Take a break!

Right: Back to work.

In every realm of computing, "Save your work, often" is an important mantra. I haven't inflicted saving
on you before this, because, despite all the reading you've had to do, you wouldn't have to do much to get
back to where we are now even if youhad to re-start from scratch a few times.

Saving, itself, isn't very hard... but good use of your hard disc means that some things need to be
considered.

First, I'm going to suggest that you use a separate folder (what we once called "directories") for each
Delphi project you embark upon. A good place for those folders on my machine would be a folder called
"TKB Delphi Projects" Change the initials (TKB) to your initials for your folder. If you just call it "My
Delphi Projects", it is easy to become unclear as to who created the folder.... you? Borland? Microsoft?

I'd recommend putting the Delphi Projects folder in the My Documents folder.

One more thing, before we save your work:

A Delphi project consists of at least three files. There will be one with each of the following extensions:
.dpr, .pas, .dfm. (These are discussed in more detail in my tutorial "The Whole Picture".) In addition,
eventually, there will be a file with the .exe extension. This, and only this, is what you send on to
customers. It is all they need to use your program. Without the other files, which are only useful to

http://sheepdogguides.com/dt2l.htm (5 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

Delphi programmers, they can't (easily) change things within the program, e.g. your copyright message.

While what I'm about to describe isn't the only way to do things, do them this way for the moment. You
can re-write the rules later, when you have a better idea of the consequences.

Use the menu to invoke "File | Save All". (Not "Save project as..", not the simple "File | Save", or any of
the other things. Use "File | Save All")

You'll get a save dialog with "Save Unit1 As" in the title bar.

Use the tools to navigate to "My Documents"

Use the "New folder" button to create a new folder (!), call it, "(Initials) Delphi Projects"

Double click on the folder's icon. That should move you into the folder. Don't be alarmed that it is
empty... it should be at this stage.

Click the "New folder" button again, and create a folder called DD47, to stand for "Delphi Demo 47",
which is my name for the program we are creating during this tutorial. Use my name, because parts of
the name get into things we're going to do, and you will be saved typing and confusion if you use DD47

Double click on the DD47 folder icon to move into the project's folder. It will also still be empty at this
point.

The "Save Unit1 As" dialog box should now have "DD47" in the "Save In:" edit box. We've got the
"where" of the saving sorted out. Now we have the "what" to do...

In the edit box for File Name, change the proposed "Unit1.pas" to "DD47u1.pas", click the "Save"
button.

As soon as the save is done, you'll get another Save dialog, but this time it is to "Save Project1 As...".
You will (or should already be!) in the right place, i.e. "My Documents\(initials) Delphi Projects\DD47.
You need to change the name for the file to DD47.dpr. One consequence of this choice is that the default
name for the .exe file will be DD47. (You can rename it, it will still run, but you might as well have it
start with a good name.

We'll say more about saving in a moment. (If you use Windows Explorer or similar to look in the DD47
folder, don't worry about the extra things which will be there.)

I said there were four important Windows, and we've only covered three so far. The remaining window is
the Object Inspector. It has its name nicely in its title bar. If for some reason you can't see it, press F11,
and it should appear.

The Object Inspector tells us much more than we wanted to know about many, many things, but it is also
useful. With it, you can get things the way you want them.

http://sheepdogguides.com/dt2l.htm (6 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

Make sure that the component palette's pointer button is currently selected. Then click on the button you
put on the form. The box at the top of the Object Inspector should now be saying "Button1: TButton".
This says that the button's name is "Button1", and that it is an object of the TYPE (important word, but
we can leave it for now) of the object is "TButton".

The main part of the Object Inspector is made up of two tabbed pages, each of which consists of two
columns. Make sure that the "Properties" tab is selected. You should see "Cancel: False, Caption:
Button1, Cursor: crDefault...", etc. Click on the edit box to the right of "Caption", where it says
"Button1". Change "Button1" to Quit.

Now click somewhere in the form other than on the label or the button. At the top of the Object
Inspector, you should now see Form1: TForm. Go down to the "Name" property (currently "Form1".
(You may need to re-size the Object Inspector, and/or use the scroll bar). Re-name the form DD47f1.

Do "File | Save All" again. You won't see any messages, but Delphi will save all the important files.

Do "Run | Run". Your button should now say "Quit", which helps the user know what it is for! Use the
button to go back to the "design" phase of the Delphi program development cycle.

Now... I said there were two buttons on the Delphi interface window which I found useful. The first is
the green, right pointing triangle. This is the equivalent of doing "Run | Run" with the menu. If it is
greyed out, it means the program is already running.

Use the Object Inspector to change the form's button's name to buQuit. Don't re-save yet.

Look at the buttons on the Delphi interface. Two have a picture of a folder, and a small grey rectangle,
wider than it is high. On my machine, they are the first two from the left, in the top row of buttons. On
each, there is also an arrow. The rectangle is your hard disc. The icon with the arrow from the folder to
the hard disc marks the "Save All" button. If, with one of the Delphi windows selected, you hover the
mouse pointer over the button, you'll get a tool tip saying "Save All". Click this frequently as ou work! If
the button is greyed, it means that you haven't made any changes since the last save. (I only got you to
change the button's name so that the "Save All" button wouldn't be in the greyed state.)

We're now, finally, going to address the specific topic this tutorial (nominally) is about: Getting input
from the user. We're not even going to do very much with the input... that's for another day! But we'll get
it. As follows....

On the "Standard" tab of the component palette, click on RadioGroup. Don't worry too much (yet) about
getting the right component(!) Try for the one near the right hand end, is a grey rectangle with a blue
"splodge" on its upper left edge, and some blue lines, each pre-ceeded by a dot inside the rectangle. If
you hover the mouse pointer, it will say RadioGroup when you're over the right one.

Now click on the form. The object inspector should confirm that you did get a Radio Group, by saying
that the object is "RadioGroup1: TRadioGroup". If it doesn't, delete the object you added (press delete
key), and try again!

http://sheepdogguides.com/dt2l.htm (7 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

If necessary, move the label and button you created earlier to make room for the RadioGroup.

Be sure that the RadioGroup is selected. Its name will be in the box at the top of the Object Inspector.

In the Object Inspector, you'll see a row called "Items", with "(TStrings) in the box in the right-hand
column. Double click on TStrings (or click, and then click on the little square with three dots). This will
bring up the "String List Editor"

Type in Red, Blue, Green, in that order. Press enter after Red and Blue, so that the words are on separate
lines. At the top of the String List Editor there should be a message saying that you have 3 lines. Click
the OK button. Do a "Save All", before you forget!

If you now run the program, you will see some radio buttons. If you click any of them, it will become
"checked", and whichever was checked previously will become unchecked.

A "minor" untidiness, which we could prbably live with, should be tidied away. At present, when you
start the program, NONE of the radio buttons is pressed. We'll fix that. It may seem like a little bit of
black magic for the moment. Don't worry... just use the trick.

You need to get the form showing. If it isn't already, be sure that one of the Delphi windows is currently
the window with focus (i.e. "active") and press F12 once or twice. The form should appear. Double click
somewhere on it NOT on the label, the button, the radiogroup. You should be switched to the code
window (as you were when we told the Quit button what it's job was), and you should be seeing...
procedure TDD47f1.FormCreate(Sender: TObject);
begin

end;

DON'T click "Save All" just now... Delphi will "see" the empty "FormCreate" skeleton, and remove it.
On the line just after the "begin", add...
radiogroup1.itemindex:=0;

This will cause the first (item "0") of the radio buttons to be checked when the program starts up. You
can (and should) click "Save All" now.

If you did NOT get "procedure TDD47f1.FormCreate...." when you tried for it, just leave whatever you
get, go back to the form (pressing F12 is the easy way) and try again.

Well... so far so good. We have a way to let users tell the program their wishes. How do we get the
program to take notice of those inputs? That's really a story for another tutorial, but as you have done all
the work you've done, you deserve something, so here's a simple use of the input....

Go back to the form. Double click somewhere within the RadioGroup. You should get...

http://sheepdogguides.com/dt2l.htm (8 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

procedure TDD47f1.RadioGroup1Click(Sender: TObject);


begin
if radiogroup1.itemindex=0 then label1.caption:='You pressed RED';
if radiogroup1.itemindex=1 then label1.caption:='You pressed BLUE';
if radiogroup1.itemindex=2 then label1.caption:='You pressed GREEN';
end;

(Note that the first radio button is "number zero". Computer programmers often count the first thing in a
list as "zero". It can be very helpful. Delphi isn't entirely consistent... it sometimes counts things from
"1".)

Of course, our program doesn't do much... but there will be many times when you need to make settings
from a limited list of choices, and the RadioGroup component gives you one way to do that. See my
Level 3 tutorial on getting input for another option, which is a level 3 tutorial as it moves more quickly,
gives you less hand holding, and explores more subtle ideas. QTODO>>> Postscript: Talk about
"instance", "control", "component" ditto "RadioGroup1's OnClick handler"

Jazar 200
Delphi Vote Click this, please, to help get this site publicity at Jazar Top 200 Delphi

.. and here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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 Sheepdog Software (tm) freeware, shareware page.

Link to Tutorials main page


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for

http://sheepdogguides.com/dt2l.htm (9 of 10) [1/28/2005 3:44:12 PM]


Delphi: Getting Input From Your Users

more information.

http://sheepdogguides.com/dt2l.htm (10 of 10) [1/28/2005 3:44:12 PM]


Delphi:

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

Delphi:
This page is information rich, and a has search button at the bottom of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

PLESE NOTE: This is a rough draft. You are welcome to the information within it,
just so long as you don't think that all of my tutorials have so many rough edges!!
DD46: User input: DD46: User created dialog box. Level 3. (And a bit on coloured shapes)

(Derive and link to DD47's tut.. dt2l: Radio buttons)

=========

The project starts as a very simple form.

It has a shape called Shape1, and two buttons, buSetColor and buQuit. Q AND DO META TAGs< TITLES, ETC

Apologies!! I wrote notes for this tutorial, and then left them behind when I moved desks for a time. I will try to re-work this
later, when back at the desk with the notes. In the meantime, for intermdiate Delphi users, the following may be useful.

The example creates a form with a shape on it. Initially, the shape is white (if you haven't done things with the Object
Inspector to make design-time changes)

There's a button on the form, called buSetColor. When you click the button, a little dialog... written by you, tailored to your
needs, pops up. The dialog has three buttons: one each for red, green and blue. The dialog won't go away until you click one of
the buttons. When you do, the dialog goes away, and the shape changes color.

As I said... I have not got access to my notes just now, and am merely presenting below the code you would get if you
followed those notes. You can probably infer what you need to from the code, but DON'T try just to copy the code from top to
bottom.

Basically, you need to...

Start Project. (Call it DD46)


Put a shape and two buttons on the main form.
Use Delphi's File | New | Form to create a second form. Name it diaAskColor, save it
as dd46diau1
Put three buttons on it
Create the three "Click" handlers shown below.
Set up the main form's buSetColor "Click"" handler as shown.
Along the way, either by hand or by Delphi, you'll add "dd46diau1" to the main form's
"uses" clause.
It should work!!
========

http://sheepdogguides.com/dt3o.htm (1 of 4) [1/28/2005 3:44:15 PM]


Delphi:

The main form's code is as follows:

unit dd46u1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, dd46diau1;

type
TDD46f1 = class(TForm)
buQuit: TButton;
Shape1: TShape;
buSetColor: TButton;
procedure buQuitClick(Sender: TObject);
procedure buSetColorClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
DD46f1: TDD46f1;

implementation

{$R *.DFM}
{$R+}

procedure TDD46f1.buQuitClick(Sender: TObject);


begin
application.terminate;
end;

procedure TDD46f1.buSetColorClick(Sender: TObject);


var c1:integer;
begin
c1:=diaAskColor.showmodal;
if c1=1 then shape1.brush.color:=clRed;
if c1=2 then shape1.brush.color:=clGreen;
if c1=3 then shape1.brush.color:=clBlue;
end;

end.
And to the project, you add a form called dd46diau1.

In its properties, you make everything under BorderIcons false, and you make Visble false.

It has three buttons, buRed, buGree, and buBlue.

It has code as follows....

http://sheepdogguides.com/dt3o.htm (2 of 4) [1/28/2005 3:44:15 PM]


Delphi:

unit dd46diau1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TdiaAskColor = class(TForm)
buRed: TButton;
buGree: TButton;
buBlue: TButton;
procedure buRedClick(Sender: TObject);
procedure buGreeClick(Sender: TObject);
procedure buBlueClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
diaAskColor: TdiaAskColor;

implementation

{$R *.DFM}

procedure TdiaAskColor.buRedClick(Sender: TObject);


begin
modalresult:=1;
end;

procedure TdiaAskColor.buGreeClick(Sender: TObject);


begin
modalresult:=2;
end;

procedure TdiaAskColor.buBlueClick(Sender: TObject);


begin
diaAskColor.modalresult:=3;
end;

end.
Once again... apologies for the crude state of this "tutorial" at the moment. I hope tat even like this it may be useful to
someone!

Jazar 200
Delphi Vote Click this, please, to help get this site publicity at Jazar Top 200 Delphi

.. and here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

http://sheepdogguides.com/dt3o.htm (3 of 4) [1/28/2005 3:44:15 PM]


Delphi:

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay my
bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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 Sheepdog Software (tm) freeware, shareware page.

Link to Tutorials main page


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi, and they
provide promotional services, too. Click the "Help get this site publicity" link above for more information.

http://sheepdogguides.com/dt3o.htm (4 of 4) [1/28/2005 3:44:15 PM]


Delphi tutorial: Menu, etc

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial: Menu, About page, Quit method.


This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

In this tutorial, we will create a menu, an 'About' panel, and a 'Quit'


button.

This tutorial is a level 2 tutorial... you only need to have grasped the material in the level 1 tutorials to
undertake this.

Start a project, any project.

Add a main menu object to the form. (It is available from the 'standard' components page of the
components palette.) Where you place the icon will have no bearing on the appearance of the menu when
the program is run... just put it in some place out of the way on the form.

Double click on the main menu object on your form. A new window should pop up. It is in this that you
will define the menu bar of your program.

A rectangle made of dotted lines will be at the left hand end of the menu bar, and the Object Inspector
will be showing an unnamed object. Name it mmFile, then Caption it '&File'. (And press enter, or use an
arrow key to leave the caption box)(The ampersand (&) will cause the F to be underlined, and make
Alt-F an alternative to clicking on this menu item.

Click on 'File' on the menu design form.


Press the 'down' cursor key.
Make the caption for the first item in File's pulldown '&New Game', and name it mmFileNewGame.
Press Enter.

Click on the dotted-line-rectangle below 'New Game'


Make the caption '&Quit', Name mmFileQuit

Click on 'File' again.

http://sheepdogguides.com/dt2a.htm (1 of 5) [1/28/2005 3:44:18 PM]


Delphi tutorial: Menu, etc

Press the 'go right' cursor key.


Make the caption '&About', Name mmAbout

You now have a basic menu, illustrating the possibilities. Close the menu design window. To extend it
later, just select it (MainMenu1) in the object inspector and double click on the 'Items' field.

Now you need to add code to your program to act on the menu options.

I'm not going to do anything here about the 'New Game' item.. that is too specific to whatever application
you are working on.

On your form (not on the menu design window), click on File, then click on Quit. Delphi will add the
skeleton of an event handling procedure to your source code, probably calling it .mmQuitClick, and will
move you to the code editing window, with the cursor ready for the code to be added. You want at least...

application.terminate;

You may want the program to do other things first, for example giving the user a chance to change his/
her mind. If the program involves an .ini file or data which may need saving, then if it has be altered
since the last save, it is usual in Windows programs to check with the user:'Work not saved. Save it now/
No/ Cancel?' (Working with data from files is beyond the scope of this tutorial, but is covered in later
tutorials.)

You can test your menu and the File|Quit option now.

________________

For the 'About' option, we will create some text which will appear and which can be made to go away
again.

The approach taken here to doing an 'About' panel differs from that in the excellent Delphi (ver 1)
manual. Each has its merits.

Before you begin, resize the whole form to something reasonable.

a) Add a panel ('standard' component) to your form. Name it pAbout. Make it as wide as your form, but
only high enough to show one line of text. Move it (up or down) to an out of the way place on your form.

Panels are great because they are 'container' components. We will put things on the panel, and because
they are 'contained' by the panel. we can do things to the whole collection with single actions.

b) Don't be alarmed by the result of the next change. Set the panel's Align property (not AlignMENT) to
alClient.

c) Put a button on the panel. Name it bpAboutOK; Caption: OK.

http://sheepdogguides.com/dt2a.htm (2 of 5) [1/28/2005 3:44:18 PM]


Delphi tutorial: Menu, etc

d) Put a memo component on the panel. Name it mpAboutMemo; align alClient; make enabled false
(Stops users changing 'About' text. Changes wouldn't be permanant, anyway.)

e) When you added the memo, your 'OK' button probably disappeared. Use the listbox at the top of the
object inspector to select bpAboutOK. The little black squares mariking a selected item appear on the
form. RIGHT-click somewhere within the selection squares. Select 'Bring to Front' from the menu. Move
it to some tidy place. If your form gets resized, the button will only maintain its distance down and over
from the upper left hand corner. If the form gets too small, scroll bars will appear.

f) Reselect mpAboutMemo. Be careful in this work that you are getting the object you want. It is easy to
get mpAboutMemo instead of pAbout.

We are going to put some text on the panel. Now... I must confess: I do not fully grasp all of the details
of what I'm about to delve into... but what I'm suggesting works! (The problems that you can encounter
involve having 'returns' embedded in your text at places you don't want them. There's a complex
interplay between the following memo properties: Enabled, Scrollbars, Wordwrap. The WantReturns
property is not involved in this issue. While the memo's Enabled property is false, the setting of
WantReturns is irrelevant. Setting WordWrap true won't fix everything for you... the system inserts extra
returns into the text to reflect the width of mpAboutMemo when the program was compiled... but having
it set true is better than having it set false: The layout may be poor, but at least no text is lost. Leave
Scrollbars ssNone. They won't work while Enabled is false, anyway, nor will they automatically
disappear if not needed.

(If you want to try to get to the bottom of all of this, you may be happier working with the panel's and
memo's align properties set to alNone)

mpAboutMemo should be selected at this point. Double-click on the Lines property. The String List
Editor pops up. Delete the default mpAboutMemo which is there. Enter the panel's text. Typical 'About'
test includes the program's name, vendor address, and copyright messages. My imperfect sustem requires
that you press enter near the end of lines, as in the bad old days of manual typewriters. Press enter twice
to create blank lines between paragraphs. When the text is complete, click on the editor's 'OK' button.
(You don't need to use the 'save' button.)

The system is good at adding new returns if the memo isn't wide enough... but it isn't good at taking them
out again if the memo gets wider.

You may want to set the memo's Alignment property to alCenter. This centers each line of the memo's
text in the space available.

Anyway... it may not look perfect, but there should be some useful content, anyway.

__________
Once you are happy with your text, you need a way to 'hide' it while you work on the rest of the project.
Set pAbout's Align property to alNone and resize the panel to be very narrow vertically. Horizontally,
don't make it narrower than the form. If you want extra 'hiding', select the panel, right-click, click on
'Send To Back'.

http://sheepdogguides.com/dt2a.htm (3 of 5) [1/28/2005 3:44:18 PM]


Delphi tutorial: Menu, etc

__________
Now we come to writing the code to make the About panel appear and disappear.

a) Create an OnCreate event for the form, if there isn't one already. Put the following in it:

pAbout.hide;

b) Create an OnClick event for mmAbout as follows:

pAbout.show;
pAbout.bringtofront;
pAbout.align:=alClient;
bpAboutOK.setfocus;

c) Use the object inspector to select bpAboutOK. (It doesn't matter if you have the panel minimized.)
Create an OnClick event which says

pAbout.hide;

And there you have it!

__________
An extension:

If you like to put version indicators into your programs, as you should, you can fool around with the
Lines property of mpAboutMemo each time the version number changes, or you can....

Select pAbout, set Align alNone.


Add an edit box. Call it epAboutVersion. Be sure it is in front of the memo. Make Autosize false,
Enabled false.

In the FormCreate procedure, add epAboutVersion.text:='Version 0.00';

(Labels don't work well for something like the Version field. They are always under controls (e.g. memos
or buttons) on the panel. Furthermore, unless their Transparent property is made True, they can blot each
other out. 'Sent to Front' still has a bearing, but only in 'stacking' the labels, all of which are under the
controls.)

http://sheepdogguides.com/dt2a.htm (4 of 5) [1/28/2005 3:44:18 PM]


Delphi tutorial: Menu, etc

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2a.htm (5 of 5) [1/28/2005 3:44:18 PM]


Delphi tutorial: File Handling

HOME > > > TUTORIALS TABLE OF CONTENTS / - - / - - / - - / - - - Other material for programmers

Delphi tutorial: Reading, Writing Files.


This has good information, and a search button at the bottom of the page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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


Simple File Handling.

This was first written long ago, originally in Delphi 1, for which it remains valid. In September 2002, I did the tutorial
myself, using Delphi 2, making a few "tidies" here and there. If you find problems, do please let me know!

First: What do I mean by file handling? (For those of you who already know... be patient.. I'm only going to spend a about
four paragraphs on this!)

A 'file' is something saved on a disc. Writing to a file is a bit like sending something to the printer. You have something in a
variable, and you want it written down somewhere. The 'something' can be of any type- string, byte, integer, record.
Continuing my analogy of printing as a way to understand writing to a file: Not only can you write to the file, but you can
also put your something anywhere in the file that you want it, as if you were able to specify where on the page printing
should occur. Often a file will be organised. The analogous piece of paper would have rows and columns marked on it, so
you could say: "Write (it) in the second column of the third row."

The 'file handling as printing' analogy becomes a little strained when you learn that not only can you 'write' things on the
'paper', but if you overwrite something written earlier, a perfect 'erasure' occurs first.

The 'file handling as printing' analogy becomes even more strained when you turn to consider reading from a file. Not only
can you write to a file, as discussed above, but you can also 'see' what has previously been put in any part of the file. Once
everything else is in place, you have something like

function GetNthStringFromFile(bN:byte):string;
begin
GotoRecord(bN);
GetNthStringFromFile:=ReadStringFromFile;
end;

(Only function, begin, :=, string, byte and end in the above are built in elements of Delphi, by the way.)

Not only can you write to and read from files, but you can also delete them, rename them, move them, copy them etc.

So... that's what filehandling is. Now on to doing it...

A warning: Delphi (version 1, anyway) seems to incorporate at least three systems of general file handling, and several
options for doing specific file related jobs. Furthermore, traditional file handling keywords are sometimes used for other
jobs. Built in to Delphi, for instance, we have: Close, CloseFile and FileClose! I am not going to do a comprehensive
review of Delphi's file handling. I am just going to give you some tools that can be used on almost any file handling job. At
the end, I will mention some of the built in options for specific jobs.

http://sheepdogguides.com/dt2b.htm (1 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: File Handling

Just to give this a focus, I will work up a 'High Scores' table, such as you will find in many games. I won't go into the details
of what game this high scores table serves. We will require that the high scores table be held in the file 'HighS.txt', in the
same directory as the game's .EXE file.

((( An aside: If you put HighS.txt and the game's .EXE in the same directory, the program will find it without hassle
UNLESS (Win95, at least), you've put them both on the desktop. However... you can put them both in any OTHER
directory, and put a simple shortcut to the .EXE file on the desktop, and all will be well.)))

The high score table will keep the top ten scores and the name of the player. The score will always consist of three digits.
The player name will always consist of 25 characters, though some right hand characters may be spaces. Each top player's
score + name is called a record. During most of the program's execution, the ten records in HighS.txt will also be available
in the array sSN (strings of Score-plus-Name). Each element of SN is a 28 character string. The first element (top score) is
element 0.

In outline, what we need for the game program is..

When game starts:


... if HighS.txt does not exist, create one, and leave it 'open'.
.....................(More on what 'open' means in a minute)
........else open HighS.txt
Copy what is in HighS.txt into the array sSN[0..9]
Repeat
....Let player have a go
....See if his score is higher than that in sSN[9]
....If it is, revise the array sSN and
.........write it to the disc, replacing the old HighS.txt
Until no one wants to play any more
Close the file (More on 'close' in a minute')
End the program

((Another aside: The 'write it to the disc' step could have been put after the 'until' if you wanted to save disc thrash... but that
would leave the program vulnerable to the sort of people who fail to exit programs by the intended route.))

First bit of good news: There is a built in function FileExists. You can just say if "FileExists('HighS.txt') then..." and the
program will do what you would expect.

((Aside: You may know enough to see that the following uses an elephant gun to shoot a mouse. My intention is to show all
of the elements needed for general file handling, not to devise the best possible High Scores handler.))

Now then... 'Open' and 'Close'. The program can't write to a file unless you say WHICH file. You don't want to say which
file every time you do anything with it, so the idea of a file type variables arose. Before you do any reading or writing, you
'open' the file. After that the file variable is your way of referencing the file when you want to work with it. (You can have
several files open at the same time, by the way.) NB: In the system of file handling in Delphi that I use, the word 'open' isn't
used to open the file. You either 'reset' it, or 'rewrite' (misleading) it. (Explanation of their differences: to follow.)

Get your Delphi fired up. Start a project DD02 (Delphi Demo), with a form DD02f1, unit DD02u1.

Get yourself into DD02U1.PAS's window.

Make the second line {$R+}. (If you want to know more about this detail... unrelated to file handling... look in the help file
under compiler directives.) NB::: DON'T turn the line {$R *.DFM} into {$R+ *.DFM}!! {$R followed by a file spec has a
completely different function, and putting the + in is disasterous!

Just after 'var' and 'DD02f1: TDD02f1;', add...

http://sheepdogguides.com/dt2b.htm (2 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: File Handling

df:file of byte; (*df for 'Data File'*)

Click on the events tab of DD02f1 in the Object Inspector. Double click on the empty field to the right of 'on create'. You
find your cursor is now in DD02U1.PAS's panel, between 'begin' and 'end' of the FormCreate procedure.

Enter....
assignfile(df,'HighS.txt');
rewrite(df);
closefile(df);

((Aside: I can NEVER remember if it is 'rewrite' or 'reset' I want for this... so I just type whichever comes to mind and do
ctrl-f1, and up comes the help file to tell me what I need to know! Don't forget ctrl-f1... use it often.))

Save your project.... do it often... reading and writing to files can do all sorts of wonderful things (crash system). THEN try
to run what you have so far. You'll only get a blank window, but if you do, all is well so far! End your program. (Alt-f4, or
the easier to use/ harder to describe Win95 or Win 3.x alternatives)

(Aside: either put a 'Quit' option in a menu, of if you're not happy with menus yet, make a 'quit' button... all the 'onclick'
handler needs to be is application.terminate)(I HOPE that's ALL you need. Can any expert confirm that Delphi cleans up
after sloppy programmers who terminate without first closing any files which happen to be open?)

After df:bytefile; add


sSN:array [0..9] of string[28];(*Score plus Name*)

After procedure TDD02f1.FormCreate(Sender:TOBject); add


var c1:byte;

Save project, run. Still... 'nothing' happens... just checking material added so far.

After rewrite(df); add

for c1:=0 to 9 do sSN[c1]:='00'+IntToStr(9-c1)+'-NoNameABCDEFGHIJKLMNOPQR';

Save, run.

We're now going to do something that isn't strictly necessary for file handling, but will help us debug this project. We are
going to do it the hard way, because I still don't know how to do it properly, i.e with watch/evaluate. We're going to put a
memo on our form so that we can see what is in each element of sSN.

Put a memo on the form. (The memo component is on the 'Standard' tab of the component palette.

Click on the TStrings beside the object's Lines property.


Replace 'Memo1' with 0. Press enter. Type 1, press enter, etc, until you have the digits 0 to 9 in a column in the String List
Editor window. Click OK. (No need to save).

Adjust size of memo on form to be more than big enough for the 0 to 9 vertically, and
000-NoNameABCDEFGHIJKLMNOPQR horizontally.

After sSN[c1]:='00'+IntToStr(9-c1)+'-NoNameABCDEFGHIJKLMNOPQR' add

for c1:=0 to 9 do Memo1.lines[c1]:=sSN[c1];

Save project, run. At last it does something you can see! Add the following just before the "closefile(df)..."

http://sheepdogguides.com/dt2b.htm (3 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: File Handling

for c1:=0 to 9 do WriteLineToFile(sSN[c1]);

Before you can run that, you need to provide a WriteLineToFile procedure.

Just after the var c1:byte; near the start of procedure TDD02f1.FormCreate... add:

procedure WriteLineToFile(sTmp:string);
var c1,c2:byte;(*Don't try to do away with any of the three uses
........of c2... the complier won't like it!*)
begin
for c1:=1 to length(sTmp) do
begin
c2:=ord(sTmp[c1]);(*sTmp[2] returns the second character of the string sTmp*)
write(df,c2);
end;
c2:=13;write(df,c2);(*This plus next will allow editing datafile*)
c2:=10;write(df,c2);(*with Notepad, which is sometimes useful*)
end;

(*Notepad files do not always have the 13/10 pair after the last line, by the way.*)

If you load HighS.txt into Notepad, you should see a bunch of lines consisting of a number and a hyphen followed by
'NoNameABCDEFGHIJKLMNOPQR'.

So far so good! Go make a cup of coffee- you deserve a break.

We have to go back to 'rewrite' and 'reset'.

Assign(df,'HighS.txt');rewrite(df); WILL open a file called HighS.txt. Unfortunately, if there is already a file of that name,
the old file will be destroyed in the process... not very helpful if you want the people who had high scores last time to still
show in the table the next time the program is run!

First, we'll fix things so that if there isn't a HighS.txt already, the program will make one. Just after the existing 'Assign(df...'
line, add

if not FileExists('HighS.txt') then begin


.... and just before the existing 'closefile(df);' put
end (*no ; here*)

And immediately following the "...end (*no ; here*)", above, you put in the following, which reads the old HighS.txt if
there was one:
else begin
reset(df);
for c1:=0 to 9 do sSN[c1]:=ReadLineFromFile;
for c1:=0 to 9 do Memo1.lines[c1]:=sSN[c1];
end; (*else*)

Again, you'll have to add the ReadLineFromFile function before the program will run. It can go just before 'procedure
WriteLineToFile..'

function ReadLineFromFile:string;

http://sheepdogguides.com/dt2b.htm (4 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: File Handling

(*Not a very generalised read: Assumes 28 byte strings followed


by two 'waste' bytes*)
var c1,c2:byte;
sTmp:string;
begin
sTmp:='';
for c1:=1 to 28 do begin
read(df,c2);
sTmp:=sTmp+chr(c2);
end;
read(df,c2);read(df,c2);
ReadLineFromFile:=sTmp;
end;

Once that appears to be working, you can do the following test:


Run the program once, then quit it.
Load HighS.txt into Notepad.
Change the first character to 'X'. Be sure you CHANGE the first character, don't just ADD an X... the line must have the
same length after the change as it had before it.
SAVE the new HighS.txt (from Notepad).
Run your program again... you should see 'X09-NoName...' as the first line.
Delete HighS.txt
Run your program again.
You should once again have a 'clean' HighS.txt.

That pretty well covers the essentials. For the game, of course, you would have to get the array sSN updated any time
someone achieved a new top ten score, and then execute

assignfile(df,'HighS.txt')
reset(df);
for c1:=0 to 9 do WriteLineToFile(sSN[c1]);
closefile(df);

It is important to match your reset/rewrite statements with closefile statements. Delphi is pretty forgiving about programs
closing while files are still open, but the situation is best avoided. It is NOT a good idea to do a new assign(df,'') if you have
not done closefile(df). You can re-reset a file. If you were to rewrite a file which had had things done to it already, those
things (and anything else already in the file) would be lost.

It is also important not to have any extra closefile(df)'s. One solution is to declare a variable called boFileOpen. Set this
false in OnFormCreate. Set it true when the file is opened. Then you can have closefile(df)s whereever you might need
them, but put them in...

if boFileOpen then begin


closefile(df);
boFileOpen:=false;
end;
... but you shouldn't need this in a simple program. You should know if the file is open!

Time for another break!

In the above, we assumed that the file would consist of exactly 10 strings, each 28 characters long, each (including the last)
followed by two bytes we weren't using. Life is seldom so simple!

http://sheepdogguides.com/dt2b.htm (5 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: File Handling

Happily, there is a function called eof (End Of File).

If I get sufficient encouragement from feedback from THIS tutorial, I may write up a more obscure, but more generalised,
routine for reading from a file into the elements of an array. Something like the following would do to read a very short
string of characters into a string type variable:

assignfile(df,'Short.txt');
reset(df);
sTmp:='';
repeat
read(df,c1);
sTmp:=sTmp+chr(c1);
until eof(df);
closefile(df);

Implicit in the preceeding is the fact that eof becomes true WHEN you read the last item in the file. You don't have to TRY
to read PAST the end of the file to make eof return true.

Other useful words you should know about are seek(df,n), FilePos(df), FilesSize(df). There are entries for each in the help
files. In the Delphi 1 help file, look under 'I/O Routines'. (The section on 'File-management routines' takes you into a whole
other system of reading and writng files. Some of the things there (e.g. FileAge) are useful, and won't clash with the things
already explained. Others will, e.g. FileClose. Stay away from things involving an integer type parameter called a handle.)

Seek is particularly useful. It allows you to move to a particular point in the file for your next read or write. Rewrite and
Reset both perform a seek(df,0), i.e. if you read or write after either, you will read or write at the start of the file. (As rewrite
erases any existing file, any write would have to be at the file start, and no read would be possible.) Read and write both
move the pointer forward, as you can tell from the fact that our program worked.

The following would tack an 'A' onto the end of a file. From it, I hope you can see how to use seek to append something to
an exisiting file.

if fileexists('Short.txt') then begin


assignfile(df,'Short.txt');
reset(df);
seek(df,FileSize(df));
c2:=65;(*Ascii for 'A'*)
write(df,c2);
closefile(df);
end;(*fileexisits*)

Things to avoid: You may have to shut down your machine and re-boot if you do the following:

assignfile(df,'HighS.xxx');read(df,c1);
(Attempt to read from a nonexistent file AND without a reset or rewrite before the read.) Having {$R+} at the start of the
unit won't save you from the crash. Even adding reset(df); won't help if the file does not exist. You should have an explicit
FileExists('HighS.xxx') test before any reset call.

Pascal type strings(the ones I've been using, as opposed to pChar type strings (topic for a whole other tutorial!) can only be
up to 255 characters long. You may get away with a file access which results in something equivalent to...
sTmp:='';

http://sheepdogguides.com/dt2b.htm (6 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: File Handling

for c1:=0 to 500 do sTmp:=sTmp+'X';.......


... but I wouldn't recommend letting the situation be possible.
{$R+} won't catch it, by the way. Even if you declare a type string80=string[80]; and declare sTmp to be of that type, even
with {$R+} in effect, the program won't complain. (It won't crash every time, though! Still best avoided!)

{$R+} won't catch: var c1,c2:byte;c2:=250;for c1:=0 to 100 do inc(c2);


This is because range checking isn't applied to the inc (and dec) functions. Replace inc(c2) with c2:=c2+1 to obtain range
checking. I'd guess there's an execution speed penalty, but it will probably be worth it, except maybe in an inner loop that
executes many many times.
{$R+} will, however, catch
var s:array[0..5] of byte;
c1:byte;
begin
for c1:=0 to 20 do s[c1]:=123;

Now I'll show you something more, using a fanciful example. Suppose you wanted to take file 'In1.txt' containing
'ABCDEF' and file 'In2.txt' containing '123456', and from them create file'Out.txt' consisting of 'AB12CD34EF56'. Surely,
we can have one 'get two characters from file' function, and use it to look at either of two (or more) input files? (Yes, we
can.) Notice also that this program doesn't assume that you will have the whole of any of the files involved in the computer
at any time.

I'm not going to build the whole thing up bit by bit. The following is the heart of it all. Tell me if you find any errors or
difficulty in working it up from the indications here.

procedure TDD03f1.FormCreate(Sender: TObject);


type ByteFile=file of byte;
var df1,df2,df3:ByteFile;
c1,c2:byte;
sTmp:string;
function ReadTwo(var df:bytefile):string;(*'file of byte' unacceptable. You have to
define a type, and use that*)
var sTmp:string;
c1:byte;
begin
sTmp:='';
read(df,c1);
sTmp:=sTmp+chr(c1);
read(df,c1);
sTmp:=sTmp+chr(c1);
ReadTwo:=sTmp;
end;
procedure WriteTwo(sTmp:string);
var c1:byte;
begin
c1:=ord(sTmp[1]);write(df3,c1);
c1:=ord(sTmp[2]);write(df3,c1);
end;
begin
assignfile(df1,'In1.txt');
assignfile(df2,'In2.txt');
assignfile(df3,'Out.txt');
reset(df1);
reset(df2);

http://sheepdogguides.com/dt2b.htm (7 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: File Handling

rewrite(df3);
for c1:=0 to 2 do begin
sTmp:=ReadTwo(df1);
WriteTwo(sTmp);
sTmp:=ReadTwo(df2);
WriteTwo(sTmp);
end;
closefile(df1);
closefile(df2);
closefile(df3);
end;

The programs we've looked at so far use "file of byte", and read or write single bytes one at a time. If the file consists only
of lines of text (like our High Scores project), you declare the file variable as type textfile, and then you can pick up a whole
line with readln(df,sTmp);

If the file consists entirely of lines of text, and you are content to have the whole file in memory at once, you can use
LoadFromFile, which is built in to Delphi.
Create a form with a memo called Memo1 (default name). Then do:

Memo1.lines.loadfromfile('SomeFile.txt');

If you have a file called SomeFile.txt, it will have been loaded into the memo.

If you want to work with .ini files, there is a whole bunch of tools for that. See the IniFiles Unit help for a starting point into
this topic. (You CAN do .ini files the way we did the High Scores, too, though.)

File handling is an important part of programming. I hope this tutorial has helped get you started. And my thanks to Eugene
V from St.Petersburg in Russia (I had an interesting visit to that lovely city in December 1984) for pointing out a little flaw
in this as originally published. It could have caused beginners some real headaches.

?????????????A mystery for the experts: I'd welcome an explanation, if anyone can provide one!

At one time, I was suggesting that near the start of this program you should have, just after the "end;" after the comment
"{public declarations}",

ByteFile=File of byte;
String28=string[28];

var
DD02f1: TDD02f1;
df:ByteFile;sSN:array [0..9] of string28;(*Score plus Name*)
That has now been replaced by the more transparent

{ByteFile=File of byte; This now gone}


{String28=string[28]; This now gone}

var

DD02f1: TDD02f1;
df:file of byte;

http://sheepdogguides.com/dt2b.htm (8 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: File Handling

sSN:array [0..9] of string[28];(*Score plus Name*)


Whatever possessed me to do things the more complicated way? What permitted me to establish ByteFile and String28 as
aliases for what I wanted? Both structures seem to work in Delphi1 and Delphi2. Ah well.. It's fixed now, and simpler is
always better... when it works!
A slight digression about converting between Delphi 1 and Delphi 2. I frst wrote this tutorial a long time ago, using Delphi
1. Because of a helpful reader pointing out a problem, I went through the tutorial myself, as a pupil. At the same time, I
decided to check it for Delphi 2 compliance. All was well, although there are things (not present in this program) which
need attention if you migrate a Delphi 1 program to Delphi 2, or vice versa.
After the Delphi 2 version was done, I decided to see if it would run in Delphi 1. I copied the DD02u1.pas, DD02u1.dfm
and DD02.dpr files to a machine with Delphi 1. In the Uses clause, Delphi 2 puts a unit named "Windows". For Delphi 1,
replace that with the two units named WinTypes and Win Procs.
I then tried to run the program and began getting messages about "line too long". You may or may not see htis. My
machines were behaving strangely at this point. I think what was happening is that the non-printing characters marking the
ends of lines had become confused. As few of us are going to do much Delphi 2 to Delphi 1 conversion, I'm not spending a
lot of time on this. I did, eventually, get the code of the delphi 2 version to run happily in Delphi 1, with only the change
mentioned already to the units listed in the uses clause.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar Top 200
Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay
my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi, and they
provide promotional services, too. Click the "Help get this site publicity" link above for more information.

http://sheepdogguides.com/dt2b.htm (9 of 9) [1/28/2005 3:44:23 PM]


Delphi tutorial: Using an old project as the basis of a new one (Level 2).

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial: Using an old project as the basis of


a new one (Level 2)
This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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


DT2c.. Using an old project to start a new one.

This may not cover all elements of the process, but it illustrates what I did on one occasion!

I had DD06 up and working well. I wanted to make a new program which was an adaptation of DD06.
The adaptation will be called DD07 here.

First I created a folder for DD07.


Then I got Delphi running, and did File|OpenProject, and opened DD06.

I then did File|SaveProjectAs, and when the first box came up, I changed to the DD07 folder, changed
the default DD06.dpr to DD07.dpr. (Only one thing SEEMED to need saving, but this was misleading...
Delphi was 'helpfully'(?) 'remembering' that the .pas file for this project was back in DD06's folder... not
what I had in mind!

To fix this, I clicked on the DD06u1.pas window, then did File|SaveFileAs, and changed the folder and
name of DD06u1.pas to DD07u1.pas, and ran the project again. That seemed to give me all the right
files, and the .exe file was now DD07.exe.

However, there were still references to DD06f1 in various places.

Next, I used the object inspector to change the name property of the form from DD06f1 to DD07f1.
N.B.... trying to edit the source code to change references to 06 to say 07 is not a good idea. And I re-ran
the program.

Now all references to DD06 seemed to be okay. If you referred to DD06 anywhere in comments that you
wrote, I doubt they would be changed... but neither would they prevent the program from running.
Perhaps now you might want to use Delphi's editor's search and replace, just to see if any references to
DD06 remain.

http://sheepdogguides.com/dt2c.htm (1 of 2) [1/28/2005 3:44:26 PM]


Delphi tutorial: Using an old project as the basis of a new one (Level 2).

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2c.htm (2 of 2) [1/28/2005 3:44:26 PM]


Delphi tutorial: Where To Put Things (Level 2).

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial: Where To Put Things (Level 2)


This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Once you have got started with Delphi, you will sometimes know what you need to add to a unit, but
have trouble getting it in the right place. This started as an answer to that, but as I wrote, I got too heavily
into another issue! I will try to re-edit this into more logical pieces one day... but rest assured... this does
eventually get to 'Where to put things', even if there is a (useful, I think) detour along the way!!! I think
this tutorial is less well structured than others, but I also think that there is important information in it,
worth the effort you will have to make to extract it. What do you think? (Both issues!)
__________

This discussion follows on from the level 1 tutorial called 'The Whole Picture', but you don't need to read
that now. That talks about all the elements of a Delphi project. This restricts its attention to units... the
'thing' you see when working on a form and the program code which determines its behaviour.

In syntax notation form (see below) a basic unit is nothing more than....

{unit heading} ; {interface part} {implementation part } end .

(I hope that whets your appetite for learning about syntax notation? And, by the way, a complex unit is
not much more complicated.)

Keep the basic 'skeleton' clear in your mind, and you will progress faster.

The following is an almost empty, parts named-by-Delphi-defaults unit. I have added the reference
points, (*1*), (*2*), etc.

.unit Unit1;(*1*)
.
.interface (*2*)
.
.uses

http://sheepdogguides.com/dt2d.htm (1 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

. SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,


. Forms, Dialogs, StdCtrls;(*3*);
.
.type (*4*)
. TForm1 = class(TForm)
. Label1: TLabel;
. procedure Label1Click(Sender: TObject);(*5*)
. private
. (* Private declarations *)(*6*)
. public
. (* Public declarations *)(*7*)
. end;(*8*)
.
.var
. Form1: TForm1;(*9*)
.
.implementation(*10*)
.
.{$R *.DFM}(*11*)
.
.procedure TForm1.Label1Click(Sender: TObject);
.begin
.label1.caption:='Clicked';
.end;
.
.end.

END OF ALMOST EMPTY DELPHI UNIT

This program would need a simple form. The form would have a label called Label1, which initially said
'Hi'. When you run the program, all it does is change the 'hi' to 'Clicked' if you click on it.

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;

http://sheepdogguides.com/dt2d.htm (2 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

... 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.
____________________
Much of your Delphi programming is as simple as adding the...

. label1.caption:='Clicked';

to the program above. Delphi takes care of all sorts of things for you, you just add 'what to do' between
the Delphi supplied 'begin' and 'end'
================
A short digression....

Help on help... This bit ought to ba Level 1 mini tutorial... for for now it goes here! The following
assumes you haven't used the 'find' tab of the help file viewer... and may still be relevant, even if you
have.

Imagine you are working on some program code. You are about to use a word, and you can't quite
remember the details. Type the word. You can leave the cursor at the end of the word. Press F1. The
computer will either bring up a page of help, or a dialog giving you several choices. All very like using
Help files in general, BUT!! BEWARE!! With Delphi there are a number of different help files. It is easy
to get yourself into ONE of them, and get the impression that there is no help on what you want to know.
The title on the help window you are viewing will tell you which help file you are in. If you suspect that
you are in the wrong help file, go back to the unit page you were on, put something different in, or just
move the cursor, and press F1 again. If you get the 'Search All window, you are 'up' to a more global
level, and are looking at all of the Delphi help files for whatever you need. When you select an item from
the list, you will frequently see a number of items relating to that topic. After each, in brackets, you'll see
an indication of which help file that entry would take you to.

You will find reading many of the help file entries easier and more productive once you understand the
syntax notation system (described here) which computer people have evolved over the years to allow
concise, unambiguous and comprehensive descriptions of what is and is not allowed in a language.

An enorourmous part of Delphi and Pascal (all of it, I suppose... certainly most of it) consists of blocks.

A block is...

{declaration part}{statement part}

Often, Delphi will take care of the declaration part for you. (The words in this section are all good search

http://sheepdogguides.com/dt2d.htm (3 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

keys in the help files, by the way.)

The statement part is.....

{simple statement}
or
{compound statement}

--------------
Simple statements are things like....

c1:=5

if c1= 5 then c1:=3 else c1:=5

inc(c1)

showmessage('Hi')

---------------
A compound statement is....

begin {statement} :+ ;{statement}+: end

Thus, the following ar legal compound statements:

begin c1:=5 end

begin
if c1=5 then c1:=3 else c1:=5;
showmessage('hi')
end

-----------
Happily, a statement can be nothing! This is happy, because it allows the following to be legal, too:

begin
if c1=5 then c1:=3 else c1:=5;
showmessage('hi');
end

There is an aditional semicolon in this version of the previous example... the one on the showmessage
line. Unless a statement could be nothing, that semicolon would be illegal.

LEARN THE ALLOWED SYNTAX. LEARN TO SEE THINGS IN SYNTAX NOTATION TERMS. If
you do, many, many, many tedious hours of trying to get some piffling little thing right will be saved.

http://sheepdogguides.com/dt2d.htm (4 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

Another, related, tip: If you're really stuck with something, print out the offending section. Draw circles
around the parts of what you have, starting with the innermost structures. The circles should never
cross... you will end up with circles (one or more) withing circles, within circles in a properly constructed
Pascal / Delphi program. If you see places where the circles do cross, you will be looking at the places
where your attempt at a solution has a problem!

==============================
And now, at last... Where to put things!!!

To create exemplary situations, I am going to create a tiny application with two forms. You don't need
two forms for many things, but there's no harm in introducing some of the issues now.

First of all (perhaps outside Delphi), set up an empty folder. Start a new project. We'll not bother with
fancy names for things, just use the Borland defaults. I'm doing this in Delphi 2, by the way... Delphi 1
users shouldn't find too many differences.

On the form that Delphi gives you, create a label. Caption it 'Hi'.

Save what we have so far.

Create a second form (File|New Form). Put a label on it. Caption it 'Bye'.

Create an OnClick handler for form1 which says...

form1.hide;
form2.show

Run the project. You'll get a message saying..

form1 references form2... not in Uses list... add?

Answer 'yes'.

This will put...

uses Unit2;

... into unit1.pas just after the word 'implementation', my refernce point (see simple program above)
(*10*)

We've added something! We've seen where it should go! Whenever you can, leave the work to Delphi...
but be sure you understand what is going on!

Run the program. Click on Hi. The first form will disappear, the second will appear. Click on the little x

http://sheepdogguides.com/dt2d.htm (5 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

in the upper right of the form and it will disappear... but your application is still runnning!!! (The first
form, though not currently visible, is still present on your machine.) Happily, there is an icon on the
taskbar which you can right click. Then click close.

For both forms, add an OnDestroy event handler consisting of...

application.terminate;

((PROBLEM::: At this stage, I am pretty sure that the application closed properly when I clicked the
little x in the upper right of either form. Later, the application went back to NOT closing when I clicked
on the little x of the second form. Do you get the same thing? Do you know why, how to fix it? ('Email
me' button at bottom!) Sorry about this loose end...)))

__________________
I like my programs to display a version number. We're going to set up a constant in unit1.pas which will
be available to both of the forms in the project.

In unit1.pas just after my refernce point (*3*) add...

const ver='1.00';

(Put it in apostrophes or Delphi will consider it to be type currency, and you want to use it as a string.)

Add another label to form1. Name it laVer

Add a OnCreate event handler to form1, and make it....

laVer.caption:='Version number: '+ver;

Add another label to form2. Name it laVer (Notice we CAN use the same name as we used earlier?)

Add a OnCreate event handler for form2, and make it....

laVer.caption:='Version number: '+unit1.ver;

When you compile, you'll get an error message. This is because unit2 doesn't know about the constant
declared in unit1 unless you tell unit2 to use unit1. You do this by adding...

uses unit1;

just after my reference point (*10*)

Why don't you put it up with the other uses items in the list ending just before my (*3*)? You could.. it
will work, if put there. However, to help your programs to develop smoothly, you try to keep the scope
of things no more extensive than necessary. (This is a big topic, worthy of a tutorial in itselt.. but for
now, just take my word for it!) The const ver='1.00'; had to go up in the interface section of unit1 so that

http://sheepdogguides.com/dt2d.htm (6 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

unit2 could 'see' it. Other units do not need to see that unit2 uses unit1, so that is placed down in the
implementatino section.

========================
Now we're going to look a bit at where and how procedures or functions should be added to Delphi units.
Just bear with me? We'll have a little 'learning by doing.' At first, some of the things I'm doing will seem
like overkill... but reasons will emerge. We will start with a little inches to meters converter.

Set up an empty folder. Start a new project. Let Delphi pick names, except as noted. Save the new project
to the empty folder.

Put two labels on the form, side by side. Name them laInchesHeader and laMetersHeader. Caption them
Inches and Meters

Under the first, put an edit box named edInchesInput, with text 0.

Under the other, put a label named laMetersOutput, with caption 0.

Double click on the edit box. Delphi will prepare most of the following, and the required forward
declartion near the start of the unit. You will need to enter the suff between the 'begin' and the 'end'.

. procedure TForm1.edInchesInputChange(Sender: TObject);


. begin
. laMetersOutput.caption:=
. floattostr(strtofloat(edInchesInput.text)/39.37)
. end;

Get that much working. NB/Beware: You need to keep the contents of the edit box a valid number at all
times to avoid an error our program is not robust enough to cope with.

Test data: 39.37 inches is one meter. 100 inches is about 2.5 meters.
__________________
Once that is working, change it to the following:

. procedure TForm1.edInchesInputChange(Sender: TObject);


. function Convert(si1:string;si2:single):string;
. begin
. Convert:=floattostr(strtofloat(si1)/si2);
. end;
. begin
. laMetersOutput.caption:=Convert(edInchesInput.text,39.37)
. end;

This is essentially the same as what went before, but we have created a 'new word in the language',
'Convert'. It is a function. In other words, when the program executes, and it comes to the line....

http://sheepdogguides.com/dt2d.htm (7 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

. laMetersOutput.caption:=Convert(edInchesInput.text,39.37)

everything to the right of the := simply results in a string. The string is calculated from whatever is in
edInchesInput.text at the time, and the 39.37 is used in the calculation.

Now add three more labels and one more edit box to your form, again in a square. This part of the form
will be used for converting between miles and kilometers. Name the edit box edMilesInput and the lower
right label laKMOutput. Double click on the edMilesInput editbox, and build the following. (You can do
most of it with a simple select/copy/paste)....

. procedure TForm1.edMilesInputChange(Sender: TObject);


. function Convert(si1:string;si2:single):string;
. begin
. Convert:=floattostr(strtofloat(si1)/si2);
. end;
. begin
. laKMOutput.caption:=Convert(edMilesInput.text,39370/(5280*12))
. end;

Now... it should occur to you that the two Convert functions present several puzzles:

1)Why have two identical things in the unit?

2)How does the program know which convert to use?

Answer to Q1: There is no good reason... other than this is a way to lead you to a more satisfactory
answer.

Answer to Q2: As the program stands now, each 'Convert' is LOCAL to a different procedure.

From either of the procedures, select all of....

. function Convert(si1:string;si2:single):string;
. begin
. Convert:=floattostr(strtofloat(si1)/si2);
. end;

Press ctrl-X... that is a quick way to do Edit|Cut

Move to just after the

. {$R *.DFM}

...which is just after the word 'implementation'

http://sheepdogguides.com/dt2d.htm (8 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

Press ctrl-V.. that is a quick way to do Edit|Paste.

Find the Function Convert... /si2);end; stuff in the other procedure and cut it out. be very careful to leave
the right 'end's in place! The implementation part of your unit should now consist of....

. implementation
.
. {$R *.DFM}
.
. function Convert(si1:string;si2:single):string;
. begin
. Convert:=floattostr(strtofloat(si1)/si2);
. end;
.
. procedure TForm1.edInchesInputChange(Sender: TObject);
. begin
. laMetersOutput.caption:=Convert(edInchesInput.text,39.37)
. end;
.
. procedure TForm1.edMilesInputChange(Sender: TObject);
. begin
. laKMOutput.caption:=Convert(edMilesInput.text,39.37*1000/(5280*12))
. end;
.
. end.

Get it working again!

See how one function can be shared by two parts of your unit? This not only saves you typing, but there
is only ONE place where errors can hide.
_____________________________
Confession: I couldn't think of a plausible excuse to do the following in the example we have developed
this far. Trust me, though... there will be times when you need the following techniques.

Suppose you wanted to refer to what is in edMilesInput.text from within the Convert function. For the
sake of this tutorial, add the two lines needed to make Convert into the following. (It won't compile.)

. function Convert(si1:string;si2:single):string;
. var siTmp:single;
. begin
. siTmp:=strtofloat(edMilesInput.text);
. Convert:=floattostr(strtofloat(si1)/si2);
. end;

(We never use siTmp, so in a real program the line would be pointless... but there will be times when you
want to use such a thing.)

http://sheepdogguides.com/dt2d.htm (9 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

If you try to compile it, you'll get an 'undeclared identifier' error message (Delphi 2. Similar, or same in
other Delphis, I would expect.)

This is because the edMilesInput object is unknown to Convert. EdMilesInput is outside Convert's scope.

There are two solutions.

You can tell Convert where to find the object by extending the name.

. siTmp:=strtofloat(Form1.edmilesinput.text);

will compile just fine. The only change is putting Form1. in front of the name of the object. We've left
Convert outside the Form1 object, and accessed part of Form1 through explicit naming.

The alternative is to make Convert part of Form1. That requires two changes. The function declaration
becomes..

. function TForm1.Convert(si1:string;si2:single):string;

(We've merely added the TForm1. (NB: *T*Form1 this time, merely Form1 (No T) under the other
approach.)

It is also necessary to include a copy of the above (one line only) in the interface part of the unit. As it
should be an exact copy, it is sensible to use select/copy/paste to create the copy. (The more you use
s/c/p, the more fluent you will become with this useful toll of RAD)

The copy should go just after the...

. private
. { Private declarations }

You will only need to put things in the 'public' part when you are dealing with more complex projects, by
which time you'll realise when to use the alternative. Putting things in the 'private' section restricts their
scope... always a good idea. Never give anything more scope than it needs.

==================
More on scope...

As you know, you cannot use a variable unless you have declared it. In the final stages of the exercise
above, we delcared siTmp (data type 'single') in the function Convert. We only needed it within Convert,
so it made sense to declare it within Convert. It cannot be used outside of convert... nor (which is more
the point) can it have any effect outside of Convert. As far as possible restrict the scope of variables.

An exception: I don't think I ever wrote a program which didn't have an sTmp variable. The 's' says, to
me and to anyone using the same conventions, that this is a string-type variable. (Delphi doesn't care

http://sheepdogguides.com/dt2d.htm (10 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

what you call your variables... but you will, when you try to read your programs!) The Tmp warns me
that anything I put in this variable is there temporarily.. I shouldn't, don't need to, worry about putting
new things in it, because I've agreed with myself not to put anything there that needs to be there many
lines later. Anywhere an sTmp appears in my code, it should have been initialised only a few lines
previously. The following is a pretty typical use of sTmp for me. (The code converts the number in score
to a string, and puts spaces in front of it to make the string at least three characters long... useful for
formating text in a monospace font.)

. sTmp:=IntToStr(bScore); (*Score is a variable with a value in it*)


. if bScore<10 then sTmp:=' '+sTmp;
. if bScore<100 then sTmp:=' '+sTmp;

With such a a variable, I don't mind giving the whole program a single sTmp which all parts of the
program can share, using and re-using it as often as need be. To make a variable available to a large part
of the program, you put

. var sTmp:string;

just after the {$R *.DFM} at the start of the implementation part of the program.

An exception to the exception: loop counters need to be declared within the procedure or function which
use them. I would like to declare a c1 similar to the sTmp just discussed, for things like the following
which makes a (weakly) encoded copy of a string...

. sTmp:='';
. for c1:=1 to length(sEnCodeThis) do
. sTmp:=sTmp+chr(ord(sEnCodeThis[c1])-1);

Unfortunetly, you aren't allowed to use a global c1 for this... it needs to be declared locally.
________________________
If you have a multi-form project, and you want something in a variable, say bScore, in one form, say
Form1, to be available to another form, say Form2, you need to put

. bScore:byte; (*NB NOT var bScore:byte;*)

just after

. public
. { Public declarations }

in the interface part of Form1. When you have done that, then in Form2 you can access bScore by calling
it Form1.bScore. (You might want to read that as "Form1's bScore".)

============================

http://sheepdogguides.com/dt2d.htm (11 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

The End

============================
Sorry... as I said at the start, I know this tutorial is badly organised, but it does present some improtant
information. I hope you will feel that whatever effort you have to make is rewarded.

=== notes to myself...

=== Important to do: Edit out to own turtorial: 'Syntax Notation'


=== Important to do: Edit out to own turtorial: 'Help with help'
=== Important tutorial to do: Scope.

HAPPY PROGRAMMING!!

----------------
___________________

=====================

Was the above of any use? Please send an email, at least. (If you would be interested in more tutorials
like this, say so. I'll try to remember to notify you if they become available.) For my idle curiosity...
Where are you, please? (City, state, country?)

Even better, download a piece of my software, try it and pass it on to someone?

Cheers, Tom Boyd

www.arunet.co.uk/tkboyd/offers.htm

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

http://sheepdogguides.com/dt2d.htm (12 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Where To Put Things (Level 2).

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2d.htm (13 of 13) [1/28/2005 3:44:30 PM]


Delphi tutorial: Syntax Notation (Level 2).

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for


programmers

Delphi tutorial: Syntax Notation (Level 2)


This has good information, and a search button at the bottom of the
page
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

Syntax notation:

Master this material, and you will be able to learn more from the Boland "Help" files. The material
covered is hard to explain, but not very hard to use... and it covers a powerful tool for describing what is,
and isn't, allowed in the language.

For a long time, computer manuals have been using things like "Enter DELETE &LT;name&GT;" as a
quick way to say "Press the D, E, L, E, T, E keys, and then the keys which make up the name of the thing
you want to delete. E.g. enter DELETE FRED, or DELETE TheUnwantedFile.TXT"

This is a fine and useful convention. Unfortunately, the people who invented HTML (the language used
to display web pages) dedicated the &GT; and < symbols to another use, and getting them to appear for
you (as they have in this section) is a real pain!

Therefor, in the following, I'm going to use the { and } in place of > and <. NB: In Pascal and Delphi, {
and } are alternatives to (* and *). I WON'T use { and } that way here!

BUT... at point (*11*) in the simple Delphi unit above, you will see {}. They should be there, as
themselves, not as substitutes for &GT; and <.
____________________
It is VERY USEFUL to learn to think of Pascal and Delphi code in the following terms:

A simple procedure declaration is made up as follows:

procedure {name}{formal parameter};


begin
{statement}
end;

http://sheepdogguides.com/dt2d1.htm (1 of 4) [1/28/2005 3:44:34 PM]


Delphi tutorial: Syntax Notation (Level 2).

Look at the TForm1.Label1Click procedure declaration in the example unit above.

TForm1.Label1Click is the procedure name.

(Sender:TObject) is the formal paramater.

label1.caption:='Clicked'; is the statement.

____________________
If you master this method of communicating, called syntax notation, you will have a powerful tool for
expressing or reading about complicated things in a very elegant manner. A lot of the best Pascal and
Delphi support, including the Borland supplied help files, uses syntax notation extensively.

It is so important that I am going to digress for a moment, and 'describe' a simple subset of English using
syntax notation. You might be amused to learn that I have written programs to generate whimsical
sentences using something like the following....

In my subset of English,

an article is 'A' or 'The'

a noun is 'cat' 'dog' 'brick' 'flower' or 'hand'

a verb is 'ate' 'bought' 'painted' or 'planted'

a sentence is....

{article}{noun}{verb}{article}{noun}.

With nothing more than the above, I've said that in my subset of English, the following are ALLOWED.
(Even if they don't make sense!)

"A cat ate a flower."

"The hand painted a brick."

"The brick planted the dog."

... and so on.

Even now, we have a pretty powerful tool. But it gets better!

If we say that putting something between two |s we are saying it is optional, we extend the tool to allow
things like....

a sentence is....

http://sheepdogguides.com/dt2d1.htm (2 of 4) [1/28/2005 3:44:34 PM]


Delphi tutorial: Syntax Notation (Level 2).

|{article}|{noun}{verb}||{article}|{noun}|

NOW, in addition to the sentences which were allowed previously, the following become possible:

"Cat ate."

"A cat ate."

"A dog painted brick."

"Dog painted a brick."

LASTLY... we build in the power of recursion. If I write an element thus..

:+element+:

it will mean that it may appear not at all, or once, or many times. (I'm afraid :++: are non-standard
punctuation marks forced on us by the limitations of HTML, too. Sorry.)

Now we can define a "compound sentence", which is....

{sentence} :+and {sentence}+:

which makes possible:

"A cat ate a flower and the hand painted a brick."

"A cat ate a flower and the hand painted a brick and the flower ate dog."

... and so on.

Just using

{sentence} |and {sentence}|

would have only made possible two phrase sentences.

(The logical among you... and logical you must be if you are to program without tears... will have notice
that I've been sloppy about the matter of the period at the end of a sentence. It could be dealt with... but I
didn't want to!)

Now you have a powerful tool available. Good news: In other reference sources, where the author has
diagrams available, you will find a graphical alternative to my |s and :+{thing}+:s.... which make reading
the syntax notation child's play, once you get the hang of it.

http://sheepdogguides.com/dt2d1.htm (3 of 4) [1/28/2005 3:44:34 PM]


Delphi tutorial: Syntax Notation (Level 2).

=====================

Was the above of any use? Please send an email, at least. (If you would be interested in more tutorials
like this, say so. I'll try to remember to notify you if they become available.) For my idle curiosity...
Where are you, please? (City, state, country?)

Even better, download a piece of my software, try it and pass it on to someone?

Cheers, Tom Boyd

www.arunet.co.uk/tkboyd/offers.htm

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2d1.htm (4 of 4) [1/28/2005 3:44:34 PM]


Delphi tutorial: Command Line Parameters, an alternative to .ini, registry.

Delphi tutorial: Command Line Parameters, an


alternative to .ini, registry.
HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Using Command Line Parameters


I was writing a program to display datafiles of stock prices.
I had many files, all of the same format, all in the same folder. For this, you can imagine just a sample:
IBM.HIS, HPCO.HIS and DIS.HIS.
The program starts by asking which data you want to see. If you type 'DIS', you get the stock prices for
Disney, from the file DIS.HIS
I did not want my program to need to use an .ini file or the registry, but I did want a way to tell it where (in
what folder, aka directory) to look for the data, without having to put that information each time I ran the
program, and without having to have the path hard coded into the program.
I was prepared to hard code a default location for the data. However, in addition to that, I wanted it to be
possible for the user to tell the program to look in another place by using a 'command line parameter'.
(Hereinafter called a clp.)
Before I go into the programming of this tutorial, let me just expand on the idea of using clps. For
simplicity, I'll work with a more simple case. Suppose you had a program for displaying the contents of a
text file. It would be possible to write it so that the text would be displayed in a 10 point font if you used a
clp of 10, or 18 point font if you used a clp of 18, (and so forth).
__________
In Win3.x you would either modify an existing program manager icon, or set up a new one in the usual
way: Program manager |File |New |Program Item. If you are modifying an existing icon, within Program
Manager you select it, then use File| Properties to access the Program Item Properties dialog. You add
command line parameters (clps) to the end of the file's command line property. We'll see in a moment how
the program can look at what you've put there. Don't try it yet.
__________
In Win 95 and 98 you can only (as far as I know!) use clps with shortcuts to programs, but this doesn't
seem like a particular nuisance. In both, first create the shortcut. Then right click on it, then click
properties. In 95, you select the 'program' tab and add the clp to the designated 'cmd line'. In 98, you add
the clp to the 'target' line of the shorcut. In some circumstances, it seems that you need to put the program

http://sheepdogguides.com/dt2e.htm (1 of 5) [1/28/2005 3:44:37 PM]


Delphi tutorial: Command Line Parameters, an alternative to .ini, registry.

designation in quotes, with the clp coming after, e.g.


"C:\Windows\notepad.exe" C:\MyText.txt
(The example given would create a shortcut which would launch Notepad loaded with MyText. Does
anyone know how, in Win3.x, to cause Notepad to launch with wordwrap turned on?)
__________
Anyway... back to our story...
Write a small text file in C:\. Call it TMPDD08.txt
Start a Delphi project. Put a memo on the form.
Set up....
procedure TForm1.FormCreate(Sender: TObject);
begin
memo1.lines.loadfromfile('C:\tmpdd08.txt');
end;
(You might also want a 'quit' button which executes application.terminate)
When you run this, you should see your text appear in the memo.
Once that's working...
Just after the loadfromfile line, add...
memo1.font.size:=strtoint(InputBox('Font Size Selection', 'Font size?', '12'));
(When you run the program, it will complain if you enter something silly, but this tutorial isn't about error
trapping.)
The program should now allow you to specify the size you want used to display the text. You still have to
type in your requirement each time the program runs, though.
Now replace the memo1.font.size... line with the following two lines...
if paramcount>0 then
memo1.font.size:=StrToInt(paramstr(1));
AND (before you try to run it) put 18 in as a parameter using Delphi's Run| Parameters menu item. (This is
just a quick, easy, way to see how the program would run from an icon or shortcut with a clp specified.
Once you get the program running under the IDE (i.e. with Delphi's Run command), you can try running
the program from outside Delphi if you want to. You don't even have to close Delphi down.)
Now when you run the program, the memo should appear in an 18pt font. Change the size specified, just to
be sure you're seeing the result of the parameter you have set.
Now, backtracking a little, what was all that code about?
paramcount is a function. It returns the count of clps which were present when the program was run.
paramstr(1) returns the first clp. You can use paramstr(2), (3), etc if you have more than one clp.

http://sheepdogguides.com/dt2e.htm (2 of 5) [1/28/2005 3:44:37 PM]


Delphi tutorial: Command Line Parameters, an alternative to .ini, registry.

So far so good, I hope?


_______
We're now going to return to the original objective: setting up a program to fetch files from a default
location if there is no clp, or if the clp points to a place without the required type of file, or from a clp
specified location otherwise.
You can use different locations and filenames if you wish, but for this tutorial, I'm going to make the
extension of the target files DD8. The clp-specified location will be C:\TEMP\ and the default location will
be C:\ Note that for the tutorial you should put the data files in a different directory than the .exe file just in
case something works, but not for the reasons you think! (In use, the system doesn't mind if the data shares
the .exe's folder.)
Create a two test data files...
C:\tmp1.DD8 containing 'This came from C:\'
C:\TEMP\tmp1.DD8 containing 'This came from C:\TEMP'
(You can delete TMPDD08.txt; we won't need it again)
Make the following changes to your Delphi program:
Just after the {$R *.DFM} after 'implementation', add
const DefaultPath='C:\';(*must end with \*)
var sDataPath:string;
Make FormCreate (in it's entirity, i.e. remove earlier code in it)...
sDataPath:=DefaultPath;
memo1.lines.loadfromfile(sDataPath+'tmp1.DD8');
... and get that much running.
Use Delphi's Run| Paramters menu item to set up C:\TEMP\ as the clp. (Don't miss the second \)
Add....
if paramcount>0 then sDataPath:=paramstr(1);
..... to the program, just after the sDataPath:=... line.
Now when you run the program, your other tmp1.DD8 should appear in the memo box.
______
That gives us most of what was required. However, the program needs to be made more robust, more
user-friendly.
The program will be changed so that it only uses the clp designated folder if there is suitable data there. For
the purposes of this, we will define 'suitable' as having a .DD8 file name extension. (This was the reason I
chose that 'odd' extension.)
Just after the....
if paramcount>0 then sDataPath:=paramstr(1);... add....

http://sheepdogguides.com/dt2e.htm (3 of 5) [1/28/2005 3:44:37 PM]


Delphi tutorial: Command Line Parameters, an alternative to .ini, registry.

if sDataPath[length(sDataPath)]<>'\' then sDataPath:=sDataPath+'\';


(*preceeding saves user who forgets terminal \ in path designation*)
if not fileexists(sDataPath+'*.dd8') then begin
showmessage('No .DD8 files found in folder '+sDataPath+
'. Trying default.');
sDataPath:=DefaultPath;
if not fileexists(sDataPath+'*.dd8') then
showmessage('No .DD8 files found in folder '+sDataPath+'.');
end;
(If your program cannot run without a data file, you need to add code to handle the error that occurs if
neither the default folder nor the clp-designated folder hold suitable files.)
Clps are a great alternative to .ini files and the Win95 registry. I don't like receiving programs that 'do
things' to my system, so I try to avoid putting such 'features' in programs I sell. With clps, I can write a
program so that it will run on a customer's machine without 'doing things' to it until he/she has decided that
he wants to allow the changes. The 'you may do things' instruction can be put into a clp to save the
customer having to answer 'May I...?' repeatedly. Clps can also be used to configure software in a relatively
permanent and convenient manner. For example, I have some arithmetic games. A parent or teacher can
have one copy of the program, but two shortcuts. Using the first shortcut entails a clp which causes the
program to give easy questions; using the other causes the program to give hard questions.
Floreat clps!

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However..
this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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


Here is how you can contact this page's author, Tom Boyd.

http://sheepdogguides.com/dt2e.htm (4 of 5) [1/28/2005 3:44:37 PM]


Delphi tutorial: Command Line Parameters, an alternative to .ini, registry.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2e.htm (5 of 5) [1/28/2005 3:44:37 PM]


Delphi tutorial: TTimer component, Event Driven Environments.

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial: TTimer component, Event Driven


Environments
This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

This is a simple little program, but it may help you become more familiar with an aspect of Windows
which I'm still getting to grips with myself. Windows is a multi-tasking, event driven environment.

The program is a timer... I am writing this to use, as well as to illustrate things for you. The user will
specify a time interval, and after that interval, the program will cause the computer to beep. N.B.: If you
want to use this program 'for real', you may have to deal with issues arising from your power save and
screensaver.

The timer won't be very sophisticated. There will be an 'hours' edit box and a minute edit box. The user
clicks a 'start' button, and the countdown begins.

Set up a folder, as usual. I used one called TM13 (My 13th TiMer program.)
Start Delphi, do File| New Project. Put a button on the form. Name it buStart. Make the caption Start.

Do File| Save project. First you have to answer the 'Save Unit1 As' questions. Make the file name TM1F1
and be sure to save it in the directory you created for the project. Next you have answer the 'Save
Project1 As' questions. Call it TM13.

Add two edit boxes. Name them eHrs and eMin.

Add a label. Call it laMinLeft.

Click on the form. Then go to the object inspector. Click on the Events tab. Double click on the cell to
the right of the label saying 'OnCreate'. You will find that your cursor jumps into the TM13F1,PAS
editing window, between the 'begin' and 'end' of 'procedure TForm1.FormCreate(Sender: TObject);'
which Delphi has just helpfully created for you.

Enter:
eMin.text:='10';
eHrs.text:='0';

http://sheepdogguides.com/dt2f.htm (1 of 6) [1/28/2005 3:44:41 PM]


Delphi tutorial: TTimer component, Event Driven Environments.

This will make the program start with a default 'time to time' of 10 minutes.

Now for a tricky bit!

Click on the form's eMin edit box. Go to the events page of the object inspector and doubleclick in the
cell beside eMin's OnChange.

Enter the following, which looks strange, but is only a start!

if eMin.text<>'' then
laMinLeft.caption:=IntToStr(StrToInt(eMin.text));

(Save what you've got so far.)

What is all that?? It is something that will happen whenever the contents of eMin.text changes... for
whatever reason.

The if eMin.text<>'' part is to stop the program having problems if you change the eMin text to be
nothing. This isn't robust or thorough error trapping, but it is better than nothing. This is, after all, a
beginner's level tutorial!

Always study odd code from the 'inside' out. In this case, the first thing to look at is the

StrToInt(eMin.text)

It turns a STRing (eMin.text) inTO a number (of type INTeger)... IntToStr... get it? (I usually just write it
inttostr, which works fine, but is harder to read.)

However! laMinLeft's caption must be data of type string. (Why does an edit box have 'text', but a label
has a 'caption'? Don't know.)

So... and the reason for this WILL become clear, I promise, we take the thing we made into an integer
and turn it back into a string with IntToStr(thing-we-already-dissected).

Get that much running. When you change the contents of the eMin edit box, you should see
coresponding changes on the laMinLeft label.

Now revise the eMinChange procedure to make it....

procedure TForm1.eMinChange(Sender: TObject);


var iMinsFromHrs:integer;
begin
iMinsFromHrs:=0;
if (eHrs.text<>'') and (eHrs.text<>'eHrs') then iMinsFromHrs:=60*StrToInt(eHrs.text);
if eMin.text<>'' then
laMinLeft.caption:=IntToStr(iMinsFromHrs+StrToInt(eMin.text));

http://sheepdogguides.com/dt2f.htm (2 of 6) [1/28/2005 3:44:41 PM]


Delphi tutorial: TTimer component, Event Driven Environments.

end;

Save your typing. Get the program running. All it should do so far is to get the laMinLeft caption to
reflect the settings in the two edit boxes.

The 'and (eHrs.text<>'eHrs')' part of the IF statement is needed because when the program first runs, the
eMin.text:=10 in the form's OnCreate causes execution of the eMin OnChange event. At that time,
eHrs.text is 'eHrs', which will cause StrToInt(eHrs.text) to complain! (There are simpler ways around this
that I might use in real life, but while doing the tutorial doing it this way has advantages.)

Now we need an OnChange event handler for the eHrs edit bos. It will be similar to the one we've just
done. See if you can devise it before reading the answer below....

procedure TForm1.eHrsChange(Sender: TObject);


var iMinsFromHrs:integer;
begin
iMinsFromHrs:=0;
if (eHrs.text<>'') then iMinsFromHrs:=60*StrToInt(eHrs.text);
if eMin.text<>'' then
laMinLeft.caption:=IntToStr(iMinsFromHrs+StrToInt(eMin.text));
end;

So far so good! We've already been using events... but in fairly simple, obvious, ways.

Put a 'Timer' on your form. You'll find it on the system tab of the Component Palette. (It looks like an old
fashioned clock face.) Delphi's name, Timer1, will do fine. Add Timer1.enabled:=false; to the form's
OnCreate procedure.

Make an OnClick handler for buStart. (You do this as you make OnChange handler's for the edit boxes.)
It should say....

Timer1.enabled:=true;

The timer is a pretty primitive component: only four properties and one event, and nothing visible
appears on the form during the program's execution. Even so, it has it's uses!

Make Timer1's OnTimer event be...

http://sheepdogguides.com/dt2f.htm (3 of 6) [1/28/2005 3:44:41 PM]


Delphi tutorial: TTimer component, Event Driven Environments.

laMinLeft.caption:=IntToStr(StrToInt(laMinLeft.caption)-1);

... save your work, run it. Once you clear up the typos, if you click on the 'Start' button, you will see the
number in laMinLeft count down about once a second. Why? I'll tell you.....

Whenever the timer's enabled property is set to true, the timer is counting down from a starting value.
When the timer counts itself down to zero, the OnTimer event is triggered. In our program, we set that up
so that it would look at the number in laMinLeft.caption at the moment, and replace it with that number
minus 1.

You change how often the Ontimer events occur by changing the timer's interval property. Try it at 200.
That will cause an OnTimer event every 200 milliseconds (5 times per second). To make the program
count down in minutes, make the interval 60000. (This is about as high as you can make it, by the way.)
While debugging the program, you'll want to set it lower.

Now add more to the OnTimer handler, after the line already there:

if laMinLeft.caption='0' then begin


timer1.enabled:=false;
form1.color:=clRed;
end;

That's it! The program now does what it was supposed to. Sorry about the failure to have it make a noise
at the end of the timed period, but that is more trouble than you might expect! There are notes about it in
the Level Two 'How To.. section.

I hope you now have a better feeling for the use of the timer, and an idea of what it is good for. NB: It is
a Very Bad Idea in Windows to have something like

for c1:=0 to 10000 do sTmp:='pause a moment';

You shouldn't create loops which will tie up the system, especially loops which are only there to create
an idle time during the program's execution. Any long loop should have application.processmessages in
it, to allow Windows to keep up with variaous housekeeping. For example, if you were adding all the
numbers between 1 and 1000, you'd do something like...

var wC1,wCount:word;
begin
wCount:=0;
for wC1:=1 to 1000 do begin
wCount:=wCount+wC1;
appplication.processmessages;
end;
end;

_________

http://sheepdogguides.com/dt2f.htm (4 of 6) [1/28/2005 3:44:41 PM]


Delphi tutorial: TTimer component, Event Driven Environments.

Just before we finish, there's another issue you need to know about.

If you do...

Timer1.enabled:=false;
Timer1.enabled:=true;

... then Timer1.interval milliseconds later, the timer's event will be triggered. I am not aware of any easy
way to see how much of the interval has passed before a moment when you make enabled false. I am not
aware of any easy way to 'use the unused part' of a previous, prematurely halted, countdown.

If you want, say, to give a pupil 30 minutes for a task, but to provide a 'pause' button which will 'stop the
clock' if necesssary, then the way to do that would be to use a timer to time the passing of minutes (or a
smaller unit), and use the timer's event to count how many minutes have passed with the counting not
paused.

If you look at the contents of the timer's interval property, it will always give you the full time of one
timeout, regardless of how recently the timer was last enabled. In other words, the countdown occurs in
some other place, which isn't (afaik!) available to you.

_________

That's it for this tutorial. Hope you found bits useful. The program has many faults... for example, if you
click start a second time after the first period expires, the program doesn't behave.... but the program
shows what it was meant to.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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.

http://sheepdogguides.com/dt2f.htm (5 of 6) [1/28/2005 3:44:41 PM]


Delphi tutorial: TTimer component, Event Driven Environments.

Link to Tutorials main page


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2f.htm (6 of 6) [1/28/2005 3:44:41 PM]


Delphi: Some sourcecode to peruse.

HOME - - - - - Delphi Tutorials TOC - - - - - - - - - - - - Other material for programmers

Delphi: A small illustration: Reading Skill Exerciser


This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

Click here if you want to know more about the source and format of these pages.
This tutorial is accompanied by the full sourcecode for a program that allows a user to exercise an
important reading skill. The program displays a number of words on the screen... but only briefly. It then
puts another word on the screen, and asks the user whether that word was in the list of words displayed
previously. The number of words shown can be altered, as can how long they are displayed.

Zipped sourcecode for the program discussed here.


Zipped .exe of the program discussed here.

Within the sourcecode there are illustrations of how to achieve things with Delphi. You already know
what the user needs to know about the program's operation. Now I'll turn to aspects of the program which
would only interest a programmer.

In a fit of laziness, I decided to hold the program's vocabulary in a memo. There's just one word on each
line. The memo is hidden, so the user will not be aware of it. This was perhaps not the most elegant way
to hold the words, but it does give you a chance to see memos at work. By the way: This program is not
intended as a commercial product in its current form. A commercial product, for example, would need a
way to change the vlist from which displyed words were drawn. For the sake of this "how to program"
demonstration, the words were put into the memo "at design time". In other words, I used the Object
Inspector to access the Lines property of the memo. Clicking on the [...] at the right hand end of the Lines
item brings up Delphi's String List editor. I typed the words I wanted, one to a line, and clicked 'OK'. I
set the memo's WordWrap property to false. During the programs's FormCreate I say memo1.hide. Job
done; words available!

The program starts up poised to go, and there's a "Go" button to start it running as soon as the user is
ready to proceed with the exercise. There's a menu with a way to change how long the words appear, and
to change how many words appear in each set..

Once "Go" is clicked, the following happen:


Words are selected to be displayed.
A word is selected to be presented in the "Was <word> shown?" question.
The words are displayed for a period of time controlled by a timer.
Once the words disappear, the question is displayed.
As soon as the user responds, feedback and the next problem appear.

http://sheepdogguides.com/dt2h.htm (1 of 5) [1/28/2005 3:44:45 PM]


Delphi: Some sourcecode to peruse.

This continues until the user clicks on the "Quit" button... which terminates the program. (Another bit of
crudeness you would improve in a commercial version.)

Let's look at details of some of those stages. You might want to look at the sourcecode as we go through
these points.

Note how when "Go" is clicked, the "Go" button is hidden. Just a minor bit of tidiness, but it is worth
managing things thus. It makes no sense to have a "Go" button available when the program is already
Go-ing. One school of thought would say that rather than use buGo.hide;, I should have used
buGo.enabled:=false; That leaves the button visible, but greyed out. Both approaches have their place. I
would lean more towards the enabled:=false approach when there are circumstances in which the button
might again become available. Having it visible but greyed out tells your user that sometimes "Go"ing is
an option, but not at the moment. In the program we are considering, you never "Go" again after the first
click on that button.

The event handler for buGoClick is only about 8 lines long. This means you can study it easily, there isn't
too much to assimilate, it is too exposed to provide many hiding places for bugs. So how does it achieve
so much? The "secret" is in the little word "ChooseAndDisplayWords". That's quite an involved
business, and one that we'll need again later, so it is a good idea to parcel it up in a discrete procedure.
Learning what should and what should not be put in procedures is an important part of mastering the art
of programming in Delphi, and other languages. Good use of procedures and functions is also a valuable
mental discipline, forcing you towards having a clear idea of what is required from each part of your
program.

In the case of this program, the job of ChooseAndDisplayWords is to pick the words that are to be
presented for reading, pick the word that the user is going to be asked "Was it in the list?", make a note
of whether the word is or is not in the list, and put the words on the screen. Depending on your
background, you may need to become "reckless" with variables. If in doubt, use another variable!

By the way: I'm not sure I could have written ChooseAndDisplayWords less elegantly. It does the job
there's certainly nothing pretty about the algorithm!

Going back to the variables filled during ChooseAndDisplayWords: The words in the list are put into
saWordsInQues[1..n]. ("sa" for "string array". If you don't understand arrays, you need to! This program
makes some use of them, for instance in the line that says...
for c1:=1 to bPossWordMax do saWordsInQues[c1]:='';
This empties saWordsInQues[1], saWordsInQues[2], saWordsInQues[3]... prior to their use. (Probably
unnecessary, as the program turned out, but in general a good idea.)) The program then puts words in an
appropriate number of the elements of saWordsInQues, checking along the way that no word is in the list
more than once.

ChooseAndDisplayWords puts the word for "Was it in the list" into sAskIfInList.

ChooseAndDisplayWords puts "true" in boWordInList if it was, and "false" there if it isn't.

And it puts the words on the screen. As long as ChooseAndDisplayWords accomplishes the above, we

http://sheepdogguides.com/dt2h.htm (2 of 5) [1/28/2005 3:44:45 PM]


Delphi: Some sourcecode to peruse.

don't have to worry about its innards. This is beautiful because


a) When we are looking at the main code of buGoClick, and at the other place where
ChooseAndDisplayWords is used, we are saved any distraction from the details,
b) If our sense of beauty is sufficiently offended, we can go back later and improve the code within the
procedure, without any concern about anything else in the program. The code could be re-worked by
someone who never had, never would see the rest of the program
c) If we choose to make the "list of words" something more sophisticated, that is certainly possible. In
fact, I intend changing the program so that instead of a random jumble of words, the user sees a sensible
sentence. ChooseAndDisplay words will become somewhat more complex to achieve this, but the
outside world will still only see the same simple outputs: What to display, what to ask about, and whether
that's in the stuff displayed.

So... moving on. Another part of "Go" was to start the timer. When the timer times out, the words to be
read disappear and the "Was <word> shown?" question appears. The timer is disabled, to prevent further
timeouts for the moment. eAns.setfocus is equivalent to clicking on the eAns edit box, which prepares
things for the user to enter "Y" or "N" to answer the question.

Then the program just sits there until the user presses some key. As soon as that happens, the eAns
OnChange event occurs, taking us to the code for that.

Again: The event handling code doesn't look like much... because a bunch of related matters have been
parceled up in CheckAns. Not just for tidiness, but again because all that stuff is needed twice.... once in
the handling of if the user typed "Y", and once in the handling of if the user typed "N". Notice that the
program is the perfect parent: The user can type (almost) anything, and the program will just ignore it...
unless it is "Y" or "N", the two sensible answers.

Details: The sTmp:=uppercase(eAns.text) at the start of the eAnsChange handler means that whether the
user types "y" or "Y", the program will behave as if the user typed "Y".
The eAns.selectall at the end of the eAnsChange handler is there so that when the user answers the next
question, that answer will overwrite any previous answer. The remmed out "eAns.text:='';" made sense,
and might have worked, but i was getting some inputs double counted. That may have arisen because
changing eAns within the eAns OnChange handler was asking for trouble, but I think there was some
unintended double use of sTmp in the code.

So... still looking at the eAns Onchange handler: Whether the user presses "Y" or "N", the program
executes CheckAns (more on this in a moment). It clears away the question about "Was <word>
shown?". It restarts the timer. And it sets up the next question. All very tidy!

One little diversion, before we look at CheckAns. I've not found explicit confirmation of something that I
hope is true.... I hope that if a timer is not enabled, and you then enable it, the timer starts counting down
from the "top" of its full interval. That is to say: If the interval is set at, say, 4 seconds, and you enable
the timer, I hope (and believe!) that you will get the full 4 seconds before the first timeout. This is the
sort of optimistic assumption that can get you in trouble in programming! I'm 99% certain that if you
leave the timer enabled, you will get an OnTimer event every 4 seconds... I'm just not certain how to
ensure that you get a full 4 seconds before the first OnTimer event.

http://sheepdogguides.com/dt2h.htm (3 of 5) [1/28/2005 3:44:45 PM]


Delphi: Some sourcecode to peruse.

Back to work: The details of CheckAns. First of all, I trust you inderstand that if you cause the CheckAns
code to execute with "CheckAns(sTmp)", then whatever is in sTmp will be transferred to sTmpLoc
within the code for CheckAns. This is called passing parameters, is very important generally, and is used
in a simple way here.

CheckAns is quite a nice little procedure, with two procedures of its own. Jump down past their
definitions to
begin
boIncNumRight;.........

As the rem says, this Boolean variable seems an unnecessary encumberance. It is used to make a note of
the need (or lack thereof) to add 1 to bNumRight shortly. (Again, part of my messy fix of the double
counting problem.)

The four "if" statements are neat and tidy, their logic being (I hope) clear. The messy details of what you
do when the user was right or wrong are neatly tucked away in the small procedures for those
circumstances. Look at them now.

"if (sTmpLoc='Y') or (sTmpLoc='N')..." is probably unnecessary... I don't think CheckAns is called in


any other circumstance... but it doesn't hurt to be careful! When "Y" or "N" has been entered, various
things need to be dealt with, and you can see them in the sourcecode. the "if iNumberDone>3.." test is
there to suppress the "percent right" reporting until a reasonable number of problems has been done.

That covers the meat of the program. One side-dish deserves comment:

The menu offers a way to change both the number of words in each list, and the time for viewing them.
In both cases, the only answer that makes sense is an integer, but the InputBox function is quite capable
of accepting any charcters. We could devise complicated routines to look at the user's response,
something along the following lines.....

repeat
sTmp:=InputBox('How Many','How mny?",5);
until sTmp <is made up only of digits>
... and then do
bPossWordMax:=strtoint(sTmp);

It wouldn't be too hard, but why go to the hassle? And why not start getting comfortable with the try...
except... construct, which will solve much more complex problems, as well as taking care of this little
one.

The basic idea with "try" is that the program will do the things from where "try" appears quite normally,
and will skip over the stuff between "except" and its "end" EXCEPT when something goes wrong. If, for
instance, you try to convert something from a string to an integer which cannot sensibly be converted,
strtoint quite helpfully "raises an EConvertError exception". (The strtoint help file entry tells you this.)

http://sheepdogguides.com/dt2h.htm (4 of 5) [1/28/2005 3:44:45 PM]


Delphi: Some sourcecode to peruse.

When an exception is raised, if you are in a try.. except... block, then everything else, down to the
"except" is SKIPPED, the program does anything it ought to according to the "except" part, and then
continues after the Except's "end".

If you look at the procedures for WordsPerSet1Clcik, and TimeToView1Click you will see that with a
little judicious use of boTmp, it is possible to force a user to give sensible answers to the questions before
the user can proceed. Possible... and easy!

So! I hope that's shown you some useful ideas. Please remember that I myself plan to sell something not
a great deal fancier than what I've shown you here, so plese resist the temptation to use it as a starting
point for anything too directly derivative. You an always get it from my freeware/ shareware site! :-)
Sheepdog Software Store

Zipped sourcecode for the program discussed above.


Zipped .exe of the program discussed above.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2h.htm (5 of 5) [1/28/2005 3:44:45 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

HOME - - - - - Delphi Tutorials TOC - - - - - - - - - - - - Other material for programmers

Delphi: TScrollbar, GetTickCount, TabOrder,


TabStop, Interlocking enables
This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

Click here if you want to know more about the source and format of these pages.
The most generally useful apart of this tutorial will be the material on the TScrollBar component. Don't
assume that scrollbars are only the ones we know and love on the edges of windows. They can also be
place in the main part of the window, where they are ovten called slider controls. I would guess htat
almost everyone as used one to control the volume of audio output from the computer, for instance.

While the job the program does will be of little interest to most readers, I think some techniques in the
program have general applicability.

If you are an intermediate Delphi programmer, I'm afraid you're going to have to wade through some
material expressed in detail for beginners. Sorry about that!

Before starting into the "meat" of the program, I will deal with GetTickCount, which is used in the
program. It is not written up in the Delphi 1 help files, but it does work, even under Delphi 1.

If you say liTmp:=GetTickCount, you will get a number. (liTmp should have been declared as being of
type longint (long integer).) The number changes rapidly, but at a fairly constant speed in all computers.
I've used this to cause a short delay with

liTmp:=GetTickCount;
repeat
until GetTickCount>liTmp;

Ordinarily, a loop like this would spell disaster... Windows doesn't respond well if a program takes over
the machine. Windows has to get a chance to do all of it's multi-tasking bits and pieces. If you do have a
loop in your program, it is wise to include
application.processmessages
within that loop. However, in this case a) the loop will not sieze control for very long, and b) I had
problems when I put application.processmessages inside the loop.

One point to bear in mind when using GetTickCount: It will, from time to time, give you grief... I'll
explain why in a moment. However... the grief I'm talking about arises only rarely. (Not good enough, I

http://sheepdogguides.com/dt2i.htm (1 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

hear you say... and for some programs I'd agree... but not all.)

The problem is one of overflow. If you understand that, you can skip down to the story continues. For
those who don't understand, I'm going to repeat myself without the technobabble.

I know a boy who has two brothers. I can indicate how may children there are a number of ways with a
keyboard. There's "3", of course... don't dismiss htat as too obvious, or you're going to miss the point I'm
making. There's also "three", "tres" (if you speak Spanish). I can do this: X-X-X. So... the idea of three is
simple, but how we show it is really fairly independent of the idea.

Inside the computer, we often "write down" numbers, of course. And there are many ways to do that.
(That could be the subject of a tutorial in itself, but for now I'll confine myself to one method!) The
number we get from GetTickCount is held inside the computer as a FIXED number of ones and zeros. If
you know binary, you know that the number of brothers in my example (3, as we usually write it), is "11"
in binary. However, if that number were stored in a longint type variable, it would be more accurate to
say that it is...
00000000000000000000000000000011
Remember I said that longint numbers occupy a FIXED number of ones and zeros? Computers are not as
clever as humans. We know that 0003 is the same as 3, and rarely bother to write out leading zeros.

(A little aside: Don't assume that one system's "Long Int" is the same as another system's. Delphi 1 uses
32 1s and 0s for a longint type number. If you work with the datasheets for the Dallas MicroLan / 1-wire
devices, you'll find that one of their integer types is of a different size from Delphi's idea. There's even a
nasty niggle at the back of my mind saying that between versions of Delphi the definition of some of the
integer types changed.)

(While I'm off of my topic anyway: Don't let my use of the word "fixed" above confuse you. There's a
major way of writing numbers called fixed point notation. What we're talking about here isn't that.)

Hang in there.. we're getting to the point. Before that, consider the odometer in a car... the thing that says
how many miles it has travelled. I have a very old car with only 5 wheels. It says I have driven 23,000
miles. Actually, I've travelled 123,000 miles- that's an example of an overflow problem.... there just isn't
a wheel for hundreds of thousands of miles. After it read 99,999 it went back to reading 00,000, even
though it should have said 100,000.

Overflow problems with longint values are similar. Eventually, the number gets so big that the next
number can't be shown properly. At that point you either get a "range check error", if you have {$R+} in
your program (more on this in a moment) or your program gets away with the problem, or you see
strange behaviour, even a crash, perhaps. (Similar things happen with other number representation
systems, longint isn't unique in this.)

Just to be thorough (ignore this paragraph if you like): longint is a signed type.... the 32 bits are not all
used for simple "binary" information. The left hand bit, if 0, says "treat the rest as a simple binary
number" (e.g. "000...0011" would mean "three") However, if that left hand bit is a 1, the whole number is
a negative number.

http://sheepdogguides.com/dt2i.htm (2 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

There are scraps in the program of my attempt to provide the small delay I needed without using
GetTickCount. I did things that "should" have worked, but couldn't find my errors. This failed and
mostly remmed out code is the only reason for the timer and for boTickTock.

The {$R+} issue: This is a compiler directive I recommend that you put into your sourcecode. I usually
put it just after the automatically generated {$R *.DFM} which appears just after "implementation".
N.B.: the {$R+} turns on range checking which is a good idea, with small penalties. The {$R *.DFM} is
unconnected to the range checking issue. If you take the {$R *.DFM} out, you program probably won't
compile.

The Story Continues... The program was written to drive some electronics plugged into the computer's
parallel port. Those electronics could turn on or off 4 banks, each of eight, LEDs. The program has 4
scrollbars. If they are all fully down, all 32 LEDs will be off. If they are all fully up, all 32 LEDs will be
fully on.

I don't know if the program actually works! But I know that all the major parts are working correctly, and
because of the way the program was written, if it doesn't work, the problems will be in one small part of
the program and easily overcome. The inspriation for the program was an article in Everyday with
Practical Electronics, a magazine published in the UK for electonics hobbyists. They had a similar
program in the article written in some nasty other language, hence my urge to port it to lovely Delphi.
The aricle was on page 738 of the October 2001 issue. If anyone would loan me the hardware to finish
testing the software, I'd be grateful! (Click here for EPE's website.)

Another brief(?) aside. This one covers the hardware. You can skip to next part of main story if you like.
The "other electonics" is a single chip, the UCN5818AF from Allegro Microsystems. (Available in the
UK from the usual RS outlets. I don't know how to get it in the US, sorry.)

Pins 1 and 40 are connected to 5v. Pins 19 and 20 are connected to 0v. Put a 100n cap between 5v and
0v. Connect the following to your printer port:

UCN5... pin number LPT1 name Pin on 25-way D


39 D0 2
22 Strobe 1
21 ALF 14

Connect the LPT ground to our external circuit's ground. Any of pins 18-25 on the D-25 should be
suitable.

http://sheepdogguides.com/dt2i.htm (3 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

PLEASE NOTE: You CAN damage your computer if you make


ill-advised connections to it. Any use you make of anything you find
here must be AT YOUR OWN RISK

For information on making things to connect to your parallel port, you may want to visit my page on that
topic. From there, you will find links to electronics tutorials. The parallel port page is the most popular of
all my pages.

So! The program uses four sliders to turn 32 bits of output from an external chip on or off. Each slider
controls 8 of the output bits. When the slider is fully down, the message to those 8 bits is "0"; when it is
fully up, the message is "256", which in binary just happens to be 11111111. The numbers between 0 and
256 cover all possible combinations of 1s and 0s in the 8 digit binary equivalent of the number.

I didn't try to be "clever" in my program.

We can ignore most of what's in the FormCreate handler, but just going through that:

laTitle3.caption:=laTitle3.captin+ver+');
takes what I put in the laTitle3 label at design time, which was "Delphi versoin by TKBoyd (version",
adds in whatever's in the program's "ver" constant (I'll come back to that), and finishes the label off with
a ")" to balance the one before "version".

In almost all of my programs, I declare a constant called "ver" (For "version") I make backups of work
from time to time, I have multiple copies in use, and distributed via my shareware enterprise. Whenever I
know that major changes have taken place, or that an older version has been "left behind" (e.g. a backup
has been done), I change the version ID. A date usually suffices, but if on a given day I have several
versions, I just add "a", "b", "c"... to the date. Many a time this practice has saved me agonising over
which copy of someting is the most advanced. It also helps when customers come to me with questions
about the copy they are using.

Now we come to the second line of FormCreate:

boHWEnabled:=false;

boHWEnabled is a boolean variable I declared to keep track of whether the user wants any messages
passed to the hardware the program was written to drive. ("boOOLEAN hARDwARE endabled") Until I
can borrow that hardware, there's no point in me literally unplugging my rinter while I do the
programming, when I can "unplug" the parts of the program that will (eventually) send meaages to LPT1.
Note that I set the program up so that it defaults to NOT sending things to LPT1... the user must do

http://sheepdogguides.com/dt2i.htm (4 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

something first... a partial protection against accidents.

Connected with this initialisation of boHWEnabled is the design-time specified caption on buPortOnOff.
When the program starts, this says "Turn Port On". Digressing from FormCreate for a moment: the
buPortOnOff handler is as follows:

procedure Tepe01af1.buPortOnOffClick(Sender: TObject);


begin
if boHWEnabled then begin
laPortOnOff.caption:='enable';
buPortOnOff.caption:='Turn Port On';
boHWEnabled:=false;
end (*no ; here*)
else begin
laPortOnOff.caption:='disable';
buPortOnOff.caption:='Turn Port Off';
boHWEnabled:=true;
end;(*else*)
end;

laPortOnOff is just one line of a longer message above buPortOnOff saying "Click button below to
(enable/disable) messages to parallel port." (Note how good choice over object names can make working
on a project easier.)

The buPortOnOff handling doesn't exactly turn the port on or off. Rather, it sets boHWEnabled true or
false. Then, anywhere in the program that something might be sent to the parallel port, there's an "if
boHWEnabled..." test first. It may seem complicated, but doing it this way keeps things more clear in the
long run.

The two lines in FormCreate relating to the timer are irrelevant, unless you can overcome thr problems I
had with boTickTock and it's intended role.

What remains breaks into two halves. Parts of the program are concerned with where the sliders are, and
the other parts deal with passing that information to the hardware. Cutting through the details, we come
to the event handler for ScrollBarChange. Every time the "thingie" on the scrollbar moves, for whatever
reason, the ScrollBarChange event is generated. And within that we find
if boHWEnabled then Send4BytesToExternalDevice;

We'll come back to that. First a little comment to forstall confusion: There are four ScrollBarChange
event handlers: ScrollBar1Change, ScrollBar2Change, Scroll3BarChange, and ScrollBar4Change. This is
pretty inelegant programming, but with intelligent use of cut and paste, it sure gets the job done quickly.
Note: The Send4BytesToExternalDevice which is part of each of the scrollbar's Change handlers is the
same Send4BytesToExternalDevice, and it sends the values of all four scrollbars each time, even though

http://sheepdogguides.com/dt2i.htm (5 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

(typically) only one scrollbar changes at a time. This wasn't done out of laziness, but rather because the
hardware the program drives has no provision for accepting new values for sub-sets of the 32 bits of
output it provides.

While we're looking at ScrollBarChange let me explain


bSB1Inverted:=255-ScrollBar1.position;
When the scrollbar is vertical on the screen, if the "thingie" is at the top, ScrollBar1.position returns zero.
I wanted "up" to equate to "high". The scrollbars were configured so that the highest value they return is
255. Thus, 255-ScrollBar1.position returns 0 if ScrollBar1.position is at its maximum, and 255 when it is
at zero. Obviously (?) Send4BytesToExternalDevice uses what is in bSB1Inverted, bSB2Inverted,
bSB3Inverted and bSB4Inverted.

Certain properties of the scrollbars deserve special mention. These properties were set as indicated at
design time.

Setting Kind to sbVertical oriented the scrollbar the way I wanted it.
The setting in LargeChange (16) determines how much the scrollbar moves if you click on the bar, but
not on the "thingie". SmallChange is set to 1 for this program, but you might have circumstances when
you wanted a larger change. Even if SmallChange is set to, say, 10 you can get intermediate values by
dragging the "thingie".
Max and Min determine the highest and lowest values returned by Position. Setting Postion to 255 meant
that the "thingie" would start at the bottom of the scrollbar.
The values set up for the TabOrder and TabStop properties of various objects on the form are not much
affected by the fact that some of the them are scrollbars. Some users never use the tab key, but many do,
and in some programs it is very useful. If you don't use the tab key, you will usually have to use your
mouse to get from object to object in the Window. The way EPE01a was written, you can control the 32
bits without using a mouse. The program starts with the first scrollbar selected, because its TabOrder has
been set to 0, and its TabStop is set to true. If you want to change the setting of the scrollbar without
using the mouse, the "arrow keys" will do... this is normal for any scroolbar, nothing to do with
TabOrder/Stop. The other three scrollbars have their TabOrder properties set to 2,3 and 4; all have their
TabStop property set to "true". Everything else on the form with a TabStop property has it set to "false".
Because of his, if you repeatedly press the tab key, you will move from scrollbar to scrollbar, going back
to scrollbar1 after visiting scrollbar4. Shift-tab moves you through the scrollbars, but in reverse order.
Just normal Windows behaviour.) So now you know about TabOrder and TabStop!

That nearly finishes what you need to know. I'm now going to examine Send4BytesToExternalDevice in
some detail, which will cover some ground that beginners may appreciate. Don't worry too much about
what we're doing to the hardware. Concentrate on the structures used. Before I start, I will again confess
to being lazy... the code is "inefficient" in that there are a lot of almost identical lines. You cn have a lot
of fun devising more elegant solutions, but this one worked and has few "clevernesses" in it to confuse a
beginner.

The lost important thing to notice is that the main program only "knows" about
Send4BytesToExternalDevice. If you look near the top of the listing, you find...

http://sheepdogguides.com/dt2i.htm (6 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

type
Tepe01af1 = class(TForm)
laTitle: TLabel;
laTitle2: TLabel;
laTitle3: TLabel;
laTitle4: TLabel;
ScrollBar1: TScrollBar;
ScrollBar2: TScrollBar;
ScrollBar3: TScrollBar;
ScrollBar4: TScrollBar;
buQuit: TButton;
laSB1: TLabel;
laSB2: TLabel;
laSB3: TLabel;
laSB4: TLabel;
buPortOnOff: TButton;
Label1: TLabel;
Label2: TLabel;
laPortOnOff: TLabel;
Label4: TLabel;
Label5: TLabel;
Timer1: TTimer;
Label3: TLabel;
procedure FormCreate(Sender: TObject);
procedure buQuitClick(Sender: TObject);
procedure ScrollBar1Change(Sender: TObject);
procedure buPortOnOffClick(Sender: TObject);
procedure ScrollBar2Change(Sender: TObject);
procedure ScrollBar3Change(Sender: TObject);
procedure ScrollBar4Change(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
bSB1Inverted,bSB2Inverted,bSB3Inverted,bSB4Inverted:byte;
(*The scrollbars consider UP to be 0, which is non-
intuitive, so at a low level, the sb.position is moved
to a variable which works the other way around.*)
boTickTock,boHWEnabled:boolean;
liTmp:longint;
procedure Send4BytesToExternalDevice;
public
{ Public declarations }
end;

Everything in that above "private" was generated for me by Delphi. I wrote the stuff in the "private"

http://sheepdogguides.com/dt2i.htm (7 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

section. (You don't need to worry about the use of the "public" section for quite a while.) When I wrote...

procedure Send4BytesToExternalDevice;

... I immediately used copy/paste (edit) to put the following into the program, below the word
"implementation":

procedure Tepe01af1.Send4BytesToExternalDevice;
begin
end;

... and I refrained from compiling or running the projuct until I'd put somehting between the "begin" and
"end". (If you run an empty procedure, Delphi will "helpfully" edit it out of your program for you!
Putting even something as simple as {x} between the "begin" and "end" will prevent this.)

As you've been going through the program, you've probably noticed the procedures Delay, PRn1, Prn3,
and DoByte1,2,3 and 4. But a few lines ago I implied that the program didn't "know" about them! This is
because they are buried within Send4BytesToExternalDevice. There are two benefits to this hiding:
a Things done by the hidden parts are less likely to upset other parts of the program. (They can,
especially if you do Bad Things with variables, but once you learn to avoid that, you're pretty safe...
and...
b) You'll remain clear about the fact that the hidden parts are not needed by anything other that
Send4BytesToExternalDevice. This becomes a real benefit when you start using parts of old programs
when constructing new ones.

So! How is the "hiding" accomplished?

The following isn't as lengthy as Send4BytesToExternalDevice, but it illustrates what is going on....

procedure Tepe01af1.ADemo;
procedure appendC;
begin
sTmp:=sTmp+'C';
end;
procedure appendO;
begin
sTmp:=sTmp:'O';
end;
procedure appendL;
begin
sTmp:=sTmp+'L':
end;
begin (*ADemo...*)
sTmp:='';

http://sheepdogguides.com/dt2i.htm (8 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

appendC;
appendO;
appendO;
appendL;
showmessage(sTmp);
end;
The procedure assumes that there is a declared string variable called sTmp. My use of it here has been
perilously close to the Bad Things I mentioned earlier, but forget that, if you realised. What is going on
in the above?

First of all, you have to learn to "read" the text... which is laid out in a not- especially- human- friendly
order.

procedure Tepe01af1.ADemo;

...marks the beginning of the programmer's indications of what should happen whenever ADemo is
invoked anywhere in the program. Following that are some details, which the informed reader skips over
at first, jumping down to...

begin (*ADemo...*)
sTmp:='';
appendC;
appendO;
appendO;
appendL;
showmessage(sTmp);
end;

(The (*ADemo) rem following the "begin" is optional, but always a good idea if the begin is at all far
from the start of the declaration

ADemo builds a word ("cool") in sTmp, and then displays it. Of course we could have simply said
"Showmessage('cool');", but I wanted to show you this structure where procedures are defined within
procedures.

While ADemo was doing its thing, it was required to use "appendC", "appendO", "appendL". These
procedures are not parts of Delphi.They were created, within ADemo, by putting..

procedure appendC;
begin
sTmp:=sTmp+'C';
end;
(and the other two, similar, procedure declarations) into ADemo where we did. As such, those
procedures are available to ADemo, but unknown to the rest of the program. The rules for what you can

http://sheepdogguides.com/dt2i.htm (9 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

put between "procedure" and "end" remain exactly what they were before. (These are remarkably simple
procedures). You can repeat the process, and have sub- sub- procedures, e.g. some procedure that is
defined within appendC, which is hiddend from even ADemo. (I'm not sure I've ever felt the need, but
you may do it.) You can also put function declarations within something like ADemo. (I've done htis
many times.) You can delcare constants and variables within something like ADemo (and often should,
and in one case must)... you just use "const" and "var" as you would in the main program. Here's more
complex example, showing some of these things.... (sTmp:=sTmp+chr(65) is like saying
sTmp:=sTmp+'A') The example also uses parameter passing. (This is an important concept I don't seem
to have written up anywhere. I'm not talking (here) about commnd line parameters.)

procedure Tepe01af1.Demo2;
const kA=65;
var sTmp:string;
c1:byte;
procedure append(b:byte);
begin
sTmp:=sTmp+chr(kA+b);
end;
begin
sTmp:='';
for c1:=0 to 5 do
append(c1);
showmessage(sTmp);
end;
This program will display ABCDEF.

It illustrates the time when you must use a "var" inside a procedure declaration: the control variable for a
"for" loop (c1, here) must be declared thus. It is called a "local" variable because it is "inside" Demo2,
and not "known" to the rest of the program. sTmp, obviously (I hope) is also local... you can even have
ANOTHER "sTmp" in the "outside world. You could have

sTmp:='fred";
Demo2;
showmessage sTmp;

there, and you'd first get "ABCDEF" and then get "fred".... which, if you think about it, is a little odd.
The "outside" sTmp wasn't messed up by the local sTmp while the program was doing Demo2! This
isolating of various parts of your program can be a big help in wring programs that do what you meant
them to do!

So... I hope the structure of Send4BytesToExternalDevice is more clear? Now to analyse what it is doing.

To "work" the external hardware, we need to send 1s and 0s according to the numbers in bSBInverted.
Prn1 is central to Sent4BytesToExternalDevice. If you say "Prn1(0)", you send a 0 (if boHWEnabled is
true), and if you say "Prn1(1)", you send a 1.

http://sheepdogguides.com/dt2i.htm (10 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

Before I go on: a "byte" is an eight digit binary number.

The DoByte1 sub-procedure looks at a part of bSB1Inverted, which, you may recall, is a number that is
determined by the position of the "thingie" in the first scrollbar. If you call DoByte1(128), you look at
the left hand bit (1 or 0) in the byte. DoByte1(64) looks at the next bit, and so on.

During DoByte1 (and 2 and 3 and 4), as each bit is examined, Prn1(0) or Prn(1) is executed, as
necessary. The Prn1(0 or 1) establishes a 0 or 1 on a line "feeding" the external hardware. The
Prn3(1);Delay(2);Prn(3); says, via a second line, "Hey! Take note of what's on the data line at the
moment."

After all 32 bits have been sent, the little

Prn3(2);
Delay(2);
Prn3(3);
at the end of Send4BytesToExternalDevice sets it so that the 1s and 0s you sent remain on the external
hardware's outputs until the next time you tell it to change what is showing.

One last little point: As it stands, I think this program will only compile with Delhi version 1, because of
the lines port[888]:=bTmp; and port[890]:=bTmp. There are ways around this problem if you want to
compile the program with more advanced versions of Delphi. Also, I'm 99% sure it won't work in
versions of Windows beyond Windows 98, certainly not in Windows NT. This is due to those operating
systems protecting the printer port from the sort of direct access used here. I THINK the program will
run okay on Windows 95 and 98 machines, which is why I include it in the zip file, for those of you
(grin) not still working with Delphi 1 on a Win 3.1 machine. See my page about using the parallel port
for more information on this issue of port[888], etc.

I'm out of time! Hope I didn't leave any loose ends?


Click here to download zip file with sourcecode and exe

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

http://sheepdogguides.com/dt2i.htm (11 of 12) [1/28/2005 3:44:50 PM]


Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2i.htm (12 of 12) [1/28/2005 3:44:50 PM]


Delphi: The String Grid component

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

Delphi: The String Grid component


This page is information rich, and a has search button at the bottom
of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

Click here if you want to know more about the source and format of these pages.
This tutorial, on its surface, is about the string grid component (object type TStringGrid). However, in
discussing that, a nice example arises of using event handlers in general, and in the specific case of
having one handler take care of events triggered by more than one object. It also gives a nice example of
incremental development, and leads on to a later tutorial about the "sender" argument which arises when
Delphi creates a skeletal event handler for you, and about selecting cells of a string grid with program
code at run time as opposed to having a human do it "by hand" when the program is running.

We are going to create a matching game.

Two lists will appear on the screen, i.e.

red merci
cheese non
thank you rouge
green oui
yes vert
no fromage
The user will click on an item in either column, and then try to click on the matching item in the other
column. If successful, both will go away.

Start a new project in the usual way. For the purposes of this tutorial, the form was called DD45f1 and
the project DD45.

From the "Additional" tab of the Components Palette, put two StringGrid objects on the form, side by
side.

Name the string grids sgLeft and sgRight

Click on one of the StringGrid objects. Shift-click on the other. Both should now be selected. Leaving
both selected, use the object inspector to change the following from their default values to what is shown
below. Having both string grids selected means that you will set these values for both of them at the same
time.

http://sheepdogguides.com/dt2k.htm (1 of 7) [1/28/2005 3:44:54 PM]


Delphi: The String Grid component

FixedCols: 0
FixedRows: 0

ColCount: 1
RowCount: 10

Width: 140
DefaultColWidth: 136 (I think it needs to be 4 less than width to allow for bevel. Try setting it to 110,
140 and 160 to see the effects. The "problem" is nicely to fit the data within container. Just turning off
the scrollbars is a nasty "solution".)

Put the following in the OnFormCreate handler. For the needs of this tutorial, it is important that you use
the values given, not something merely syntactically comparable.

sgLeft.cells[0,0]:='red';sgRight.cells[0,0]:='merci';
sgLeft.cells[0,1]:='cheese';sgRight.cells[0,1]:='non';
sgLeft.cells[0,2]:='thank you';sgRight.cells[0,2]:='rouge';
sgLeft.cells[0,3]:='green';sgRight.cells[0,3]:='oui';
sgLeft.cells[0,4]:='yes';sgRight.cells[0,4]:='vert';
sgLeft.cells[0,5]:='no';sgRight.cells[0,5]:='fromage';
Run the program: You should see two string grids, each with some words in them. Note that the "first"
row is "row zero". There are two coordinates for each "cells" as a string grid can have more than one
column. I wrote the previous sentence after doing most of the rest of this tutorial. At that moment, it
struck me that this whole thing could probably have been done in one two-column string grid, instead of
in two one-column string grids. Ah, the joys of programming! Exercise for the pupil: Which would be
best? (If there's no reason not to, if I'd thought of it, I would have gone with the "simple" answer: one
string grid.)

Believe it or not, we're nearly done. I generally rail at the "behind the scenes" stuff inflicted on us by our
beloved(?) event driven, object oriented operating system... but I must admit that in this case, it does
make things simple!!

As a start towards the "final answer", double click on a cell of sgRight. This will create an empty event
OnClick handler. Fill it in with....

if true then begin


sgLeft.cells[0,0]:='';
sgRight.cells[0,0]:='';
end;
Run that. You should find that clicking anywhere in the right hand string grid blanks the first line of both
string grids.

This next step is not "necessary"... but it does eliminate a chance to be confused by an inappropriate
name. Rename the OnClick handler by hand editing the sourcecode BOTH where you added the code,

http://sheepdogguides.com/dt2k.htm (2 of 7) [1/28/2005 3:44:54 PM]


Delphi: The String Grid component

and further up the source code where it used to say....

procedure sgRightClick(Sender: TObject);


In both cases, take out the word "Right".

Save the project. You will get an alarming "error" message about the lack of a reference to sgRightClick,
and be asked if you want to remove the reference. Say yes. Don't be alarmed by the fact that the program
no longer "works". Exit it, and use the Object Inspector to set the OnClick event handler for both string
grids to "sgClick" (You should find it in the events pull down menu.)

Run the program again. It should compile without complaint, and clicking on any cell in either string grid
should blank the contents of the first line in each.

Now we will make an incremental improvement. It will still be a ways from our "final" answer, but it
will illustrate concepts.

Put a label on the form, name it laTmp.

Change sgClick to....

procedure TDD45f1.sgClick(Sender: TObject);


var recTmp:TGridRect;
liTmp:longint;
begin
recTmp:=sgRight.selection;
liTmp:=recTmp.Top;
laTmp.caption:=inttostr(liTmp);
if true then begin
sgLeft.cells[0,0]:='';
sgRight.cells[0,0]:='';
end;
end;
... and run the program. Click in the RIGHT HAND string grid, watching what comes up in your label.

Now, just after....

public
{ Public declarations }
...in the sourcecode, put....

liSGRLeft,liSGRRight:longint;
This creates two variables (fields? There is a difference... but I'm not too clear on it!!) you can use
throughout the program. Something to AVOID, in general, but there are good times to do it, and times

http://sheepdogguides.com/dt2k.htm (3 of 7) [1/28/2005 3:44:54 PM]


Delphi: The String Grid component

when the "badness" isn't too bad.

Put liSGRLeft:=0 and liSGRRight:=0 in the form's OnCreate handler. They will track which row is
selected, and at the start of the program, the first (called "0") row is selected.

Add another label, call it laTmp2. Put laTmp below sgRight, and laTmp2 below sqLeft. Change sgClick
to....

procedure TDD45f1.sgClick(Sender: TObject);


var recTmp:TGridRect;
begin
recTmp:=sgRight.selection;
liSGRRight:=recTmp.Top;
laTmp.caption:=inttostr(liSGRRight);
recTmp:=sgLeft.selection;
liSGRLeft:=recTmp.Top;
laTmp2.caption:=inttostr(liSGRLeft);
if true then begin
sgLeft.cells[0,0]:='';
sgRight.cells[0,0]:='';
end;
end;
.... (notice that liTmp:longint; has been removed) Change the ....

sgLeft.cells[0,0]:='';
sgRight.cells[0,0]:='';

... part to....

sgLeft.cells[0,liSGRLeft]:='';
sgRight.cells[0,liSGRRight]:='';

Now the cells that you click are the cells that get blanked!

We're now going to create a function. If you haven't done this before, think of it as "making up a new
word for the language". Your "new word" will only work within the program it is part of. (Until you
learn more advanced techniques.) Our new word is going to be called boPair. "bo" for "Boolean", an
important data type. Boolean data can only be "true" or "false". We will be able to use our "new word"
anywhere that something that can be true or false can be used in a program.... e.g. with the "if...{boolean
thing}... then..." statement.

To create the function:

Just after "liSGRLeft,liSGRRight:longint;" (just below "public"), add...

http://sheepdogguides.com/dt2k.htm (4 of 7) [1/28/2005 3:44:54 PM]


Delphi: The String Grid component

function boPair(liTmpL,liTmpR:longint):boolean;

... and just before the "end." at the bottom of the page (yes, I meant "end.", not "end;"), add...

function TDD45f1.boPair(liTmpL,liTmpR:longint):boolean;
begin
result:=true;
end;
In the OnClick handler sgClick, change....

if true then begin


... to

if boPair(0,0) then begin


... and run the program again. It still does (if you've got everything right!) what it did before... but it does
it by a different process, one we are now going to make fancier!!

Within sgClick, change "if boPair(0,0)" to....

if boPair(liSGRLeft,liSGRRight)
Change function TDD45f1.boPair to....

function TDD45f1.boPair(liTmpL,liTmpR:longint):boolean;
begin
result:=false;
if (liTmpL=0)and(liTmpR=2) then result:=true;
end;
At this point, if you click on "rouge" when "red" is selected in the other column, they should both
disappear.

The program we are developing here has what is called "hard coded" questions. That is not a very good
approach for a commercial version of something like the quiz we will have finished in a moment.
However, the "extra" stuff" to make the questions and the mapping of correct pairs more flexible is not
complicated, nor does it require a different approach. The little program that is created in this tutorial has
been expanded into something useful, Matching Pairs, MGA15, available from my commercial
freeware / shareware site. Please give it a visit!

Back to work... Remember, that for this program to "work", you need to have entered the words I
specified, in the order I specified, earlier in the tutorial. ("red, cheese, thank you...").

After "if (liTmpL=0)and(liTmpR=2) then result:=true;", add...

http://sheepdogguides.com/dt2k.htm (5 of 7) [1/28/2005 3:44:54 PM]


Delphi: The String Grid component

if (liTmpL=1)and(liTmpR=5) then result:=true;


if (liTmpL=2)and(liTmpR=0) then result:=true;
if (liTmpL=3)and(liTmpR=4) then result:=true;
if (liTmpL=4)and(liTmpR=3) then result:=true;
if (liTmpL=5)and(liTmpR=1) then result:=true;
... and the demo program is "done"!!

The program developed in this tutorial is developed further in Part Two, which

So! I hope that's shown you some useful ideas. While I doubt you want a pairs matching program,
perhaps this example will have shown you how helpful the event driven powers of Windows can be. I
hope too that the incremental development used above will help you get to your programming
destinations faster than will be the case if you try to "chew" over-large "mouthfuls."

If you are comfortable with the material above, and ready for something more advanced, you might be
interested in Part Two, which takes the matching game discussed above, and develops it further. Again, I
was surprised by how useful and interesting I found some general principles that I stumbled across while
working up the tutorial. Part Two looks at using code to select a cell of a string grid at run time. Along
the way, some more generally important material arises concerning using references to Delphi created
objects, e.g. the object in "sender" arising from Delphi created event handlers.

The source code for the program, as at the end of this tutorial (Part One), can be downloaded by clicking
on either of the following links. You do not need to do both. I'd suggest fetching and running the self
extracting archive, but see "Why two options" if you're not sure what would be best.

Click here to download zip archive...Problem? Please report, quote:T45z


Click here to download self extracting exe...Problem? Please report, quote:T45s
Why two options?

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

http://sheepdogguides.com/dt2k.htm (6 of 7) [1/28/2005 3:44:54 PM]


Delphi: The String Grid component

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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 Sheepdog Software (tm) freeware, shareware page.

Link to Tutorials main page


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt2k.htm (7 of 7) [1/28/2005 3:44:54 PM]


Delphi: Selecting cells, using "Sender", Etc

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

Delphi: Selecting cells, using "Sender", Etc


This page is information rich, and a has search button at the bottom
of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

Click here if you want to know more about the source and format of these pages.
Pick a cell, any cell. Ostensibly, this tutorial is about using code to select a cell of a string grid at run
time. Along the way, some more generally important material arises concerning using references to
Delphi created objects, e.g. the object in "sender" arising from Delphi created event handlers.
Program driven cell selection, AND direct references to objects within code....

This follows on from an earlier tutorial. You really ought at least to skim Part One before reading on.

The source code for the program, as at the end of Part One, can be downloaded by clicking on either of
the following links. You do not need to do both. I'd suggest fetching and running the self extracting
archive, but see "Why two options" if you're not sure what would be best.

Click here to download zip archive...Problem? Please report, quote:T45z


Click here to download self extracting exe...Problem? Please report, quote:T45s
Why two options?

A little farther down the page, you will find a replacement for the sgClick handler. It was extracted (and
modified) from the code in MGA15, my commercial elaboration of the ideas in DD45. (You can get that
shareware program (not its source code, sorry!, from my freeware/ shareware store).

Once the new sgClick is in place, not only can you do everything you could do before, but the selected
cell in the column you DIDN'T click in, to identify a pair, will change to the next non-blank cell. (When
you succeed in finding a pair.) That is simple enough to describe. You'd be surprised at how long you
could spend trying to achieve that behavior. I count myself lucky: when I started the programming, it
went fairly smoothly.... probably merely by luck, as I say. Look CLOSELY at the following code to see
how all the pieces are fitting together to achieve the result. (Or, if you like a challenge, try to achieve the
result before you look at my code!) (More on this after the code....)

Before the revised code will run, you must also add...

bLastFilled:byte;
...just after...

public

http://sheepdogguides.com/dt3n.htm (1 of 6) [1/28/2005 3:44:57 PM]


Delphi: Selecting cells, using "Sender", Etc

{ Public declarations }
... and you must add...

bLastFilled:=5;
...just after "sgLeft.cells[0,5]:='no';sgRight.cells[0,5]:='fromage';"

The new sgClick handler is as follows.....

procedure TDD45f1.sgClick(Sender: TObject);


var grTmp:TGridRect;
objOther:TSTringGrid;
bCurrent,c1:byte;
boDone:boolean;
begin
grTmp:=sgRight.selection;
liSGRRight:=grTmp.Top;
grTmp:=sgLeft.selection;
liSGRLeft:=grTmp.Top;
if sender=sgLeft then
begin
objOther:=sgRight;
bCurrent:=liSGRRight;
end//no ; here
else begin
objOther:=sgLeft;
bCurrent:=liSGRLeft;
end;//else
if boPair(liSGRLeft,liSGRRight) then begin
sgLeft.cells[0,liSGRLeft]:='';
sgRight.cells[0,liSGRRight]:='';
//Make sure there is at least one not-blank row
boDone:=true;
for c1:=0 to bLastFilled do
if objOther.cells[0,c1]<>'' then boDone:=false;
if boDone then
showmessage('Congratulations on clearing the board!');
if not boDone then begin
//Now move the selection in the other
// column forward to next not-blank row
repeat
inc(bCurrent);
if bCurrent>bLastFilled then bCurrent:=0;
until objOther.cells[0,bCurrent]<>'';
grTmp:=TGridRect(rect(0,bCurrent,0,bCurrent));
objOther.selection:=grTmp;

http://sheepdogguides.com/dt3n.htm (2 of 6) [1/28/2005 3:44:57 PM]


Delphi: Selecting cells, using "Sender", Etc

end;//..of "if not boDone..."


end;
end;
Right.. what's going on? Look at the first line:

grTmp:=sgRight.selection;
grTmp has been declared as a TGridRect object, a type built into Delphi. These objects are rectangles
constituted of one or more cells from a string grid. In this code, we are always putting just one cell in any
TGridRect object. The code above says "Put into grTmp the cell which is selected in the right hand string
grid.

Once we've done that, we can do....

liSGRRight:=grTmp.Top;
That says "Put the y coordinate of that cell into liSGRRight" (SGR for String Grid Row). The values in
grTmp.Top will be in terms of the string grid, 0 for the first row, 1 for the second row, 2 for the third
(from the top), etc. The numbers are not in pixels, for instance.

So... now we know which row is selected in the right hand string grid. Next....

grTmp:=sgLeft.selection;
liSGRLeft:=grTmp.Top;
... gets ahold of which row is selected in the left hand string grid.

Watch this next bit carefully! It illustrates an important "trick":

if sender=sgLeft then...
... does something of great power, but something I'm only just beginning to use (at 9/04), so you won't
see it illustrated often in my other tutorials (yet). You need to be comfortable with the idea of things
being passed to subroutines (procedures and functions) when they are called. The OnClick handler for
both string grids, the subroutine we are looking at here, is a subroutine much like any other. However, as
an event handler, it is typically called not by some line of code in your program, but by an action by a
user while the program is running. None-the-less, it can have... and has had... something passed to it
when it was called. That "something" is of type TObject, you can see from the procedure's declaration.
And the object which was passed is sitting in the variable (field? Apologies if I'm mixing those terms
incorrectly) called "sender". "Sender" isn't some magic, special, Delphi declared word. It is just the name
that the compiler "happens" to use when setting up an event handler. So... what's in Sender? It depends
which string grid gave rise to the execution of the OnClick handler. Remember: sgLeft and sgRight both
use sgClick to react to the mouse being clicked while over the string grid. You've guessed what's in
"Sender" by now, haven't you? It is sgLeft or sgRight!! So now we can say....

http://sheepdogguides.com/dt3n.htm (3 of 6) [1/28/2005 3:44:57 PM]


Delphi: Selecting cells, using "Sender", Etc

if sender=sgLeft then
begin
objOther:=sgRight;
bCurrent:=liSGRRight;
end//no ; here
else begin
objOther:=sgLeft;
bCurrent:=liSGRLeft;
end;//else
... which puts the other string grid, whichever one wasn't responsible for this call of sgClick, into
objOther. bCurrent is given the index of the current position of the selected cell in that string grid, relying
(probably unnecessarily, but this is the code I got to work!) on the global variable which we put that
information into some time ago.

The next line....

if boPair(liSGRLeft,liSGRRight) then begin


tests whether the user has answered a right answer. There is nothing new about that from the program as
we left it at the end of the tutorial which this one follows on from.

Next, as before, we blank out the cells with the pair the user successfully identified....

sgLeft.cells[0,liSGRLeft]:='';
sgRight.cells[0,liSGRRight]:='';
Soon, we are going to change which cell is selected in one of the columns. First, though, we are going to
make sure that there still is a non-blank cell to move the selection to. As a "by-product" we are also
finding out if the user has done, i.e. cleared all the cells. boDone will be true or false accordingly.

In the following, the third line is the heart of the "magic"...

boDone:=true;//initialize it.
for c1:=0 to bLastFilled do
if objOther.cells[0,c1]<>'' then boDone:=false;
... then we do....

if boDone then
showmessage('Congratulations on clearing the board!');
... then, if we aren't done, we change which cell is selected. Study the code carefully... it gets a little
complicated only because it needs to skip over empty cells, and jump back to the first cell if it gets to the
bottom without finding an empty cell. For the moment, don't worry about
"grTmp:=TGridRect(rect(0,bCurrent,0,bCurrent));"... treat it as merely putting a reference to the right
cell into grTmp. We'll come back to that.

http://sheepdogguides.com/dt3n.htm (4 of 6) [1/28/2005 3:44:57 PM]


Delphi: Selecting cells, using "Sender", Etc

if not boDone then begin


//Now move the selection in the other
// column forward to next not-blank row
repeat
inc(bCurrent);
if bCurrent>bLastFilled then bCurrent:=0;
until objOther.cells[0,bCurrent]<>'';
grTmp:=TGridRect(rect(0,bCurrent,0,bCurrent));
objOther.selection:=grTmp;
end;//..of "if not boDone..."
end;
end;
That line "grTmp:=TGridRect(rect(0,bCurrent,0,bCurrent));" does something cool that lets us accomplish
what we want. I hadn't seen it in action before. I found out how about it from the ever helpful Alan
Lloyd, who has been posting excellent help at comp.lang.pascal.delphi.misc for YEARS. (You can
access the archive with groups.google.com.)

objOther.selection:=
....must be followed by a datum of type TGridRect.

TGridRect is a Delphi-defined type. Here the word is being used as a function. If you put something it
can cope with inside the brackets after it, then, in this syntax, TGridRect will return a datum of type
TGridRect. While I don't know how, directly, to specify the relevant cell of the string grid, happily, i do
know that i can refer to it with rect, a built in function of Delphi.

What we're seeing is called explicit typecasting. (See typecasting (not "type casting"), variable
typecasting in the Delphi help file f you want to study this further.)

In case it helps you understand better, let me mention that if you put....

showmessage(inttostr(objOther.width));
...into the code someplace after you've done objOther:=sgRight; or objOther:=sgLeft;, then the
showmessage will give you the width of the relevant string grid during the execution of the OnClick
handler. Oddly(?) I couldn't get the following to work!...

showmessage(inttostr(sender.width));
I say "oddly", as I thought that all we've done is put what was in sender into objTmp... but I'm obviously
missing something here (Yes, I've tried "With sender as TStringGrid..."), my brain aches, I've found a
way to do what I want to, so I leave the rest to you!!!

Enjoy.

I'm sure that the use of Sender within the sub-routine is going to be enormously useful when several
objects share the same event handler. Did I sufficiently stress the little bit "if sender=sgLeft..."? We

http://sheepdogguides.com/dt3n.htm (5 of 6) [1/28/2005 3:44:57 PM]


Delphi: Selecting cells, using "Sender", Etc

named one of the string grids "sgLeft". That "if..." is saying "Was it the control the programmer named
'sgLeft' that gave rise to execution of this handler at this time?"

And so to BED!!!

So! I hope that's shown you some useful ideas. A commercial realization of the ideas in this tutorial is
available from....
Sheepdog Software Store

It is called "Matching Pairs, MGA15"

Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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 Sheepdog Software (tm) freeware, shareware page.

Link to Tutorials main page


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt3n.htm (6 of 6) [1/28/2005 3:44:57 PM]


Delphi tutorial: Creating an array of Edit Boxes.

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for programmers

Delphi tutorial: Creating an array of Edit Boxes


Click here if you want to know more about the source and format of these pages.
There is a search button at the bottom of the page.

This tutorial assumes that you are comfortable with using arrays in general. For example, if writing a program to
keep track of a small shop's stock of the 20 items it routinely carries, it is assumed that you would immediately plan
to use something like StockLevel:array[1..20] of integer; (Working from 0 is often beneficial, but used 1 in case the
zero index confused anyone.)
I hope you will see ways to write a better program as the tutorial progresses. I am trying to keep the project from
having too many distracting embellishments.
You may find one particular aspect of using an array of controls odd.... you won't be able to place them on your
form as you would a plain edit box. More on this later.
I am endebted to Mr. Alan Lloyd of comp.lang.pascal.delphi.misc newsgroup for getting me past obstacles I
encountered when I first tried to use arrays of controls.
The program will create a screen like:
====================
Add these up

4 5 1 5
2 8 1 7
- - - -
? ? ? ?

Click here when done


====================
The user replaces each '?' with something, and the program marks the answers. N.B. For this tutorial about arrays,
the program we are writing is NOT asking the user to add four thousand, five hundred, fifteen to anything. The user
IS being asked to do four separate sums, the answer to the second being 13. (The program could be modified to ask
the user to add two four digit numbers.)
Arrays of edit boxes will be used for the digits of the first number in each problem (FirstNum[x]), for the digits of
the second number (SecNum[x]), and the digits of the user's guess (Guess[x]). The digits of the right answer will be
in an array of strings (Correct[x]). While it seems odd to be using strings to hold the elements of arithmetic
problems, it works well.
__________________
As a first step, we will create the array FirstNum, and the first element of that array. The index ("number") of that
element is going to be 0.
Start a new project called DD15, with my usual suffixes to distinguish forms, units, etc.
Add StdCtrls to the Uses section. The TEdit control is defined in StdCtrls, so the compiler needs StdCtrls to set up
our array of TEdit controls.

http://sheepdogguides.com/dt3a.htm (1 of 6) [1/28/2005 3:45:01 PM]


Delphi tutorial: Creating an array of Edit Boxes.

In the Var section add:


FirstNum:array [0..3] of TEdit;
Use the Object Inspector to create an OnCreate event handler for the application's form (DD15f1, in my naming
scheme). Add the following to it:
FirstNum[0]:=TEdit.Create(Self);

FirstNum[0].parent:=Self;

FirstNum[0].top:=5;
FirstNum[0].left:=5;
FirstNum[0].height:=50;
FirstNum[0].width:=50;

FirstNum[0].enabled:=true;
FirstNum[0].show;

FirstNum[0].text:='Hi';
...and run the program. You should get an edit box in the upper left, saying 'Hi'.
Some fine points:
a) My teacher suggested using
FirstNum[0].parent:=TWinControl(Self);
I looked up what the Delphi help had to say about TWinControl:
'The TWinControl component is the abstract component type for windowed controls, which are controls with
window handles, including the standard Windows controls. It is unlikely that you will ever derive a new component
directly from TWinControl, however. Instead, you will usually derive from TCustomControl'
My simpler version seems to work. (Alan was creating an array of panels, maybe that matters.)
b) The program 'works' without the FirstNum[0].enabled:=true; and FirstNum[0].show;... but assumptions about
initial states are always dangerous in programming. To quote from the Delphi Help: 'Since a constructor always
clears the storage it allocates for a new object, all fields automatically have a default value of zero (ordinal types),
nil (pointer and class types), or empty (string types).'
c) Of course, the FirstNum[0].text:='Hi'; isn't necessary, but it does allow you to be sure that any edit box you see is
the one you created.
d) By the way... don't try to do FirstNum[0].setfocus; because it won't work within FormCreate, even for an
'ordinary' edit box. Setfocus must be done in a different procedure after form has been created. I've had this type of
problem in other circumstances, and any feedback on ways around it would be welcomed! The problem: Often I
create, initialise, etc, objects, etc, in the main form's OnCreate handler, but find that I can't do all of the initialisation
I would like because, in essense(?) I'm trying to use things before they are set up and available(?)
Once you have the above working, you have mastered all of the essentials! The rest of the tutorial is just putting
together the promised example, with a few hints at shortcuts along the way.
______________________________
Start a new project. Again, I'm calling mine DD15

http://sheepdogguides.com/dt3a.htm (2 of 6) [1/28/2005 3:45:01 PM]


Delphi tutorial: Creating an array of Edit Boxes.

Add StdCtrls to the Uses section.


In the Var section add:

FirstNum, SecNum, Guess:array [0..3] of TEdit;


Correct:array [0..3] of string;
(If I were writing this for the end result, I'd use a two dimensional array. You might like to try re-writing it that way
as an exercise!)
Just after the Var section, make a Const section with:

GridTop=25;
GridLeft=15;
VSpace=20;
HSpace=40;
Gap=10;
(These are just for things like positioning the edit boxes, they don't need to be 'understood'.)
Use the Object Inspector to create an OnCreate event handler for DD15f1. Make it:

procedure TDemoF1.FormCreate(Sender: TObject);


var b1:byte;
begin
for b1:=0 to 3 do begin
FirstNum[b1]:=TEdit.Create(Self);
secnum[b1]:=TEdit.Create(Self);
Guess[b1]:=TEdit.Create(Self);

FirstNum[b1].parent:=Self;
secnum[b1].parent:=Self;
Guess[b1].parent:=Self;

FirstNum[b1].top:=GridTop;
secnum[b1].top:=GridTop+Gap+VSpace;
Guess[b1].top:=GridTop+2*(VSpace+Gap);

FirstNum[b1].left:=GridLeft+b1*(HSpace+Gap);
secnum[b1].left:=GridLeft+b1*(HSpace+Gap);
Guess[b1].left:=GridLeft+b1*(HSpace+Gap);

FirstNum[b1].width:=HSpace;
secnum[b1].width:=HSpace;
Guess[b1].width:=HSpace;

FirstNum[b1].height:=VSpace;
secnum[b1].height:=VSpace;
Guess[b1].height:=VSpace;

FirstNum[b1].show;

http://sheepdogguides.com/dt3a.htm (3 of 6) [1/28/2005 3:45:01 PM]


Delphi tutorial: Creating an array of Edit Boxes.

secnum[b1].show;
Guess[b1].show;

FirstNum[b1].enabled:=false;
secnum[b1].enabled:=false;
Guess[b1].enabled:=true;

FirstNum[b1].text:='?';
secnum[b1].text:='?';
Guess[b1].text:='?';

end;(*for*)
end;(*OnCreate*)
... and run the program. You should get a matrix of edit boxes, four wide, three high, all with a '?' in them.
____________
Now to set up problems to solve....
Add a menu with a 'New' option, named mmNew
Make the mmNewClick event the following:

procedure TDemoF1.mmNewClick(Sender: TObject);


var b1,bNum1,bNum2:byte;
begin
for b1:=0 to 3 do begin
bNum1:=random(10);
bNum2:=random(10);
FirstNum[b1].text:=IntToStr(bNum1);
SecNum[b1].text:=IntToStr(bNum2);
Correct[b1]:=IntToStr(bNum1+bNum2);
Guess[b1].text:='?';
end;
Guess[0].setfocus;
end;
Get that to run without error messages.
(Unless you want the same problems over & over again, add
randomize;
to FormCreate)
Add a button to the form, underneath where the matrix of edit boxes appears (though there will be none in sight on
the form you edit... they only appear when the program runs, as you have seen by now.) Name it buClickToMark,
Caption 'Click here to mark answers'.
Add a label to the form below buClickToMark. Name: laScore, Visible: false. (Don't set Enabled false, by the way...
it acts like Visible:=false!)
When testing the program, using the tab key to go from window to window is easy. You never need touch the
mouse.

http://sheepdogguides.com/dt3a.htm (4 of 6) [1/28/2005 3:45:01 PM]


Delphi tutorial: Creating an array of Edit Boxes.

Make the OnClick for buClickToMark:

procedure TDemoF1.buClickToMarkClick(Sender: TObject);


var b1,bScore:byte;
begin
bScore:=0;
for b1:=0 to 3 do begin
if Guess[b1].text=
Correct[b1] then inc(bScore);
end;
bScore:=bScore;
laScore.caption:=IntToStr(bScore);
laScore.show;
end;
Remember: THis program is asking the user to do four separate addition problems. The user is NOT adding two four
digit numbers, though you could modify the program for that use quite easily when everything else is working.
(Irrelevant aside: You might be amused to know that I spent about half an hour trying to find out why I always got a
score of 4 if the test before inc(bScore) was
if IntToStr(StrToInt(FirstNum[b1].text)+StrToInt(SecNum[b1].text))=Correct[b1]
... of course, I looked in all the wrong places first.)
There you have it! There's plenty of room to improve the application, of course, but the use of several arrays of edit
boxes is clear, I hope.
There is a Level Four tutorial which follows on from this with ideas for making use of modified standard
components. (Filename at one point was Dt4a.htm)
Tom Boyd

Click here for zip file with source code.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar Top
200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this
doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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!

http://sheepdogguides.com/dt3a.htm (5 of 6) [1/28/2005 3:45:01 PM]


Delphi tutorial: Creating an array of Edit Boxes.

Click here to visit editor's freeware, shareware page.

Link to Tutorials main page


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi,
and they provide promotional services, too. Click the "Help get this site publicity" link above for more information.

http://sheepdogguides.com/dt3a.htm (6 of 6) [1/28/2005 3:45:02 PM]


Delphi tutorial: Introduction to Graphics.

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial: Introduction to Graphics


This has good information, and a search button at the bottom of the page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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


Simple Graphics work.

Start a project called DD04. Save the main form as DD04f1, the unit as DD04U1. Put a button on the form,
caption it 'Do it'.

The following will draw a line when you click 'Do it':

procedure DD04f1.ButtonClick(Sender:TObject);
begin
DD04f1.canvas.moveto(100,100);
DD04f1.canvas.lineto(200,200);
end;

Note that the moveto/ lineto calls must not be made in the form's OnCreate event handler. You won't see the
line. I think it boils down to the idea that you have been trying to draw on something before it exists.
Have a look in the Delphi help files under "Drawing lines and shapes" for the wealth of other things you can do.

Unfortunetly, something as simple as the above isn't satisfactory. Run the program. Resize the window smaller
to cover up some of the line. Now resize it bigger again... the bit of the line you lost has not come back, has it?

Remove the 'Do it' button and its OnClick handler.

Add to the form a TImage object... you will find it on the 'Additional' tab of the components palette. Make it
400 wide, 100 high, put top and left at 10. Leave it with its default name of Image1.

Put the following in the form's OnCreate handler:

var Bitmap:TBitmap;(*Provide a suitable variable*)


begin(*main of OnCreate*)
Bitmap:=TBitmap.create;(*Create a bitmap object*)
Bitmap.width:=400;(*Assign dimensions*)
Bitmap.height:=100;

http://sheepdogguides.com/dt3b.htm (1 of 3) [1/28/2005 3:45:06 PM]


Delphi tutorial: Introduction to Graphics.

Image1.Picture.Graphic:=Bitmap;(*Assign the bitmap to the image component*)


Image1.Picture.Bitmap.canvas.pen.color:=clRed;
(*Have a look at the canvas Help to see all the properties*)
Image1.Picture.Bitmap.canvas.moveto(10,10);
Image1.Picture.Bitmap.canvas.lineto(300,50);
end;

Note that for some reason, now you CAN draw on the object even during the forms OnCreate event. This
graphic DOES persist, even after the window is resized or covered.
The Delphi 1 help file has lots of good stuff in it.. but the hyper-links and index seem faulty to me. Start with a
search for drawing lines. Double click on Drawing Lines and Boxes. Now double click on the topic called
Drawing Lines and Shapes. From that, you can use 'See Also' to look at Useing Pens and Using Brushes. See
also the help material under the "Style property" topic of the result of a search on "Style"
Have fun!!!

If you have a graphic in a .BMP file (as produced, say, with Paintbrush) then replace the two lines in the above
setting the bitmap width and height with:
Bitmap.LoadFromFile('Demo.BMP');

(You must not resize the bitmap after the LoadFromFile... but you can draw on the Bitmap.canvas as before.) If
Image1 wasn't big enough for the bitmap you tried to load, you will loose parts of the bitmap. However, even if
Image1.autosize equals false, loading a small bitmap into a large image will shrink the image to fit the bitmap.

I do not at this time know how to load .GIF files to a bitmap. In some cases, using something like Paint Shop
Pro, you can load a .GIF into a graphics package, then re-save it as a .BMP file. Answers for how to
LoadFromFile('Demo.GIF') would be welcome, if someone knows how to do it.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar
Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this
doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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.

http://sheepdogguides.com/dt3b.htm (2 of 3) [1/28/2005 3:45:06 PM]


Delphi tutorial: Introduction to Graphics.

Link to Tutorials main page


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for more
information.

http://sheepdogguides.com/dt3b.htm (3 of 3) [1/28/2005 3:45:06 PM]


Delphi tutorial, A component for use and reuse in other programs, part 1 (Level 3).

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

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

This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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


Delphi Tutorial 3c, part 1, (Version 28 Dec 98)

(Programs DD04 and DD05)

Purpose: A component for use and reuse as a part of other programs.


Limitiation: I don't intend to install it into your IDE, that is to say register it.

For the tutorial we will write a 'High Scores Table' component, and a little game to show it in action. The
High Scores Table code will be in a discrete unit so that the next time you need a High Scores table in a
project, you can have one simply by ading a few lines of code, and inserting calls to relevant methods
provided by the High Scores code. The High Scores table will appear on the screen as an independant
window outside of the game's window.
_________________
Start project, as in lesson 1. Filename DD04
Add a StringGrid to the form. (It is on the 'Additional' tab of the component palette)
Change the following properties from their defaults:
Align:alClient
ColCount:2
Fixed Cols:0
Height: 160
RowCount:11
Width: 500

You should have something looking a bit like an empty spreadsheet, with a row of grey cells at the top.
Put your cursor on the line between the first two cells of the first row. You should get a double headed
arrow cursor. Use it to drag the width of the fisrt column down to something suitable for about 5 digits.
Then drag the right hand edge of the to make it just fit the form. If you are left with a horizontal

http://sheepdogguides.com/dt3c1.htm (1 of 4) [1/28/2005 3:45:10 PM]


Delphi tutorial, A component for use and reuse in other programs, part 1 (Level 3).

scrollbar, re-adjust position of the right hand edge of the grid. If, when you riun the program, your
StringGrid column widths are re-set to previous positions: Stop the program, re-re-size the columns, then
drag the whole window a bit on the screen. (This shouldn't be necessary, of sourse, but it seemed to fix a
situation where I was losing re-sizings. I was also saving the project after re-sizing.. maybe that was 'the
secret')

Put the following in the form's OnCreate event handler:


stringgrid1.cells[0,0]:=' Score';
stringgrid1.cells[1,0]:=' Name';

Save what you've got so far.


Try to run the project until successful.
Stop it (again!)
Adjust the position of the line between the grid's two columns to let 'score' show sensibly.

We'll have to go back and work on this more in a while, but first we'll begin a little application to use it.
You can't (as far as I know!) work on two projects at once, so save DD04 and then use File|Close Project
to shut down DD04 for the moment.

Set up a directory for the new project. Call it DD05. For now, just put a button on it, name/label the
button 'Quit', and make the OnClick code...
application.terminate;

Run DD05. See that clicking Quit quits it.

Now... there are many ways to make components available. The one described here isn't 'sophisticated'...
but it has the virtue of minimal disruption to your Delphi environment. If ever you decide to 'register new
components', be sure to back up the appropriate files first. (I'm being vague here because of gaps in my
knowledge... but I DO know that it isn't hard to leave yourself with an unworking Delphi!!)

>>The following should work, I think it DID work... but when I tried it again, it seemed not to... don't
worry, there's a messy 'fix' explained after the following>>>>

To use my solution, you must make a minor adjustment to your Delphi environment. In Delphi 1, you do
the following:

Use Options|Environment. Click on the Library tab. Add to the library path the specification for
whereever you put DD04 earlier, e.g. C:\Delphi\DD04
<< end of what SHOULD have worked<<<<

>>>Start of messier alternative which DOES (?) work (at a price)>>>>


Copy DD04u1.dcu and DD04.dfm to whereever Delphi looks for units, as shown by the
Options|Environment Library tab. (In my case it was Delphi\Lib) The big pain of this 'solution' is that
you have to remember to RE-copy these two files every time you make changes to them. If anyone can
show me how to make the better solution work, I'll be grateful!)(Maybe File|Add is the way to go?)
<< end of messier solution<<<<<<

http://sheepdogguides.com/dt3c1.htm (2 of 4) [1/28/2005 3:45:10 PM]


Delphi tutorial, A component for use and reuse in other programs, part 1 (Level 3).

In any case.....
Now you should be able to add DD04u1 to the Uses clause of DD05, and re-run DD05. (You won't see
anything new, but when all is well you won't see error messages, either.)

All of what follows until clear notice is within DD05u1.pas

Add to Var section...

DD04f1: TDD04f1;

Put in the FormCreate procedure which you create by clicking on that event in the object inspector in the
usual way...

dd04f1:=Tdd04f1.create(self);
dd04f1.show;

Run until that much works.

(By the way... you may think I'm an 'expert'... but you're being an optimist if you do. I'm just the
one-eyed king stumbling around in the adventure game, discovering and passing on a few things that
seem to work. If you'd like to do some of the stumbling and return the favour, tell me what the difference
is between 'Create' and CreateNew' and explain when to use which!! (See Delphi Help, i.e. press f1))

Now, just after what you added above, add...

dd04f1.stringgrid1.cells[1,1]:='Works!';

This isn't much of an application, but it does show how to access things in dd04f1 from within dd05!

A SHORTCOMING of my approach:
You'll only know about what is in dd04f1 from your work on it. One of the rewards for using the more
complex provisions of Delphi by which you could register something like DD04 as a component would
be that while working with DD05, you would be able to 'see' what was available in DD04, just as you can
see the methods and properties of the components provided by Borland.

Well! That covers the essentials. In part two, I build up a full 'application' using DD04 as a high scores
table for a little game. When you run DD05, it will look to see if an old high scores table was saved. If it
was, it will fill the DD04 stringgrid with that data. As the game progresses, the display (DD04) and the
data file will be updated asneeded.

A few final thoughts...


It is easy enough 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,

http://sheepdogguides.com/dt3c1.htm (3 of 4) [1/28/2005 3:45:10 PM]


Delphi tutorial, A component for use and reuse in other programs, part 1 (Level 3).

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.

As ever... any feedback on this tutorial would be welcome, especially notification of anything that is
simply WRONG! The story continues in part two, click here to go on to Part Two.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt3c1.htm (4 of 4) [1/28/2005 3:45:10 PM]


Delphi tutorial: Typing Tutor. (Level 3).

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for


programmers

Delphi tutorial: Typing Tutor. (Level 3)


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

This has good information, and there's a search button at the bottom
of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Dt3d: A Little Typing Tutor


This tutorial is unfinished at the moment... but maybe what is here so far is of some use?

This tutorial develops a little game which is meant to make practicing typing fun.

There's nothing terribly profound in the program. It is in the Level Three category just because you don't
get "blow by blow" instructions. The use of an array of TLabel objects is one "advanced" element in this.
The relevant issues are intorduced in DT3a if what you find here is less than you want. The tutorial may
be most useful as an example of one approach to building an application up from start to finish. Among
other things, it illustrates using constants to make programs more robust and more easily modified.

Words appear at the top of a panel, and "fall" towards the bottom of it. If they are typed quickly enough,
they disappear, and points are earned. If they reach the bottom, points are lost.

Set up a folder called DD15. (Delphi Demo..)

Start new project. Name the form DD15f1. Save the unit as DD15u1 and the project as DD15.

Add a panel. Name it paWrds. Set Align to Bottom. Make its caption blank.

Set up the following OnResize handler for the form:


procedure TDD15f1.FormResize(Sender: TObject);
begin
paWrds.height:=dd15f1.clientheight-45;
end;

http://sheepdogguides.com/dt3d.htm (1 of 8) [1/28/2005 3:45:14 PM]


Delphi tutorial: Typing Tutor. (Level 3).

Just after the form's Uses clause, add


const kMaxWrds=40;
kMaxWrdLen=30;

kMaxWrds will be the maximum index for an array holding words which can appear on the screeen for
the user to type. kMaxWrdLen sets the maximum length for the words. Here and elsewhere I've spoken
of "words". There's no reason that the program cannot also present short phrases to the user.

To the var clause add

saWrds:array[0..kMaxWrds] of string [kMaxWrdLen];

Set up the following. Make bLastWrd as a global variable.


procedure FillsaWrds;
begin
saWrds[0]:='fred';
saWrds[1]:='red';
saWrds[2]:='was';
saWrds[3]:='saw';
saWrds[4]:='dare';
saWrds[5]:='veer';
saWrds[6]:='sweet';
saWrds[7]:='dear';
saWrds[8]:='drag';
bLastWrd:=8;
end;

For this simple demo program, you can put the call to FillsaWrds in the form's OnCreate handler.

Add a button, two labels, two timers and an edit box to the form. Set them as follows...
Button: Name buStart.
Labels: Names: laLeft, laScore. (laTimeLeft will count down to show time remaining in round.)
Timers: Names: tiSeconds, tiFallInt. Disable both. Intervals: 200 (for now) and 100. (tiSeconds's interval
will be 1000 in the finished version of the program.)
Edit box: Name: edIn. (This will be where user types in the words to "erase" them from the panel.)

Thoughout the rest of this, various variables will be introduced. They will all have to be declared, of
course, but I won't always tell you explicitly to do that.

Make tiSeonds's OnTimer event say...


dec(bTimeLeft);
laLeft.caption:=inttostr(bTimeLeft);
if bTimeLeft=0 then tiSeconds.enabled:=false;

and then make the start button's OnClick handler say...

http://sheepdogguides.com/dt3d.htm (2 of 8) [1/28/2005 3:45:14 PM]


Delphi tutorial: Typing Tutor. (Level 3).

tiSeconds.enabled:=true;
tiFallInt.enabled:=true;
bTimeLeft:=60;
laLeft.caption:=inttostr(bTimeLeft);
bScore:=0;
laScore.caption:=inttostr(bScore);
iOnP:=-1;(*Number of words currently on panel.. has to start
at -1 to help make first filling of arrays go well.*)

(Declare iOnP as an integer type variable.)

You should now get a count down if you click on buStart. When that is working right, you may want to
set tiStart's interval to 1000 so that the countdown is in seconds. This is an example of how with a little
thought, often you can easily make programs behave oddly to facilitate debugging.

Before we can write more code, you need to understand some more variable and arrays. The program
will use the following futher constants (Just add to existing const clause)...
kMaxWrdLen=30;
kOnMaxPoss=12;

and the following new variables and arrays...


bWOnMax,bWOnMin:byte;
baWOnXL,baWOnYT,baWOnXR,baWOnYB:array [0..kOnMaxPoss] of word;
saWOn:array [0..kOnMaxPoss] of string [kMaxWrdLen];

kMaxWrdLen sets the longest word or phrase allowed


kOnMaxPoss sets the maximum index for all arrays keeping track of words currently "falling" down the
panel.

bOnMax, bOnMin are variable holding the maximum and minimum number of words to be on the panel
at this time. (The "extra layer" has been added so that "easy" versions can be provided simply by
changing what is in these variables.)

saWOn, waWOnXL bOnWYT, baWOnXR and bOnWYB hold the words currently on the panel and
their positions. (XL/YT: X cood, left side/ Y cood, top. XR/YB: Right/ Bottom)

You might be wondering about the "complicated" business of declaring, say, kOnMaxPoss, and then
using that when setting up the arrays, etc. If you are careful to use kMaxOnPoss in EVERY relevant
place, instead of hardcoding with 12 (or whatever other figure you feel is right), then changing your mind
about something like that is as simple as changing "const kMaxPoss=12" to const "kMaxPoss=20". It
imposes disciplined thinking, too.

(Apologies for some inconsistency in my variable names. In some cases an array of bytes for Footle
might be called saFootle, and yet something similar might be asFootle2. Sorry!)

http://sheepdogguides.com/dt3d.htm (3 of 8) [1/28/2005 3:45:14 PM]


Delphi tutorial: Typing Tutor. (Level 3).

Now we are ready to start developing tiFallInt's OnTimer.

First, to OnFormCreate add...


bWOnMax:=8;
bWOnMin:=4;

Then make a start with...

procedure TDD15f1.tiFallIntTimer(Sender: TObject);


var c1:byte;
procedure AddWord;
begin
inc(iOnP);
laLeft.caption:='write AddWord';
end;

begin (*tiFallIntTimer*)
while iOnP&LTbWOnMin do AddWord;
for c1:=0 to iOnp do begin
laScore.caption:='write DropWord';
end;
end;

"AddWord" will add another falling word to the panel and take care of all the internal variable changing
required. DropWord will erase the word from where it was, and if it hasn't hit to bottom (in which case
remove and do things to score) put it back on, further down the screen. Next, once this event handler is
finished, all that will be left is the handler for edIn, which will look at what the user has typed, and
remove words if appropriate.

Just a little aside that may give you "misery loves company" consolation the next time you do something
like what I did....

On my first attempt with this, I left out the "inc(iOnP);" in AddWord. This make my system lock up...
you should be able to see why. Delphi had autosaved my project... but the text file that gave rise to what
you are reading now had not been saved since the....

...
saWrds[7]:='dear';
saWrds[8]:='drag';
bLastWrd:=8;
end;

a long way up this file.. and everything between there and here had to be re-generated. I hope I haven't

http://sheepdogguides.com/dt3d.htm (4 of 8) [1/28/2005 3:45:14 PM]


Delphi tutorial: Typing Tutor. (Level 3).

left bits out! Get in touch if I have!

Back to developing DD15...

To begin with, we are going to write a program with a serious flaw: Some of the falling words may
overlap one another. Before the code was written, this problem was anticipated, and a way out was
foreseen, but getting the words on the screen etc, even if overlapping, was chosen as a first objective.

If the overlap problem had not been anticipated, the TextOut and TextWidth Delphi words might have
been used. I could not, however, find a TextHeight word, which I though I needed. Not using TextOut
meant putting the words on labels on the panel, and elegant management of them requires an array of
labels. (There is more on creating arrays of objects in DT3a if what follows doesn't give you all you
want. By the way, sorry: Unless I've edited that since writing this, there's an error about a quarter of the
way through that. Where it says...

"Use the Object Inspector to create an OnCreate event handler for TEdit",

it should say

"Use the Object Inspector to create an OnCreate event handler for Demof1")

Just before going on with DD15 as created, it is worth mentioning another "solution" that was considered
and rejected. (It was too crude, and not flexible enough.) It would have been easier to write a program
that divided the panel into a number of columns and only allowed a single word in each column.

So! Back to DD15: Set up an array of Tlabel objects by adding, just after "public" in the TDD15f1 =
class definition....

alaWrd:array [0..kOnMaxPoss] of TLabel;

(N.B.: This is not exactly the approach used in my "Creating an array of edit boxes" tutorial.)

Modify the form's OnCreate, making it...

procedure TDD15f1.FormCreate(Sender: TObject);


var c1:byte;
begin
FillsaWrds;
bWOnMax:=8;
bWOnMin:=4;
for c1:=0 to bWOnMax do begin
alaWrd[c1]:=TLabel.create(self);
alaWrd[c1].parent:=paWrds;
alaWrd[c1].hide;
end;

http://sheepdogguides.com/dt3d.htm (5 of 8) [1/28/2005 3:45:14 PM]


Delphi tutorial: Typing Tutor. (Level 3).

end;

Add another constant called kTopGap and set it to 45. Replace the 45 in OnFormResize with kTopGap,
e.g....

paWrds.height:=dd15f1.clientheight-kTopGap;

(We may not need this after all... After suggesting this change and putting it in my DD15, I discovered I
didn't need it... yet. There's no harm in it, though, and as I said before, using such things is a good idea.
Now you have only to change kTopGap... to change the space for buttons and text above the panel with
the (to be) falling words.)

Make AddWord the following... as a start, only...


inc(iOnP);
saWOn[iOnP]:='Wrd'+inttostr(iOnP);
alaWrd[iOnP].caption:=saWOn[iOnP];
waWOnXL[iOnP]:=0+iOnP*60;
waWOnYT[iOnP]:=0;
alaWrd[iOnP].left:=waWOnXL[iOnP];
alaWrd[iOnP].top:=waWOnYT[iOnP];
waWOnXR[iOnP]:=alaWrd[iOnP].width;
waWOnYB[iOnP]:=alaWrd[iOnP].height;
alaWrd[iOnP].show;

That should put Wrd0, Wrd1, Wrd2, Wrd3 and Wrd4 across the top of the panel. If things are not
working well for you, it may pay to add alaWrd[iOnP].color:=clRed to the OnCreate code... it makes it
easier to see empty labels.

We'll have to come back to AddWord later, but that will do for now.

Next: Flesh out the "make it fall" part of tiFallIntTimer as follows. Note the temporary line is only in the
program until such time as we provide the "deal with words that hit the bottom of the page" code.

Make the form's height 230 before running the following.

begin (*tiFallIntTimer*)
while iOnP140 then waWOnYT[c1]:=140;
alaWrd[c1].top:=waWOnYT[c1];
end;
end;

Now we'll work in the "Deal with user input" part of the program.

http://sheepdogguides.com/dt3d.htm (6 of 8) [1/28/2005 3:45:14 PM]


Delphi tutorial: Typing Tutor. (Level 3).

To the buStart OnCLick event handler add....

ebIn.setfocus;

Now create an OnKeyPress event for ebIn...


procedure TDD15f1.ebInKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var c1:byte;
begin
if key=13 then begin
sTmp:=ebIn.text;
for c1:=0 to iOnP do begin
if sTmp=saWOn[c1] then begin
saWOn[c1]:='';
alaWrd[c1].caption:=saWOn[c1];
end;
end;
ebIn.text:='';
end;

This is just a start, but it should at least "zap" words you type.. even if they have got to line 140. (Be sure
to type, say, "Wrd2", NOT "Wrd2".)

At this stage in writing the tutorial, I had an unpleasant sinking feeling. At this stage I realised that there
was a flaw in my basic design. If I had not been writing a tutorial, I would have gone back and changed
things. However, I didn't relish changing not only the program, but also the tutorial, so I'm going to use a
messy work-around. Those who spot the inelegance which could have been avoided may award
themselves a Gold Star. The flaw also makes a nonsense of the variable bWOnMax I set up. I'd had in
mind that the number of words on the screen would vary between bWOnMin ans bWOnMax, but that
will now be difficult, and you'll only have bWOnMin words on the screen at any time. Oops!

Well... so far so good... but here I've run out of time for the moment. Email me a "Finish Dt3d, please"
email to encourage me to finfish it!!

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

http://sheepdogguides.com/dt3d.htm (7 of 8) [1/28/2005 3:45:14 PM]


Delphi tutorial: Typing Tutor. (Level 3).

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt3d.htm (8 of 8) [1/28/2005 3:45:14 PM]


Delphi tutorial introducing access to database files. (Level Three).

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for


programmers

Delphi tutorial: Accessing database files. (Level


Three)
There's a search button at the bottom of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Dt3e: Introduction to accessing files from databases

In this tutorial we take a look at accessing database files via Delphi. It is written using Delphi 2. I think
the principles applied even in Delphi 1, but I'm not sure.

Oh heck! One sentence into this, and problems already! Where did "Cardfile" go? I was going to work
with that as a common denominator we might all have. Oh well...

In this tutorial I'm talking about using data that you may have created, or obtained, which was originally
(and may once again, one day) be accessed using one of the database managers such as dBase, Paradox,
Access, SQL (actually a language, not a product, but if you don't understand, just ignore that entry in my
list.)

This paragraph for search engines: This tutorial relates to db files, data arranged in records consisting of
fields with data.

For the tutorial, we're going to interface a Delphi program we'll write to a database file originally created
with Paradox. You may have to do things a *little* differently to adapt things for the database you use.

First catch your database...

The data will be pretty simple..... a single table with membership details for a club:

Member ID, Last name, First name, Member since


001, Adams, Jane, 1970
005, Brown, David, 1998
002, Jones, Jeremy, 1990
004, Smith, Simon, 2001

http://sheepdogguides.com/dt3e.htm (1 of 4) [1/28/2005 3:45:18 PM]


Delphi tutorial introducing access to database files. (Level Three).

N.B.: There will be times when you are working with data and Delphi when you will have no need of any
external database connectivity. THIS tutorial is about the times when you DO want to access data from
non-Delphi-program-created database files. (See the "file handling" tutorials for the times your program
is going to be the only one accessing the data in the files.) (You can, however, if you want to for some
reason, write a whole RDMS package with Delphi... but why do that? Don't, however, think a Delphi
program can't set up the table, etc, etc, if you program it to.)

Set up the database in whatever database manager you want to use. Paradox sometimes spawns index
files, etc, etc, but for the simple case of this tutorial, just one file was needed: DD14CM.DB, (for "Club
Membership") which I'll try to make available on my website. (It may not contain exactly the data shown
above.)

BEFORE starting Delphi, because I was using Paradox, I also had to establish an alias for the datafile.
Now, in a simple world, you have Paradox on the machine you want to use Paradox files on, and you can
set up an alias within Paradox. On the system I'm writing theis tutorial on, I don't have Paradox, and I do
have both the Borland Database Engine (BDE) and the more advanced IDAPI system, also from Borland,
I believe. For BDE, the program for setting up the alias was BDECFG32. (Click the Pages menu item,
then Alias). For IDAPI, the program was IDAPICFG.EXE. EVENTUALLY I got things right! Don't
despair! The Delphi part of this is easy! (And the Paradox part would be easy, too, in normal
circumstances. Lovely RDMS, Paradox, by the way. POWERFUL! FAST! (Not especially new-user
friendly, I will admit.) Oh yes... Paradox owners can, legally, give clients what they need to work with
tables created with Paradox. It is like the Adobe's policies regarding Acrobat.)

Once the external created database is available, put a copy someplace suitable. (Of course, in "real life"
you'd have just the one copy, accessed both by your Delphi program(s) and the original database
management software.) If you are using Paradox, you will also have to set up an alias (for that copy... the
path to the data is part of the alias) I called my alias DD14CMA.

Click here to download database

Having caught your database, begin the Delphi program....

Start Delphi, start a project called DD14. Main form: DD14f1, main unit DD14u1.

From the Data Access tab of the component pallette, add a TTable type object to the form. The default
name (Table1) is fine. The TTable object is a non-visible component, like a TMainMenu object. Also
from the Data Access tab, add a type TDataSource object to your form. It will also be non-visible. In the
Object Inspector, click on DataSource1's DataSet property, and the property's combolist. You should find
Table1 (the default name assigned to the TTable object you put on your form) available. Set
DataSource1.DataSet to Table1.

From the Data Controls tab, add a DBGrid and DBNavigator to the form. Set DBGrid1.DataSource and

http://sheepdogguides.com/dt3e.htm (2 of 4) [1/28/2005 3:45:18 PM]


Delphi tutorial introducing access to database files. (Level Three).

DBNavigator.DataSource to DataSource1.

Set Table1's TableType. (I needed ttParadox, which was on the combobox list.) Also, set the
DatabaseName. (I needed DD14CMA... Club Membership Alias) When you've done that, you should
find your database file (DD14CM) available in the TableName combobox for Table1. (Set
Table1.TableName to DD14CM). If all is well, you can now set the Active property to true. (If all is
NOT well, you get an error message.) As soon as Active is set true, you should see some data from the
database in the DBGrid... even before you run the application. (Make the DBGrid a suitable size.)

That's "the hard part"! Run the application. You should be able to edit the data in the database. You can
add records with the plus sign on the DBNavigator (or the Insert key); you can remove records with the
minus sign of the DBNavigator. Table1 has a ReadOnly property you can set to true if you want users to
be restricted to reading the data, but prevented from changing it.

As with all Delphi learning, once you've got the basics working, you build up what you know by
consulting the help file entries on the various properties, methods and events associated with the objects
you are using.

The apparent complexity is there so Delphi can work easily with a wide range of possible external
formats.

The TDataSource object creates the link (I am using the term diffrently from the use sometimes seen in
relational database management) between the external database and the Delphi program. The Delphi
components for database work have DataSource properties, which you set to the TDataSource object
which you have linked to the data you want to work with. I believe this is a case of "encapsulation": the
TDataSource object has a consistent interface with the Delphi database handling routines, regardless of
the details of how the program, through the TDataSource object, actually accomplishes it's manipulation
of the database files.

For example, the TTable object is "tied" to the data in the external file(s) through the TDataSource
object.

Enjoy!

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

http://sheepdogguides.com/dt3e.htm (3 of 4) [1/28/2005 3:45:18 PM]


Delphi tutorial introducing access to database files. (Level Three).

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt3e.htm (4 of 4) [1/28/2005 3:45:18 PM]


Delphi tutorial: Playing .WAV files with MediaPlayer. (Level Three).

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for


programmers

Delphi tutorial: Playing .WAV files with


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

This has good information, and there's a search button at the bottom
of the page.
Please don't dismiss it just because it isn't full of graphics, scripts, cookies, etc!

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

Dt3f: Playing .WAV files with the MediaPlayer

This is a level 3 tutorial not because it is very complicated, but because the issues are significant to a
small group of programs.

As usual, set up a directory for the exclusive use of the application we will develop during this tutorial.
COPY (don't MOVE!) into it at least two .WAV files. I used ding.wav and chimes.wav which, in my in
Windows 3.1 machine, were in C:\windows. Files you are going to play do not NEED to be in the
application's directory, but it pays to eliminate distractions when exploring a new topic.

Don't start Delphi yet! FIRST: make sure that you speakers, soundcard, etc, etc are all behaving. You
may be able to hear the WAV files simply by double clicking on the names from within Windows
Explorer. Failing that...

Win 3.1: Control Panel| Sound. Navigate to directory your .WAV files are in. Select one. Click "Test".
CLick CANCEL... otherwise you'll reassign the sound you tested to the event that the Sound app had
selected.

Win 95: Depending on how your computer was set up, you may have...
Programs| Accessories| Multimedia| Media Player
available for making sure everything is ready.

Start Delphi.

Put two buttons on the form. Name them buPlay1 and buPlay2; caption them "Play 1st sound" and "Play

http://sheepdogguides.com/dt3f.htm (1 of 4) [1/28/2005 3:45:21 PM]


Delphi tutorial: Playing .WAV files with MediaPlayer. (Level Three).

2nd sound" (or somesuch!)

(This is written for Delphi 1, by the way...) From the System tab of the component pallet, add a
MediaPlayer component to your form. (The icon is two musical notes and a bit of movie film).

Now create an OnClick handler for buPlay1 as follows...

MediaPlayer1.filename:='ding.wav';
MediaPlayer1.open;
MediaPlauer1.wait:=true;
MediaPlayer1.play;
MediaPlayer1.close;
Get that working.

By the way: the following is functionally equivalent and more elegant...

with MediaPlayer1 do
filename:='ding.wav';
open;
wait:=true;
play;
close;
end;(*with*)
Now make an OnClickHandler for buPlay2 which is identical to the one for buPlay1, except set filename
to the other .Wav file.

Don't try to use the bar with "play"/"stop","rewind", etc buttons just yet.

Some details...

The open method accesses the MediaPlayer, getting it ready to do something. Later on, the close is
important as it releases the resources tied up when you did "open". You might think you could avoid the
constant opening and closing as follows:

In the form's OnCreate handler,


1) Assign a valid filename, e.g. ding.wav to MediaPlayer.filename
2) Do MediaPlayer1.open
In the form's OnClose handler include MediaPlayer1.close;

However, this DOESN'T WORK, as even if you change what is in MdiaPlayer1.filename, the sound you
get from Play remains the same. If you try to open the MediaPlayer without first supplying a value to
MediaPlayer1.filename, the attempt to open fails. In any case, I prefer opening and closing things when I
need them, rather than having them open throughout. (Similar issues arise when you work with data
files.)

http://sheepdogguides.com/dt3f.htm (2 of 4) [1/28/2005 3:45:21 PM]


Delphi tutorial: Playing .WAV files with MediaPlayer. (Level Three).

The MediaPlayer1.wait:=true just before MediaPlayer1.play is important. It stops the program from
going straight on to MediaPlayer1.close. Take out the wait:=true and your program will still run, but you
won't hear any sounds... they are stopped within milliseconds of being started. The wait:=true has to go
just before the Play.

For our simple demo, it would be best to use the object inspector to set MediaPlayer1.visible:=false;
However, if you want to play with the player buttons, you just need to do two things with the object
inspector:
1) Put the name of a suitable file in MediaPlayer1's filename property, and
2) Change MediaPlayer1's AutoOpen property to "true".

Now if you click on the "Play" button on the row of buttons which are the visble part of MediaPlayer1,
you should hear the wav file played.

Enjoy!

Tom, Chichester, England


Click this to download zip file with source code.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200

http://sheepdogguides.com/dt3f.htm (3 of 4) [1/28/2005 3:45:21 PM]


Delphi tutorial: Playing .WAV files with MediaPlayer. (Level Three).

Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt3f.htm (4 of 4) [1/28/2005 3:45:21 PM]


Delphi: Reading joysticks

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi: Reading joysticks (And making a stopwatch


to illustrate the concepts)
This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

This tutorial needs editing! Sorry! But I thought you'd rather have the information in it, however badly
presented, than wait (probably forever) for the cosmetic surgery it needs? What happened is this: I wrote
a first attempt at explaining the material in this. I then forgot I'd done that, and wrote a second attempt!
You can read the first attempt just by reading the rest of this page. The second attempt is better, and
covers everything that appears below and more... but you have to download it... but that means you get
the sourcecode without having to type!

The downloadable version is not presented in the unusual format of these tutorials. The main text of the
tutorial is included, as a text file, in the self extracting zip (SEZ) archive which also contains the
application's source code. Click here to download that archive. Save the SEZ on your disc. You can go
offline at that point. Double click on the SEZ. It was created with WinZip, and will allow you to select a
destination folder for the material to be unzipped.

Confused yet? No? Well, let me mention that there is yet another joysticks tutorial available for you
here. It shows you a better way to read them, at least for some purposes, but it does involve more
advanced concepts. I.e. responding to Windows messages.
Here begins the first version of the tutorial....

This tutorial is based on a newsgroups post from Mark Wilkinson... thank you, Mark! This tutorial will
be short on explanation and not much longer on program... because Delphi makes things so easy!!

I have a switch that goes off-on-off-on... in response to rainfall. (It can come to rest in either state.) The
more rain, the more cycles. I wanted to monitor that switch, and the "fire button" input of a joystick
seemed the obvious, easy way. Don't worry, I have another computer for important things like Interactive
Magic's Apache and Novalogic's F-16, so losing the joystick port was acceptable.

The bad news: This information is helpful only if you have gone beyond Delphi 1.

The good news: Though I couldn't find it in the Delphi 2 helpfile, Delphi 2 has built in joystick support.

http://sheepdogguides.com/dt3g.htm (1 of 4) [1/28/2005 3:45:27 PM]


Delphi: Reading joysticks

Thanks to a newsgroups post from Mark Wilkinson (homepage: Mark Wilkinson), I discovered enough
to write my program for my rainfall monitor.

The essential bits of reading the joystick port are all in DD18. A zip archive of it's source files source can
be downloaded by clicking here.

It puts up a window showing you the current x and y positions of the joystick, and the state of Fire
buttons 1 and 2.

A few things you shouldn't overlook:

Set the timer interval to something small, say 20. (This determines how often the joystick is checked.)

Add MMSYSTEM to the "USES" clause. The unit is a standard, Borland unit, don't sorry. But be sure to
add the reference.

A few things you don't need to worry about:

The variable MyJoy is declared to be of type TJoyInfo. This class is set up by Borland; you don't need to
worry about the internal details.

The call of JoyGetPos passes a parameter by means of a pointer... I think!! the "@" sign isn't a mistake, it
is to do with pointers, I should probably go learn something about why Borland did JoyGetPos the way
they did... but in the meantime, I'm just going to use it and be happy.

The following procedure declaration header involves "var", which I don't often use, so I'll say a bit about
it here if you haven't come across it. Note it appears before li1 AND before bo1. (If it isn't repeated, the
boolean parameters bo1 and bo2 will not behave the way li1 and li2 behave.)

procedure ReadJoystick(var li1,li2:longint;var bo1,bo2:boolean);

The following is messy, and I wouldn't do things like this... but it illustrates what var is doing...

Imagine I have a global variable called Answer, and a procedure as follows:

procedure DoubleAndAdd(b1,b2:byte);
begin
b1:=b1+b1;
b2:=b2+b2;
Answer:=b1+b2;
end;

If, in my program, I said

http://sheepdogguides.com/dt3g.htm (2 of 4) [1/28/2005 3:45:27 PM]


Delphi: Reading joysticks

DoubleAndAdd(3,4);

...then Answer would be filled with 14. Okay so far... simple stuff, so far.

Now suppose....

b1:=3;
b2:=4;
DoubleAndAdd(b1,b2);

.... Same result, I hope you agree. Answer is still filled with 14. Also, I were to check what was in b1 and
b2 after the above, they would still hold 3 and 4. The b1 and b2 of the main program are separate from
the b1 and b2 of the procedure. The fact that they have the same names is mere coincidence. This is all
about scope... an important concept, one of the things Pascal Got Right, thus making it easy to write
robust programs.

Now we start the tricky stuff....

If the procedure said:

procedure DoubleAndAdd(var b1,b2:byte);


begin
b1:=b1+b1;
b2:=b2+b2;
Answer:=b1+b2;
end;

(same as before, except for the "var")

and the main part of the program said the same as before....

b1:=3;
b2:=4;
DoubleAndAdd(b1,b2);

.... Answer would still be filled with 14... BUT!....now if I were to check what was in b1 and b2 after the
above, they would hold 6 and 8. Even more "magic": if I did.....

FirstVariable:=3;
SecondVariable:=4;
DoubleAndAdd(FirstVariable,SecondVariable);

... Answer would hold 14, FirstVariable would hold 6, and SecondVariable would hold 8. 3 went into
FirstVariable, in that it went into the procedure. In the procedure, it was moved to b1. As the procedure
was finishing up, it passed back to FirstVariable whatever was in b1 at the end of executing the
procedure.

http://sheepdogguides.com/dt3g.htm (3 of 4) [1/28/2005 3:45:27 PM]


Delphi: Reading joysticks

There are other solutions. (user defined types.) Using var in the procedure declaration might be seen as a
clumsy solution... but it works! Be sure to put var in front of each group of variables you want to pass
that way.

Enjoy!

That's the simple approach to joysticks.... remember there are other tutorials on the topic in these pages,
especially the downloadable self extracting zip with the improved version of this material!

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


To email this page's editor, Tom Boyd....
Editor's email address. Comments appreciated!

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt3g.htm (4 of 4) [1/28/2005 3:45:27 PM]


Delphi: Linking to Helpfiles.

HOME - - - - - Delphi Tutorials TOC - - - - - - - - - - - - Other material for programmers

Delphi: Linking to Helpfiles


This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

Click here if you want to know more about the source and format of these pages.
While a "Readme" file can cover important ground, it isn't very long before your programs look pretty
amateur without a "proper" helpfile. Happily, connecting them to your program is easy.

Creating them, while not hard, isn't trivial. There's information on tools and techniques for creating .hlp
files here: creation of helpfiles.

Just before explaining how to link your program to it's helpfile, let me mention that this tutorial doesn't
go into the question of context sensitive help.

Let's say your program is called TRD6.exe, and the helpfile is TRD6.hlp. It is easiest, and makes sense,
to put the .hlp file in the same folder (directory) as the .exe.

Within the OnFormCreate handler, for programs named as above, you would put...

application.helpfile:='TRD6.hlp';
To launch the helpfile becomes a simple matter of executing...

application.helpcommand(HELP_CONTENTS,0);
You could put that as what happens in the OnClick handler for a menu item called "help", or the OnClick
handler for a button labelled "Help"... or you could call it some other way... but that's all the code you
need!

I said this tutorial would be short!

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at

http://sheepdogguides.com/dt3h.htm (1 of 2) [1/28/2005 3:45:30 PM]


Delphi: Linking to Helpfiles.

Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt3h.htm (2 of 2) [1/28/2005 3:45:30 PM]


Delphi: Inter-acting checkboxes and boolean variables

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

Delphi: Making checkboxes and Boolean variables


solve your problem
This "tutorial" will be less "Now type this..." than most.

I wrote a small program, and I thought elements of it might be of interest or use to you, even though I
doubt you'll need the program itself!

The program provides a timer to control a fan in my house. One button turns the fan on for ten minutes,
then switches it off. Another starts the fan going on for the first ten minutes of each half hour, then off,
then on for the first ten minutes of the next half hour... and so on, BUT: only for selected hours of the
day. (There are 24 checkboxes to specify which hours.) There's a button to turn the fan off.

That gives you the basic idea of the function of the program. To actually control the fan, you need some
external electronics plugged into your parallel port. More on this later, but even if you don't want to
bother with the electronics or tie up your port, the program has things to show you. You can run it with a
"virtual" fan provided in the software.

You can obtain the sourcecode....

....by clicking on download source code That will transfer a file called DD25.exe to your machine. Virus
check it, and then double click on it. It is a WinZip 8 created self-extracting archive. The program was
written for Delphi 1, but it will load into Delphi 2 (and, I would guess, higher Delphis) for study. (It can
be made to control a real fan under other Windows, but needs modifications not covered here.)

If you compile and run the program, it won't operate any fan you have connected for two or three
reasons, but it will "do" everything except turn on the fan, and you can fix it to do the fan, too. The
reasons it won't work are...

Within the procedures "FanOn" and "FanOff" I have remmed out the essential lines, the ones beginning
"if boEnPort then...". These procedures were created to isolate the underlying code controlling the
hardware. Using procedures thus is an important skill. With changes only in these two small procedures I
can transfer my fan control software to a different system, with a very different interface between the fan
and the computer. I might, for instance, turn it on / off via the serial port. I remmed out the essential lines
because the program, with those lines active, should not be run in a computer which has something other
than the fan control electronics connected to the parallel port. (If you remove the squiggle brackets
around the "port[888]:=" code, remove laWarnDisabled, the label saying "See "FanOn" and "FanOff"
code".)

Even once the lines are no longer remmed out, you won't turn the fan on simply by clicking the "Fan On"
button. Again, to protect the machine, and to provide a way to work on the program when a printer is on

http://sheepdogguides.com/dt3i.htm (1 of 6) [1/28/2005 3:45:34 PM]


Delphi: Inter-acting checkboxes and boolean variables

the parallel port, there's a checkbox labelled "Turn on output to port 888", which is not checked, initially.
Look at the occurances of boEnPort ("Boolean, Enable Port") in the program to see how this mechanism
operates.

Lastly, as written, the program must be compiled with Delphi 1 and run on a Windows 3.1 machine. For
purposes of studying it, it will compile in higher delpihs, if you leave the two hardware control lines
remmed out.

I won't go into the details of the hardware control here. See my Guide to Parallel Port interfacing if
you're interested. There are notes there about modifying "port[888]:=" onto alternatives for other
Windows.

Let's look at FormCreate....

boEnPort is a boolean variable which keeps track of whether we want to enable outputs to the parallel
port.

The call of FanOff invokes the low level procedure that (if boEnPort is true) actually turns the fan off. It
is hard to be sure that every pc will default to the same intial state, and in any case, some other program
may have been running. This program, by the way, is NOT "well-Windows-mannered"... it relies on you
to refrain from invoking other things that might affect the hardware controlling the fan. FanOff also
contains the code to update the onscreen indication of the fan's theoretical state. (I say theoretical,
because if boEnPort is false, after "FanOn", laFanState.caption will say "ON" regardless of the actual
fan's state.) The manipulation of laFanState.caption is deliberately put at this low level so that there are
few ways for it to be wrong! FanOff also changes the state of boFanOn, so that we have that to tell us if
the fan is on or off (theoretically) any time we need to know.

(There's a corresponding "FanOn" procedure.)

bMinsTilOff is set to 255 (the maximum value that a byte type variable can hold) to tell the program that
it shouldn't be acting on bMinsTilOff until further notice. 255 is a rogue value. More on bMinsTilOff
soon.

Most of the program's funtioning derives from the timer, "timerMins". I have a tutorial on timers, but, in
a nutshell: You set the timer's interval to a number of milliseconds. Here, for normal use, we set it to
60000. The timer counts them off, and after that many, it does whatever you have set up the
TimerMinsTimer procedure to do. The "if timerMins.interval,.60000..." line is there because during
debuggin, you may bery well want to set the timer's interval to a smaller value to compress time. (Note,
however, because of things we have not yet discussed, not all of this program's operatins can be tricked
into operating in compressed time.)

If you want to provide something like the compressed time option for debugging, always try to do it in a
way that can be adjusted with a single line of code, and try to provide yourself with warning of when the
debugging mode is in action. A label that is visible only when debug mode is on is one handy way to
protect yourself.

http://sheepdogguides.com/dt3i.htm (2 of 6) [1/28/2005 3:45:34 PM]


Delphi: Inter-acting checkboxes and boolean variables

Moving on....

Before we look at the timerMinsTimer procedure, a little more about bMinsTilOff.

So far in this program, it is only used to implement the operation of the "Turn Fan on for Ten Minutes"
button. It's use could be extended in several ways, but that's an exercise for you! For now, look at the
buFanOnClick procedure. (That's a bad name- sorry- it should be "FanOnForSpecifiedPeriod", or
somesuch.)

In buFanOnClick we see bMinsTillOff set to 10, and FanOn (which turns the fan on, and adjusts labels
on the screen accordingly). So far so good... but where the program turns it off again is a little unclear so
far! Don't worry... All will be revealed... later.

Just before we move on, I should tell you that if the user has clicked "Fan On For Ten Minutes", that will
over-ride the "Turn On / Off Repeatedly" fnctin fo rthe next ten minutes. After that time, I think, and it is
easy to mis-program this sort of thing!, the system will revert to whatever you reqested with the "Turn
On / Off..." checkbox. Which way do you WANT the program to run? Now have you set it up that way?
(The joys of programming....)

In a related vein: If you click "Fan Off", the fan will go off immediately, AND the request for the On /
Off cycling will be cancelled. Look at the code. Isn't it simple to achieve something like this.... IF you
have a well designed structure of checkboxes and other boolean entities keeping track of your wishes and
states?

If you haven't done a lot with turning things on and off, you might want to look closely at
cbEnablePortClick and be sure you understand what is going on.

And now for the heart of the program...

The heart of the program is the procedure timerMinsTimer.

This procedure executes every time the timer "times out", i.e. when timerMinsTimer.interval
milliseconds have passed. Set timerMinsTimer.interval equal to 60000, and the timerMinsTimer
procedure will execute once a minute.

Forgive me! I used a very crude system to implement the program's ability to operate the "on / off"
cylcling only in certain hours of the day. The function SeeIfThisHourIsEnabled returns true or false
depending on value in wHrs. wHrs is filled with the "hours" part of the time of day just before
SeeIfThisHourIsEnabled is called. The value comes from a call to Delphi's built in "now" function.

The first bit of code in the main block of the timerMinsTimer procedure handles situations where the fan
is on because bMinsTilOff has been set to a non-0, non-255 value.

http://sheepdogguides.com/dt3i.htm (3 of 6) [1/28/2005 3:45:34 PM]


Delphi: Inter-acting checkboxes and boolean variables

I used bMinsTilOff:=bMinsTilOff-1 instead of dec(bMinsTilOff) because I read in the Delphi help file
that no range checking is done during dec. bMinsTilOff should never equal a value outside of the range
valid for bytes... but if everything that "shouldn't" happen in my programs stopped happening I'd stay
awake nights worrying.

Look at the code. I think you'll see how it works as long as you remember that timerMinsTimer is
automatically called once a minute.

Look at the next bit of code. "Decodetime" and "Now" are built into Delphi.

Just after decodetime, I assemble a string with the current time (HH:MM) and display that on the screen.
Seeing this change is a reassurance that Windows hasn't frozen up. It is also a quick, easy way for the
user to see that the computer's clock agrees with the real world.

The next six lines (including the two "end"s in the count), the lines beginning "if(cbFanOnOff.checked)
and (bMinsTilOff=255)...." work as follows.

First: The block is skipped if "Turn On / Off Repeatedly" is not checked.


The block is skipped if bMinsTilOff is not 255. This will be the case when "Fan On for 10" has been
clicked less than ten minutes ago. We are still counting down that "Fan on" command.

If the above conditions are met, we then go off to SeeIfThisHourEnabled returns "true". The code for
checking whether this is one of the hours we want the fan to go on and off "boils down" to a simple
"true" or "false". By putting that code in it's own procedure, we can look at the details when we need
them, and not be distracted when we don't.

The line "if (boTmp) and ((wMin div 10)mod 3 = 0) then..." may need a little explanation. boTmp is true
if this is one of the hours "on / off" behaviour is wanted. wMin was filled with the current "minutes past
the hour" back when we called decodetime. If you div a number by 10, you get the integer part of
dividing the number by 10. Examples: 0 div 10=0, 3 div 10=0, 10 div 10=1, 13 div 10=1, 58 div 10=5. In
essence, we have stripped the "tens" digit off of the minutes past the hour. Now we apply "mod 3" to
that. We are only going to encounter 0-5, so I'll just tell you what x mod 3 is for that range:

0 mod 3=0
1 mod 3=1
2 mod 3=2
3 mod 3=0
4 mod 3=1
5 mod 3=2
From that little table, I think you can see that
(wMin div 10)mod 3
will equal zero when the minutes past the hour (wMin) is in the ranges 0-9 and 30-39 (inclusive).

It may seem a little clumsy to "turn the fan on" once a minute for ten minutes, even though it isn't turned
off after the first minute, and to "turn it off" once a minute for twenty minutes, but (if nothing else

http://sheepdogguides.com/dt3i.htm (4 of 6) [1/28/2005 3:45:34 PM]


Delphi: Inter-acting checkboxes and boolean variables

happens) the "turn it on/ off again" doesn't actually do anything. It's about like pushing down on a light
switch that is already down. Furthermore, if the "Fan On for 10" button is clicked, the "on / off" code
isn't called while the ten minutes tick by... but whenever it ends, if the "Turn On / Off" checkbox is
checked, the program resumes the "on / off" cycle. It is not so much a "turn off FOR twenty minutes after
being on" as a "Be off (when cycling) DURING 10-29 and 40-59 minutes past the hour."

That just about does it...

The only procedure we haven't discussed is cbFanOnOffClick. This is executed when you check the
checkbox for "Turn On / Off repeatedly". I was torn here. In some ways, I would have like the fan to
come on immediately, staying on for ten minutes from when the checkbox was checked, and then off for
twenty, on for ten, etc. However, I decided that it was better if the "on" period was always 0-9 and 30-39
minutes past the hour. That way, while you were in the house, if the fan was on when it "should" be off,
or vice versa, you had a better chance of noticing something was wrong.

Another little detail. Remember the checkbox cbEnablePort? It is not checked initially, so you must
check it if you want the program to control a real fan. The default "do everything except change outputs"
state is safer, but what if you have a system set up, and you want it to self boot in your absence after, say,
a power failure? One way around that sort of problem (other than having a specially compiled version of
the program with cbEnablePort checked by default) is to add the following to the FormCreate procedure,
just after boEnPort:=false;....
ADD THIS: if paramstr(1)="PortOn" then boEnPort:=true;

Compile the program. Following instructions are for Win9x, but similar things can be done with other
Windows. Create a shortcut to the .exe file. Right click on the shortcut. Add "PortOn" to the shortcut's
"target" designation. Put the shortcut in your "Start Menu | Programs | Start Up" folder. Now when you
boot your computer, the fan control program will start, with boPortOn set to true. You have used a
Command Line Parameter (clp). The programming shown here is very crude. It won's, for instance,
recognise PORTON. but you could fix that, couldn't you? You can read more in my tutorial on clps.

I hope you found useful things in that!

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

http://sheepdogguides.com/dt3i.htm (5 of 6) [1/28/2005 3:45:34 PM]


Delphi: Inter-acting checkboxes and boolean variables

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt3i.htm (6 of 6) [1/28/2005 3:45:34 PM]


Delphi: Displaying Images / Accessing Files

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

Delphi: RS-232, serial comms, COM1, COM2


This has good information, and a search button at the bottom of the page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

This is only a draft, sorry. I ran out of time while working on it. The program is working and necessary
information is complete here, but the explanations may be a little hard to follow in places. The whole code for
the program does appear at the end of the page, however.

This is written for Delphi 2.

This tutorial starts by showing you how to display a bitmap on a form. It goes on to product a little learning aid
which diosplays a bitmap and then gives you three buttons, each with a different label.

I wrote the program along the way to a program for learning pupils' names at the start of the school year. I'll
have a folder with a bitmap of each pupil's face. The files will be named with the children's names. The program
will display one photo and three filenames, e.g. Huey, Duey and Luey. When I click on the name of the child
whose picture is showing, I'll get the next picture. The same prigram, with a different selection of bitmaps in the
folder, could be used for learning anything that matches an image with a short name- countries by their shape,
breeds of dog, names of colors, names of chemistry glassware.... etc! If you develop a set of bitmaps from
images you are entitled to distribute, I'd be interested in discussing making them available to a wider audience.

=================
Start a new project. From the "Additional" tab of component pallette add an "Image" component to the project's
form.

Set up folder with 4 bitmaps. (In a laer draft of htis, I will explain how.) Name them Huey.bmp, Duey.bmp,
Luey.bmp, Other.bmp. Make them EASY to recognise... I just used "H", "D", "L" and "O". Easy-to-get
"questions will speed your debugging work.)

Put three buttons under the image component. Name buAns1, buAns2, buAns3. (Digress on sizing, aligning
nicely.

Put a "New Question" button on form, name it buNewQ

Now, for an initial quick check: Copy "Huey.bmp" to root of C:. Create BuNewQClick event handler:

image1.picture.loadfromfile('C:\Huey.bmp');

... and get program running. It should display Huey.

Now, to get away from having to work in root directory....

http://sheepdogguides.com/dt3j.htm (1 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

Add a DirectoryListBox and a FileListBox to the form from the System tab of the components pallette.

Access the Events tab of DirectoryListBox1; double click in the field for the OnChange event. Enter the
following as the OnChange handler:

FileListBox1.Directory := DirectoryListBox1.Directory;

(explain why above)

Run program, just to see if you can now navigate backing store.

Set filelistbox1's mask property to *.bmp. (Image copmponents can also display metafiles (.WMF) and icons
(.ICO). If you want to use those for this program, you can add the capability with few changes to what is
presented here.)

Add a lable to your form. Name it laAvailImages. Add an event handler for FileListBox1Change which says....

laAvailImages.caption:='Available images: '+inttostr(FileListBox1.Items.Count);

Now as you navigate the backing store, you should see the number of *.bmp files in whatever folder you are
looking at in the newly created label. Add a global variable (explain how-- iAvailFiles:integer under form's
"private" section. While at it: Add sTmp:string; there (will need in a moment)) called iAvailFiles. Revise the
FileListBox1Change event handler to say....

iAvailFiles:=FileListBox1.Items.Count; laAvailImages.caption:='Available images: '+inttostr(iAvailFiles);

Nearly there!

Add a FormCreate handler which says....

iAvailFiles:=FileListBox1.Items.Count;

Replace your simple, test, buNewQClick with

if iAvailFiles<4 then begin


showmessage('You need to be in a directory with more images');
end (*no ; here*)
else begin
sTmp:=(FileListBox1.Items[random(iAvailFiles)]);
image1.picture.loadfromfile(sTmp);
end; (*else*)
Now when you run the program, you should be able to see all of the images if you click the New Question
button often enough. (They should come up in a random sequence. Add "Randomize" to the FormCreate
handler to get a different "random" sequence each time you run the program. (That's not as daft as it seems, but
a topic for another day!)

http://sheepdogguides.com/dt3j.htm (2 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

So that you don't have to continually re-navigate the directory, you can add

DirectoryListBox1.Directory:='C:\My Documents\Delphi\DD30\Bitmaps';

as the first line of the FormCreate event handler if...

a) Your bitmaps are in the same place on your disc as they are on mine, AND
b)You want to do something simple, but Really Dumb!

When the program is finished, you can set the "Start In" property of a shortcut to the program to the required
directory. There's probably a better way to do what I wanted, but it doens't occur to me at the moment. You
could use an .ini file, but that's going out of favor with Redmond. Not as bad as the hard coding that is the most
easily understood solution!

So! Now you (should have) the essential hard bits in place: You can display randomly selected images on your
form.

All that's left is to build the "test learner" elements of the program. Remember that in this simple approach, the
correct "answer" for the name of any image is the image's filename. I.e. if we are learning the names of people,
their images will be labelled with their names.

Add sAnwserIs:string to the global variables (along with sTmp and iAvailFiles)

Just after...

image1.picture.loadfromfile(sTmp);

... in buNewQClick, add

sAnswerIs:=sTmp;
buAns1.caption:=sTmp;
Now when you run the program and click on the New Question button, you should see the name of the
displayed bitmap on the first of the three answer buttons. Assuming that your images will always be names
SOMETHING.bmp, to strip off the ".bmp" part, you can modify what we just added and make it...

sAnswerIs:=copy(sTmp,1,length(sTmp)-4);
buAns1.caption:=sAnswerIs;
Now... what we have so far is not a very hard test! We need "distarctors", i.e wrong answers, and we should
make it so that the right button to click is not always the first one!! (And we need to create handlers for the three
answer buttons.

First we're going to make a procedure to set the answer buttons and underlying variables. First, name the form
DD30. (30th Delphi Demo) (You can give it a name that suits you better, but if you do, there will be places in
the following where you have to substitute your name for my "DD30".) Then enter...

procedure SetUpAnswerButtonsEtc;

http://sheepdogguides.com/dt3j.htm (3 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

... just after....

procedure FormCreate(Sender: TObject);

... in the form's type declaration.

Then, just after....

implementation
{$R *.DFM}
add something just to make sure the basics are okay:

procedure TDD30f1.SetUpAnswerButtonsEtc;
(*Before calling this procedure....
1) The folder the images are in must have
been selected via DirectoryListBox1 and
FileListBox1.
2) iAvailFiles must have been set.
3) sAnswerIs must have been set.
*)
begin
buAns1.caption:=sAnswerIs;
buAns2.caption:='Two';
buAns1.caption:='Three';
end;
Now replace the last line of buNewQClick (which at present should be "buAns1.caption:=sAnswerIs;") with....

SetUpAnswerButtonsEtc;

Now when you run the program and click the "New Question" button, the first button should become labelled
with the name of the displayed bitmap, and the other two should become named "Two" and "Three".

Next we'll put some odd names on those other two buttons....

Rewrite SetUpAnswerButtonsEtc so that it becomes.....

procedure TDD30f1.SetUpAnswerButtonsEtc;
(*Before calling this procedure....
1) The folder the images are in must have
been selected via DirectoryListBox1 and
FileListBox1.
2) iAvailFiles must have been set.
3) sAnswerIs must have been set.
*)
begin
buAns1.caption:=sAnswerIs;
repeat

http://sheepdogguides.com/dt3j.htm (4 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

sTmp:=(FileListBox1.Items[random(iAvailFiles)]);
sTmp:=copy(sTmp,1,length(sTmp)-4);
until sTmp<>sAnswerIs;
buAns2.caption:=sTmp;
repeat
sTmp:=(FileListBox1.Items[random(iAvailFiles)]);
sTmp:=copy(sTmp,1,length(sTmp)-4);
until (sTmp<>sAnswerIs) and (sTmp<>buAns2.caption);
buAns3.caption:=sTmp;
end;
This is pretty crude, and it leaves the first button as always the right answer. When you are sure you see what is
going on above, reprogram SetUpAnswerButtonsEtc again to make it the following, which is less pedestrian but
more elegant, AND it "shuffles" the captions of the buttons so that the right button is not always the first button.

procedure TDD30f1.SetUpAnswerButtonsEtc;
(*Before calling this procedure....
1) The folder the images are in must have
been selected via DirectoryListBox1 and
FileListBox1.
2) iAvailFiles must have been set.
3) sAnswerIs must have been set.
*)
var sTmp2,sTmp3,sTmpTmp:string;
c1:byte;
begin
buAns1.caption:=sAnswerIs;
repeat
sTmp2:=(FileListBox1.Items[random(iAvailFiles)]);
sTmp2:=copy(sTmp2,1,length(sTmp2)-4);
until sTmp2<>sAnswerIs;
repeat
sTmp3:=(FileListBox1.Items[random(iAvailFiles)]);
sTmp3:=copy(sTmp3,1,length(sTmp3)-4);
until (sTmp3<>sAnswerIs) and (sTmp3<>sTmp2);
sTmp:=sAnswerIs;
(*Shuffle (Could probably be improved!)*)
if random>0.5 then begin
sTmpTmp:=sTmp;
sTmp:=sTmp2;
sTmp2:=sTmpTmp;
end;
if random>0.5 then begin
sTmpTmp:=sTmp;
sTmp:=sTmp3;
sTmp3:=sTmpTmp;
end;
if random>0.5 then begin
sTmpTmp:=sTmp2;

http://sheepdogguides.com/dt3j.htm (5 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

sTmp2:=sTmp3;
sTmp3:=sTmpTmp;
end;
if random>0.5 then begin
sTmpTmp:=sTmp;
sTmp:=sTmp3;
sTmp3:=sTmpTmp;
end;
(*Shuffle finished*)
buAns1.caption:=sTmp;
buAns2.caption:=sTmp2;
buAns3.caption:=sTmp3;
end;
We're now going to create a single chunk of code to handle the clicking of any of the three answer buttons. It
will need to check whether the right button was pressed, and respond accordingly. That will include generating
a new question if the current question is answered correctly.

Before we can do that, we need the following....

Near the top of the sourcecode, in the type declaration, after...

procedure SetUpAnswerButtonsEtc;

... add ...

procedure ChooseOne;

After....

implementation
{$R *.DFM}
... add...

procedure TDD30f1.ChooseOne;
begin
end;
... BUT DON'T TRY TO COMPILE OR RUN YET.

First, copy everything from between the begin and end of buNewQClick to between the begin and end of
ChooseOne, and replace everything from between the begin and end of buNewQClick with "ChooseOne".

Now to produce the event handler which takes care of a click on any of the Answer buttons. Start by going to
the form and clicking on the first answer button.The hold down the shift key, and click on the other two answer
buttons. You should find that all three are selected. You could also select them by dragging a selection box
around them. Now click on the Events tab of the Object inspector and double click on the field to the right of
the "OnClick" event. The system will assign a name of buAns1Click, and create the skelton of a handler in your
source code. Fill it in as follows....

http://sheepdogguides.com/dt3j.htm (6 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

procedure TDD30f1.buAns1Click(Sender: TObject);


var sPrevRight:string;
begin
if sender=buAns1 then sTmp:=buAns1.caption;
if sender=buAns2 then sTmp:=buAns2.caption;
if sender=buAns3 then sTmp:=buAns3.caption;
(*I suspect that the previous three lines can be
done more elegantly. sTmp:=sender.caption
didn't work.*)
if sTmp=sAnswerIs then begin
sPrevRight:=sAnswerIs; (*Prevent same question arising twice in a row*)
repeat
ChooseOne;
until sAnswerIs<>PrevRight;
end;
end;
The name of that handler, buAns1Click, is misleading. DO NOT TRY TO EDIT THE NAME WITHIN THE
SOURCECODE! Instead, go to the Object Inspector (press f11), get to the OnClick field for any of the answer
buttons, e.g. buAns1, and edit the name in the OnClick field. All necessary changes will be made in your source
code. (References to the old name, buAns1Click won't be altered, however, if they are in program comments.)

=======
The code we have produced could probably be tidied up, and could certainly be extended, but I hope it is
sufficient to work in a simple way, and to have illustrated some things for you.

=======
As promised, here is the full listing of the finished program...

unit MGA14u1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, FileCtrl, ExtCtrls, Buttons;

type
TMGA14f1 = class(TForm)
Image1: TImage;
buNewQ: TButton;
FileListBox1: TFileListBox;
DirectoryListBox1: TDirectoryListBox;
laAvailImages: TLabel;
meCopyright: TMemo;
buCopyrightOK: TButton;
Button1: TButton;

http://sheepdogguides.com/dt3j.htm (7 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
BitBtn3: TBitBtn;
procedure buNewQClick(Sender: TObject);
procedure DirectoryListBox1Change(Sender: TObject);
procedure FileListBox1Change(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure SetUpAnswerButtonsEtc;
procedure ChooseOne;
procedure buAllAnsClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure buCopyrightOKClick(Sender: TObject);
private
{ Private declarations }
iAvailFiles:integer;
sTmp,sAnswerIs,sPrevRight:string;
public
{ Public declarations }
end;

var
MGA14f1: TMGA14f1;

implementation

{$R *.DFM}

procedure TMGA14f1.ChooseOne;
begin
if iAvailFiles<4 then begin
BitBtn1.enabled:=false;
BitBtn2.enabled:=false;
BitBtn3.enabled:=false;
showmessage('You need to be in a directory with more images');
end (*no ; here*)
else begin
BitBtn1.enabled:=true;
BitBtn2.enabled:=true;
BitBtn3.enabled:=true;
repeat
sTmp:=(FileListBox1.Items[random(iAvailFiles)]);
image1.picture.loadfromfile(sTmp);
sAnswerIs:=copy(sTmp,1,length(sTmp)-4);
SetUpAnswerButtonsEtc;
until sAnswerIs<>sPrevRight;
end; (*else*)
end;

http://sheepdogguides.com/dt3j.htm (8 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

procedure TMGA14f1.SetUpAnswerButtonsEtc;
(*Before calling this procedure....
1) The folder the images are in must have
been selected via DirectoryListBox1 and
FileListBox1.
2) iAvailFiles must have been set.
3) sAnswerIs must have been set.
*)
var sTmp2,sTmp3,sTmpTmp:string;
c1:byte;
begin
repeat
sTmp2:=(FileListBox1.Items[random(iAvailFiles)]);
sTmp2:=copy(sTmp2,1,length(sTmp2)-4);
until sTmp2<>sAnswerIs;
repeat
sTmp3:=(FileListBox1.Items[random(iAvailFiles)]);
sTmp3:=copy(sTmp3,1,length(sTmp3)-4);
until (sTmp3<>sAnswerIs) and (sTmp3<>sTmp2);
sTmp:=sAnswerIs;
(*Shuffle (Could probably be improved!)*)
if random>0.5 then begin
sTmpTmp:=sTmp;
sTmp:=sTmp2;
sTmp2:=sTmpTmp;
end;
if random>0.5 then begin
sTmpTmp:=sTmp;
sTmp:=sTmp3;
sTmp3:=sTmpTmp;
end;
if random>0.5 then begin
sTmpTmp:=sTmp2;
sTmp2:=sTmp3;
sTmp3:=sTmpTmp;
end;
if random>0.5 then begin
sTmpTmp:=sTmp;
sTmp:=sTmp3;
sTmp3:=sTmpTmp;
end;
(*Shuffle finished*)
BitBtn1.caption:=sTmp;
BitBtn2.caption:=sTmp2;
BitBtn3.caption:=sTmp3;
BitBtn1.font.color:=clBtnText;
BitBtn2.font.color:=clBtnText;
BitBtn3.font.color:=clBtnText;

http://sheepdogguides.com/dt3j.htm (9 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

end;

procedure TMGA14f1.buNewQClick(Sender: TObject);


begin
sPrevRight:=sAnswerIs;
ChooseOne;
end;

procedure TMGA14f1.DirectoryListBox1Change(Sender: TObject);


begin
FileListBox1.Directory := DirectoryListBox1.Directory;
end;

procedure TMGA14f1.FileListBox1Change(Sender: TObject);


begin
iAvailFiles:=FileListBox1.Items.Count;
laAvailImages.caption:='Available images: '+inttostr(iAvailFiles);
end;

procedure TMGA14f1.FormCreate(Sender: TObject);


begin
sPrevRight:='';
meCopyright.hide;
buCopyrightOK.hide;
iAvailFiles:=FileListBox1.Items.Count;
Randomize
end;

procedure TMGA14f1.buAllAnsClick(Sender: TObject);


begin
if sender=BitBtn1 then sTmp:=BitBtn1.caption;
if sender=BitBtn2 then sTmp:=BitBtn2.caption;
if sender=BitBtn3 then sTmp:=BitBtn3.caption;
(*I suspect that the previous three lines can be
done more elegantly. sTmp:=sender.caption
didn't work.*)
if sTmp=sAnswerIs then begin (*Act on right answer*)
sPrevRight:=sAnswerIs; (*Prevent same question arising twice in a row*)
repeat
ChooseOne;
until sAnswerIs<>sPrevRight;
end (*no ; here*)
else (*Act on wrong answer*)
begin
if sender=BitBtn1 then BitBtn1.font.color:=clred;
if sender=BitBtn2 then BitBtn2.font.color:=clred;
if sender=BitBtn3 then BitBtn3.font.color:=clred;
end;(*else*)

http://sheepdogguides.com/dt3j.htm (10 of 11) [1/28/2005 3:45:39 PM]


Delphi: Displaying Images / Accessing Files

end;

procedure TMGA14f1.Button1Click(Sender: TObject);


begin
meCopyright.show;
buCopyrightOK.show;
end;

procedure TMGA14f1.buCopyrightOKClick(Sender: TObject);


begin
meCopyright.hide;
buCopyrightOK.hide;
end;

end.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar
Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this
doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for more
information.

http://sheepdogguides.com/dt3j.htm (11 of 11) [1/28/2005 3:45:39 PM]


Delphi: DLLs and Accessing Port Hardware

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

Delphi: DLLs and Accessing Port Hardware


There are two needs which could make you want to study this tutorial.

If you want to call things from a .DLL, this tutorial shows you how.

If you want to attach electronics of your own devising to your PC via the parallel port, this tutorial tells you about
the software issues... and there is a link to answers about the hardware.

October 2003: Thank you Logix4U, Programmer's Heaven and Everyday with Practical Electronics magazine!
Life just got easier for anyone wanting to access the parallel port (I know) or the serial port (I'm told). At last! A
single method that works for Win 9x, NT, 2000 and XP. Without much messy overhead.

If you want to know more about the hardware side of using the parallel port, that information is at my parallel
port page.

Before explaining The Good Stuff, a little background on two issues....

Issue 1: Back in the late 1980s, if you wanted to wink some LEDs on and off, you wired them to a printer cable,
and then wrote a program which changed the value stored in a specific memory location. In Basic, the command
was POKE, in Pascal, we used PORT. This worked even in early versions of Windows, and Delphi 1 still had a
PORT command.

Then Windows got "better". Direct access to specific memory locations became a bad idea, and from Delphi 2 the
PORT command was missing.

Issue 2: One of the strengths, I think, of Delphi is that, in general, you don't use DLLs. As much as I like that, in
the case of solving the read/write parallel port problem I was prepared to look at using one... and I was delighted
to find that things aren't very complicated. From that you should infer a warning: I'm not experienced in matters
DLL... but the following works for me. Please educate me if anything in it is wrong or unwise!

As I understand DLLs, at least as far as is necessary to use the port reading/writing DLL from Logix4U, a DLL is
a discrete file in your system which has a header which allows other programs to interact with it. The bulk of this
tutorial is about how to make a program written by you interact with someone else's DLL. If that made sense,
then skip down to "end of another attempt".

If that didn't make sense, here's another attempt to explain the beauty of DLLs:

Suppose Delphi had no easy way to double a number. Suppose someone kindly created a DLL to do that job. You
wouldn't need to know HOW they doubled the number.... all you need to know about is how to use their DLL.

In the Delphi that we DO have, you'd merely say....

bAns:=bBefore * 2;

http://sheepdogguides.com/dt3k.htm (1 of 6) [1/28/2005 3:45:43 PM]


Delphi: DLLs and Accessing Port Hardware

In the mythical Delphi with no "*2", but with the hypothetical DLL, you'd do....

bAns:=DoubledByDLL(bBefore);

The name "DoubledByDLL" is just something I made up, like the variable names. The name that you would use
would be determined by the author of the DLL. The DLL can be thought of as a library of routines that are
available to you, much as functions that you provide within your program are available within the program.

.
(End of "another attempt".)
Moving on.... we're nearly to the part of the tutorial in which we'll write a program to access the parallel port...

One detail, and two worries laid to rest, I hope.

I like my system to stay nice and simple. Windows crashes often enough without any help from me. I've always
disliked DLLs because I don't know what they're up to, because of the clutter they add, and because of the
potential for confusion. Consider the following: Suppose two packages EACH come with a DLL called
FredsStuff..... but the stuff in the two DLLs is not the same. The answer, I'm told, is that if the FredsStuff.DLL
that came with package A is installed in the folder holding package A's .exe file, and B's is in B's folder, then all
is well.

Now suppose you have three packages, living nicely each in their own folders, which all use a DLL with a name
that no one else is using. The three DLLs are identical in content as well as in name. Do you need to have three
copies of the DLL? No. You can put one copy in the Windows system folder (usually C:\Windows\System\), and
all should be well.

A warning: Please be very careful when working with this software. Other than seeing, in general, how to use
DLLs, there's no point unless you are also doing some hardware things.... and mistakes there CAN DAMAGE
YOUR COMPUTER. See my page about using the parallel port for more information on the risks, and more
advice on the things that "should" be okay.... but I ACCEPT NO LIABILITY FOR ANYTHING THAT
ARISES from your use of this material. Now we can put the lawyer back in his box, I hope.

Another chore before we start to program: You need to find the address of your parallel port. If this paragraph
daunts you, just try $378 for the port address. In Win 9x, right click on "My Computer", click on "Properties",
and click on the "Device Manage" tab. There should be a "ports" entry in the list. Expand that if it is collapsed,
double click the "Printer Port" line. Select the resources tab. Look at the first "Input/Output range" line. Make a
note of the first number there. It will probably be 0378. That's your printer port's first address. It is expressed in
hex. Just put a dollar sign in front of it when you type it into your program, and all will be well.
At last... a program... (This was written on a Delphi 2 system):

Start a new project (application).

Put a label on the form, big enough for a 3 digit number.

Add a scroll bar. (ScrollBar object is on the "standard" tab.)

Most of the default properties are fine, but change the following:

http://sheepdogguides.com/dt3k.htm (2 of 6) [1/28/2005 3:45:43 PM]


Delphi: DLLs and Accessing Port Hardware

Max:255
Min:0
Doubleclick on the scroll bar. This will create an empty "Change" event handler. Put the following in between the
"begin" and the "end":

Label1.caption:=inttostr(ScrollBar1.position);

Run the program. Moving the scroll bar thumb tab should cause the number showing in the label to change.

(If you know about hex numbers, and how easily they convert to binary in your head, you might want to use...

Label1.caption:=inttohex(ScrollBar1.position,2);

... so that when we get the program writing to the parallel port you can more easily see if what you are getting is
RIGHT! But if you don't see what I'm talking about, you can just ignore this.)

Put a copy of inpout32.dll from www.logix4u.net into the same folder as your project. You can download a zip
file with that and a whole bunch of related stuff from Logix4U by clicking here. (With WiunZip, you can pull
just the DLL out of the archive after you've downloaded it.

And, finally, make sure that your printer is NOT plugged into your printer port (!), and then...

Revise all of ScrollBar1Change so that it becomes what you see below. If your parallel port wasn't at $378
change the reference to $378!

procedure TForm1.ScrollBar1Change(Sender: TObject);


var bWriteMe, bErr:byte;
function Out32(wAddr:word;bOut:byte):byte; stdcall; external 'inpout32.dll';
begin
bWriteMe:=ScrollBar1.position;
Label1.caption:=inttostr(bWriteMe);
bErr:=(Out32($378,bWriteMe));
end;
... and when you run it, and move the scollbar thumb tab. The state of the parallel port's data pins should change.
You can see them change with a voltmeter, or a simple circuit with a few LEDs and resistors

A little mystery: On one system I was using, I did get changing states on the data pins... but they were exactly the
opposite of what I expected.

In the code above, the TForm1. may be different in what will be right for you. It simply derived from the name
of the form, as usual. The Out32 has to be Out32 to achieve the connection to the DLL. bWriteME and bErr
could be changed to names of your preference.

If you get "Debugger kernal error. Error code:1", then look to see if the .dll is in the right place, or to see if you
are trying to call a function not present in the dll. Also, for either "problem", a simple typo may be the reason for
the error message. The computer won'd find Out32 if you've told it to look for Out23!!.

http://sheepdogguides.com/dt3k.htm (3 of 6) [1/28/2005 3:45:43 PM]


Delphi: DLLs and Accessing Port Hardware

WARNING: While this works, I may have used the wrong data types for one or more of bWriteMe, bErr, and
wAddr. I will try to get this uncertainty cleared up.

Putting the $378 in as it appears above is fine in a tiny demo program. In a bigger program, where there might be
several references to the printer port address, it would be best to put....

const PrinterPortAddr=$378;

... near the start of your program, and just use PrinterPortAddr when you want to refer to the printer port address.
Half of you, gentle readers, will not need to be told this. The other half of you won't see why it is a good idea.
Trust me? Do it this way, and one day you'll thank me!

Yes... bErr should be tested to see that all was well. I'm not sure what value you should look for, though. The
documentation at www.logix4u.net is good. You can find it there if you're going to test bErr.

So much for sending things to the parallel port.

Now for reading things from it.

Fancy modern ports can support bi-directional use of the main data pins. I'm not going to get into that here. I am
going to show you how to get input across the 4 bits that have always been for input.

Inputs: If you read address PrinterPortAddr+1 (i.e. $379 on most machines), you can discover the state of 5 pins.
They determine the state of bits 3-7 of the byte at PrinterPortAddr+1. The bits are mapped and named as follows:

Bit Pin Name


3 15 Error
4 13 Select In
5 12 Paper Empty
6 10 Acknowledge
7 11 Busy
(A trap for the unwary... 'Busy' is inverted 'just inside' the computer. Thus if you apply a '1' to all of the pins,
you'll see 01111xxx when you read 889! Isn't computing fun?)

Add second label and a button to your form, and make the button do the following when clicked:

procedure TForm1.Button1Click(Sender: TObject);


function Inp32(wAddr:word):byte; stdcall; external 'inpout32.dll';
begin
label2.caption:='When last read, the port was showing '+
inttostr((Inp32($379)and $F8));
end;
(The "and $F8" stuff just hides the three bits that are not inputs and could each be 0 or 1.)

http://sheepdogguides.com/dt3k.htm (4 of 6) [1/28/2005 3:45:43 PM]


Delphi: DLLs and Accessing Port Hardware

Again: The $379 will work on most machines, but if your printer port isn't at $378, then you just use a number
which is one more than where your printer port is. Also again: You can't change the name "Inp32", and I may
have assigned the wrong types to things.

Now: That wasn't too bad, was it? The good news: It will work, you could just use it. There is another way of
calling functions from DLLs, which is probably better in some ways, though it is less transparent, and requires
some memory management.

I haven't been able to write this alternative up yet.... but everything you need to know is at the great guide to
calling things in DLL with Delphi at... an article at Programmer's Heaven.

At the beginning of this, I thanked Logix4U, Programmer's Heaven and Everyday with Practical Electronics
magazine. It was EPE that told me about the DLL's availablility (pg. 698, Oct 2003). Logix4 are big heros, of
course, for releasing the DLL and its sourcecode as freeware. I learned how to une the functions in a DLL from
the article at Programmer's Heaven.
Here's another thing about parallel port access as a footnote... and thanks to Martijn Haak in the Netherlands for
contributing this....

The BIOS data segment (40h) in your pc has a table with the address(es) of the parallel port(s) in your system.

0040:0008 has the address of LPT1, usually 378h


0040:000A has the address of LPT2
0040:000A has the address of LPT3, and
0040:000A has the address of LPT4

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar
Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... 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 an MS-DOS or Windows 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

http://sheepdogguides.com/dt3k.htm (5 of 6) [1/28/2005 3:45:43 PM]


Delphi: DLLs and Accessing Port Hardware

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

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi,
and they provide promotional services, too. Click the "Help get this site publicity" link above for more
information.
{end}

http://sheepdogguides.com/dt3k.htm (6 of 6) [1/28/2005 3:45:43 PM]


Delphi: Writing to the printer a line at a time

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

Delphi: Writing to the printer a line at a time

Tutorial written and tested in Delphi 2, on a Win98 machine, but the code should be pretty generally applicable.

Problem: I had a fine program from the days of Turbo Pascal / DOS / line oriented printers. I wanted to port it to Windows
with minimal fuss.

Good news: It didn't do anything too clever with printer control codes.... I (mostly) assembled a line, then sent it to the printer.

The line of code in Turbo Pascal (TP) which printed a line of text was writeln(lst,"Line of text") (The first parameter is LST,
not "First". LST for LiSTing device, aka LPT1) If you sent...

write(lst,'Line ')
write(lst,'of ')
writeln(lst,'text')

... then the first two lines of code (N.B. "write", not "writeln") sent stuff to the printer where it was held in a buffer. As soon as
you did a writeLN(lst,... you got what was in the buffer, plus anything specified by the writeln.

The objective was to create a Delphi equivalent to be called SendLine which had a single string type parameter, i.e. the Delphi
equivalent of writeln(lst,'Line of text') will be SendLine('Line of Text'), and equivalent of write(lst,'Part of line of text') will be
AddToLine('Part of line of Text'). The editor's search and replace facility should make converting the program code easy...
change all {writeln(lst,} to {SendLine(} should do it!

Windows may require fancier "Init printer" and "Close printer" stuff... we'll see. In TP you just used the printer without
explicitly opening the channel to it. You did, however, often send "control codes" to set the printer's font, etc. There was no
"Close printer" code needed, other than ensuring that your program had a writeln(lst, after any near-the-end writeln(lst,
commands.

For the sake of this tutorial, imagine that the old program was....

InitForPrinterOutput;
StartANewPage;
writeln(lst,'1st line of text');
writeln(lst,'2nd line of text');
writeln(lst,'3rd line of text');
StartANewPage;
writeln(lst,'Pg2 1st line');
writeln(lst,'Pg2 2nd line');
write(lst,'A bit of a third line ');
writeln(lst,'of text ');
writeln(lst,'The end');
FinishPrinting;

Start a project in the usual way. I called my DD40

To start with, we'll attempt the time honored job of outputting "Hello World".. but outputting it to the printer when a button is
pushed.

http://sheepdogguides.com/dt3l.htm (1 of 7) [1/28/2005 3:45:48 PM]


Delphi: Writing to the printer a line at a time

Here's a quote from the Delphi 2 helpfile that may have stuff some users will need...

"The Printer function creates an instance of a global TPrinter object the first time it is called. Use the Printer function when
you want to print using the TPrinter object. Printer is declared in the Printers unit. Whenever you use the Printer function and
the TPrinter object, you must add Printers to the uses clause of your unit.

"Note: : Code which assigned to the Printer global variable in Delphi 1.0 will need to be changed to call the SetPrinter function
instead. This allows the entire contents of the Printers unit to be smart linked out if nothing in the program explicitly uses
printers or calls Form.Print."

Add "Printers" to the form's uses clause.

Put a button on the form

Double click it

Insert the following code (again, taken from the Delphi 2 help file) in the event handler....

Printer.BeginDoc;
Printer.NewPage; (*See comment*)
Printer.Canvas.TextOut(300,300, 'Hello World');
Printer.EndDoc;
That was pretty painless! Don't worry all of this will soon descend into the painful depths you know so well.

Minor comment on NewPage (just ignore this, leave NewPage in if in doubt): I think you can leave NewPage out if you know
that there is nothing left over from previous uses of the printer within a running program. I was getting a blank sheet for each
run of the program which I think traces to the NewPage.

First point: When there has been a call of BeginDoc, there should be a call of EndDoc later. (No output is seen, by the way,
until the EndDoc is processed, unlike the old DOS days when typically lines were printed as soon as they were ready.) Of
course, in the example, there's little danger of a BeginDoc happening without the an EndDoc. In a more realistic case, you may
want to have a boolean variable, say "boDocBegunNotEnded which you set false during formcreate, true after a BeginDoc, and
false again after an EndDoc. The help file does tell us that "The Close procedure calls the EndDoc method."... but I like to be
sure about these things.

Second point: Because you can print anywhere you want on the page (Good! Next to impossible in DOS, and hard even to
simulate it) you can end up putting things on top of each other (Usually bad!) Not only would that happen if you did....

Printer.Canvas.TextOut(300,300, 'Hello World');


Printer.Canvas.TextOut(300,300, 'On top of other');
.... but it would (obviously) also happen if you did....

Printer.Canvas.TextOut(300,300, 'Hello World');


Printer.Canvas.TextOut(301,301, 'On top of other');
Not so obvious: What happens if you do....

Printer.Canvas.TextOut(300,300, 'Hello World');


Printer.Canvas.TextOut(300,400, 'On top of other?');
...? That depends, of course on what point in the two strings is placed at 100,100 and 100,200 (likely the upper left corner) and
on the size of the writing.

Now... vertical spacing is pretty easy to manage by trial and error. (Better methods could be addressed in a more advanced
tutorial. Anyone reading this? Interested? See bottom of page.) Horizontal spacing, usually in Windows, is much more

http://sheepdogguides.com/dt3l.htm (2 of 7) [1/28/2005 3:45:48 PM]


Delphi: Writing to the printer a line at a time

difficult.

Printer.Canvas.TextOut(300,300, 'Hello Worldiiiiiiiiiiiiiiiiiiiiiii');


Printer.Canvas.TextOut(1200,300, 'On same line');
might come out quite nicely... it did on my system. However, in Windows, what you get depends on a whole bunch of
settings... in this case the typeface and character size will have a lot to do with what result you get. Even if the above came out
ok, the following.... with the same number of "W"s as the previous had "i"s did not print nicely on my system.

Printer.Canvas.TextOut(300,300, 'Hello WorldWWWWWWWWWWWWWWWWWWWWWWW');


Printer.Canvas.TextOut(1200,300, 'On same line');
Again... "good" answers to these problems are matters for a more advanced tutorial. For now, we're going to "solve" the
problems by using a font with a fixed pitch: Courier New.

Replace the two TextOut lines with the following. I am assuming (always a bad idea, and reveals another weak spot in the
program) that you have the Courier New font on your system. If not, substitute another non-proportional font.

Printer.Canvas.font.name:='Courier New';
Printer.Canvas.font.size:=12;
Printer.Canvas.TextOut(300,300, 'y23456789012345678901234567890');
Printer.Canvas.TextOut(1200,300, 'X');
Printer.Canvas.TextOut(700,400, 'World');
Printer.Canvas.TextOut(300,400, 'Hello');
There are a couple of lessons in the output: "Hello World": Notice we "printed" the second word first? There's no need to use
code to generate a page from top left to bottom right. You might "print" headings with a fixed procedure, and then fill in the
fields in a later procedure.

In the first line, a 6 is missing, replaced by an X. You don't see the 6 under the X, as you would if you double typed with an
old fashioned typewriter. There is probably a way to get that effect if you want it, though. (Tell me the details if you chase
them down? Just the setting of a pen property, I'd guess.)

It seems that with 12pt text, line spacing of 100 is adequate, if a little tight. The "y" was there to be sure that descenders aren't
blotted out by subsequent printing of the next lower line.

(A good source of info: Search the help systems for "canvases", then select the subtopic "using the canvas". Of course, if your
Delphi is not version 2, the linking of canvas material may have been improved.)

So! We haven't covered all of "the best way to print to paper with Windows"... but we do have the essentials for what I wanted
to do.

The Delphi program can't be quite as simple as the TP program it is replacing. For each page, printing will now be in three
parts...

Start a page, inside the pc. Fill the internal version with the whole page's text. ... and when everything that's going on the page
has been put on the internal version, Print out the assembled page as real ink, real paper.

Happily, though the concept is slightly different, the outline of the code is the same as long as you always issue a "Finish
Printing" command after the last "writeln(lst," or "write(lst" equivalent... something you didn't need to do in TP programs with
a "writeln(lst" finishing off the printing. Our earlier hypothetical TP program translates as follows:

InitForPrinterOutputWV; (*WV: Windows version*)


StartANewPageWV;
SendLine('1st line of text');
SendLine('2nd line of text');

http://sheepdogguides.com/dt3l.htm (3 of 7) [1/28/2005 3:45:48 PM]


Delphi: Writing to the printer a line at a time

SendLine('3rd line of text');


StartANewPageWV;
SendLine('Pg2 1st line');
SendLine('Pg2 2nd line');
AddToLine('A bit of a third line ');
SendLine('of text ');
SendLine('The end');
FinishPrintingWV;
A real program would need more error checking than I am including here. For instance, it would be necessary to check that
lines were not too long, and that not too many lines were sent to a page.

By the way- a detail: writeln was able to take a variable number of parameters, i.e. to print out the contents of three string
variables, you could do....

writeln(lst,sVar1,sVar2,sVar3);
For our program, that would convert to....

SendLine(sVar1+sVar2+sVar3);
And... continuing with the detail... writeln could print out the contents of various types of variable whereas SendLine requires a
string. Not a problem, thanks to Delphi's rich vocabulary....

writeln(lst,nANumber); becomes SendLine(inttostr(nANumber);

(See Delphi helpfile notes on "floattostr" and "floattostrf" for the fancy stuff. End of detail's resolution)

We're going to have some global variables and constants to help things along. All will have LPR in their names, derived from
"Line Printer Replacement"

const
bLPRheight=100; (*Line pitch, vertical*)

variables (Insert the following just after the "Private" keyword in the Form's type
definition. This makes them "fields" of the form, but you can think of them as
variables.)

sLPRBuffer:string;(*Holds line as it is being assembled from misc AddToLines*)


bLPRYPos:byte;(*Count of line which is next to use. First line: "0"*)
Revise the "Print" button as follows:

procedure TForm1.buPrintStuffClick(Sender: TObject);


begin
InitForPrinterOutputWV; (*WV: Windows version*)
StartANewPageWV;
SendLine('1st line of text');
SendLine('2nd line of text');
SendLine('3rd line of text');
//StartANewPageWV;
//SendLine('Pg2 1st line');
//SendLine('Pg2 2nd line');
//AddToLine('A bit of a third line ');
//SendLine('of text ');
//SendLine('The end');
FinishPrintingWV;

http://sheepdogguides.com/dt3l.htm (4 of 7) [1/28/2005 3:45:48 PM]


Delphi: Writing to the printer a line at a time

Create first attempts at the four procedures as follows. For each, you will also have to make an entry in the form's declaration.
I.e., put the following in to the form's class definition, just before the word "Public". (Procedure declarations have to follow the
field declarations in both the public and the private sections of the class declaration, by the way.)

procedure InitForPrinterOutputWV;
procedure SendLine(sTmp:string);
procedure AddToLine(sTmp:string);
procedure FinishPrintingWV;
And then, just above the final "end." add the following. the lines starting with "//" will have no effect for the moment... get
what does have an effect working first.

procedure TForm1.InitForPrinterOutputWV;
begin
(*Not a lot needed in this simple example... but you might want, for instance,
to assign text to a page header string that gets printed at the start of each
page. This would be the place to do it. In a more complicated case, you
might also want to alter the font, and other things might need changing
as a result, and you would do those things here, too.*)
//Printer.Canvas.font.name:='Courier New';
//Printer.Canvas.font.size:=12;
//Printer.BeginDoc;
end;

procedure TForm1.StartANewPageWV;
begin
sLPRBuffer:='';
bLPRYPos:=0;
//Printer.NewPage;
end;

procedure TForm1.SendLine(sTmp:string);
begin
sLPRBuffer:=sLPRBuffer+sTmp;
showmessage('Would print: '+sLPRBuffer);
//Printer.Canvas.TextOut(300,bLPRYPos*bLPRHeight,sLPRBuffer);
inc(bLPRYPos);
sLPRBuffer:='';
end;

procedure TForm1.AddToLine(sTmp:string);
begin
sLPRBuffer:=sLPRBuffer+sTmp;
end;

procedure TForm1.FinishPrintingWV;
begin
if sLPRBuffer<>''then SendLine(sLPRBuffer);
//Printer.EndDoc;
end;
When the above works, take out most of the "//"s, but, for now, leave in those in the six line block starting with...
StartANewPageWV;

... and take out the... showmessage('Would print: '+sLPRBuffer);

http://sheepdogguides.com/dt3l.htm (5 of 7) [1/28/2005 3:45:48 PM]


Delphi: Writing to the printer a line at a time

As I've worked on this, I've become more convinced that the "Printer.NewPage;" command is not needed before the first page
is printed, but that it is needed between pages. The only problem with the program as it stands is that you get a blank sheet
before the first sensible page.

And, to finish off with, here are some quotes from the Delphi documentation which might help you better understand the issues
raised in this tutorial. Always remember the Delphi "Help" files when you are stuck. Finding what you want takes practice, but
there is a lot of useful material in those files. When you're working on a program, if you need help on "whatsit", all you have to
do is click on the word, and then do ctrl-f1.

============
Fonts Property:
Applies to

TPrinter object; TScreen component

Declaration- property Fonts: TStrings;

Description:

Run-time and read-only. The Fonts property for the screen component returns a list of
fonts supported by the screen.
The Fonts property for a printer object holds a list of fonts supported by the
printer. The list contains TrueType fonts even if the printer doesn't support them
natively because the Windows Graphics Device Interface (GDI) can draw TrueType fonts
accurately when a print job uses them.

============
procedure TextRect(Rect: TRect; X, Y: Integer; const Text: string);

Description:

The TextRect method displays text inside a clipping rectangle. Any portions of the
text passed in the Text parameter that fall "

====
Screen Variable:

Unit: Forms

Declaration- Screen: TScreen;

Description:

The Screen variable is a TScreen component that normally represents your screen
device. By default, your application creates a screen component based on information
from Windows about the current screen device and assigns it to Screen.

Example:

The following code sets the width of a form called Form1 to half the width of the
screen:

Form1.Width := Screen.Width div 2;

======

http://sheepdogguides.com/dt3l.htm (6 of 7) [1/28/2005 3:45:48 PM]


Delphi: Writing to the printer a line at a time

NewPage
Description:

The NewPage method forces the current print job to begin printing on a new page in
the printer. It also increments the value of the PageNumber property and resets the
value of the Pen property of the Canvas back to (0, 0).

{end quotes}
Regarding NewPage: Not to niggle... but in case less experienced users are puzzled..... Part of that is believed to contain an
error... probably should be resets PENPOS back to 0,0 And: The Delphi2 helpfile entry for TPrinter doesn't list Canvas as a
property, but it does imply that there is one. Also TCanvas has a link to TCanvas for TPrinter

Forgive this rather abrupt end?

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


The search engine is not intelligent. It merely seeks the words you specify. It will not do anything sensible with "What does the
'could not compile' error mean?" It will just return references to pages with "what", "does", "could", "not".... etc.
Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... 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 an MS-DOS or
Windows 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

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi, and they
provide promotional services, too. Click the "Help get this site publicity" link above for more information.
{end}

http://sheepdogguides.com/dt3l.htm (7 of 7) [1/28/2005 3:45:48 PM]


Delphi: A Word Search Program

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

Delphi: A Word Search Program

Tutorial written and tested in Delphi 2, on a Win98 machine, but the code should be pretty generally
applicable. You can download the sourcecode and some other stuff.

This program was written to illustrate some points of Delphi programming. There are areas where severe
shortcuts have been taken, e.g. the lack of flexibility over where the output files go, and their names.

The program is not meant to be "finished", or "good"... but it does work, and parts of it are well made.
The rest are started in a manner which does not obstruct eventual fine tuning.

The program asks the user for a set of letters, and then generates all possible combinations of those
letters, sorting the resulting "words" into separate files, depending on the likelihood of that string of
letters is used as a word in English.

I wrote the program with this tutorial half in mind, but inspired by a wish to pull a friend's leg over the
assertion in Dan Brown's "Da Vinci Code" that there are 92 words in "planets". With a version of this
program, I found all of them... but my list included about 11,000 others, too!

This might be a good time to download the sourcecode. If you click on that link, you will receive a self
extracting zip file. It lets you uinzip to the foilder of your choice, and does nothing more than put some
files in the folder you spoecify. Unusually for my archives, one of the included files is an exe file. Run it
to see the word seach program in action.

I will take you through some of the features from the user's point of view. Then, here, and in the
sourcecode, you will find notes on how those feataures were implemented.

The program comes to life with an edit box, a "Go" button, a memo for showing how things are going,
and a "Quit" button. The edit box has "fish" in it, as a default starting point.

Click "Go" and you'll see permutations of the letters in "fish" appear in the memo box. At the same time,
the permutations are being written to output files named DD43R0.txt - DD43R5.txt (Delphi Demo 43
Results, level 0 - 5). The words in DD43R0.txt are known to be real English words. The program's
capability to recognise real words is severely degraded in the version I've put in the zip. If you look
online for "two letter words" scrabble, you will find various lists of dubious or clear copyright status.
Look in the sourcecode for "qTwo" to learn about restoring the dictionary search capability of the
program.

If you modify the word in the edit box, you can check the permutations of other sets of letters. Not that if
you shorten the word to less than three letters, or more than seven letters, the "Go" button is disabled.

http://sheepdogguides.com/dt3m.htm (1 of 3) [1/28/2005 3:45:53 PM]


Delphi: A Word Search Program

This is because the program will not work except for 3-7 letter words. (You could extend the program to
handle longer words. You just add code at "(*Insert deeper layers HERE*)", and extend the
"sCombo:=copy(sCombo,1,5); ClearBoUsed; boUsed[c1]:=true;" stuff you'll find shortly thereafter.) The
mechanism for "turning off" the "Go" button is all in the OnChange event for the edit box, eStartWord.

The second time you run the program, the data output during the first runnning of the program is
over-written. This is very clumsy, as is the fact that the datafiles are put in th e program's folder, but this
tutorial is not about file handling. The code works, however inelegantly. If you want to save results, use
Windows Exploer to move or rename them before re-running the program.

A seven letter word generates about 11,000 permutainos. There would be no point in having all of them
available in the on-screen memo. Examine the sourcecode for the details of how the memo is used to
display just the most recently computed permutations. While the program is running, you can see the
progress as the permutations scroll past. Search the sourcecode for "qMemoScroll" for the heart of that
feature's implementation.

See the sourcecode for other gems. The several such items are flagged with the comment "qOther".

And there you have it! I hope you found some useful things in the code. If you have a webpage, links to
any of my pages would be appreciated.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


The search engine is not intelligent. It merely seeks the words you specify. It will not do anything
sensible with "What does the 'could not compile' error mean?" It will just return references to pages with
"what", "does", "could", "not".... etc.

Also: This search only searches the material on one of my websites.

Click here to visit another of my sites.

Click here to visit my third site.

Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.

http://sheepdogguides.com/dt3m.htm (2 of 3) [1/28/2005 3:45:53 PM]


Delphi: A Word Search Program

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 an MS-DOS or Windows 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

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.
{end}

http://sheepdogguides.com/dt3m.htm (3 of 3) [1/28/2005 3:45:53 PM]


How to Make a Windows Screen Saver in Delphi
(Text version)

[ City Zoo | Announcements | Articles | Tips & Tricks | Bug List | FAQ | Sites ]

How to Make a Windows Screen Saver in Delphi


by Mark R. Johnson

From time to time, I see questions asked about how to make a Windows screen saver in Delphi that can be selected
in the Control Panel Desktop. After seeing a few general responses that only partially answered the question, I
decided to give it a try myself. The code you will see here is the result: a simple Windows screen saver.
The complete Delphi source code for this screen saver is available for FTP as spheres.zip (4K). Before getting into
the details of the code, however, I would like to thank Thomas W. Wolf for the general screen saver tips he
submitted to comp.lang.pascal, which I found helpful in writing this article.

Background
A Windows screen saver is basically just a standard Windows executable that has been renamed to have a .SCR
filename extension. In order to interface properly with the Control Panel Desktop, however, certain requirements
must be met. In general, the program must:
● maintain optional settings

● provide a description of itself

● distinguish between active mode and configuration mode

● disallow multiple copies of itself to run

● exit when the user presses a key or moves the mouse

In the following description, I will try to show how each of these requirements can be met using Delphi.

Getting Started
The screen saver we are going to create will blank the screen and begin drawing shaded spheres at random locations
on the screen, periodically erasing and starting over. The user will be able to specify the maximum number spheres
to draw before erasing, as well as the size and speed with which to draw them.
To begin, start a new, blank project by selecting New Project from the Delphi File menu. (Indicate "Blank project" if
the Browse Gallery appears.)

http://www.mindspring.com/~cityzoo/scrnsavr.html (1 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

Configuration Form
The first thing most people see of a screen saver is its setup dialog. This is where the user specifies values for
options specific to the screen saver. To create such a form, change the properties of Form1 (created automatically
when the new project was begun) as follows:

BorderIcons [biSystemMenu]
biSystemMenu True
biMinimize False
biMaximize False
BorderStyle bsDialog
Caption Configuration
Height 162
Name CfgFrm
Position poScreenCenter
Visible False
Width 266
We want to be able to configure the maximum number of spheres drawn on the screen, the size of the spheres, and
the speed with which they are drawn. To do this, add the following three Labels (Standard palette) and SpinEdits
(Samples palette): (Note: You can select the following text, copy it to the clipboard, and paste it onto the
configuration form to create the components.)

object Label1: TLabel


Left = 16
Top = 19
Width = 58
Height = 16
Alignment = taRightJustify
Caption = 'Spheres:'
end
object Label2: TLabel
Left = 41
Top = 59
Width = 33
Height = 16
Alignment = taRightJustify
Caption = 'Size:'
end
object Label3: TLabel
Left = 29
Top = 99
Width = 45
Height = 16
Alignment = taRightJustify
Caption = 'Speed:'
end
object spnSpheres: TSpinEdit
Left = 84
Top = 15

http://www.mindspring.com/~cityzoo/scrnsavr.html (2 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

Width = 53
Height = 26
MaxValue = 500
MinValue = 1
TabOrder = 0
Value = 50
end
object spnSize: TSpinEdit
Left = 84
Top = 55
Width = 53
Height = 26
MaxValue = 250
MinValue = 50
TabOrder = 1
Value = 100
end
object spnSpeed: TSpinEdit
Left = 84
Top = 95
Width = 53
Height = 26
MaxValue = 10
MinValue = 1
TabOrder = 2
Value = 10
end
Finally, we need three buttons -- OK, Cancel, and Test. The Test button is not standard for screen saver setup
dialogs, but it is convenient and easy to implement. Add the following three buttons using the BitBtn buttons of the
"Additional" palette:

object btnOK: TBitBtn


Left = 153
Top = 11
Width = 89
Height = 34
TabOrder = 3
Kind = bkOK
end
object btnCancel: TBitBtn
Left = 153
Top = 51
Width = 89
Height = 34
TabOrder = 4
Kind = bkCancel
end
object btnTest: TBitBtn
Left = 153
Top = 91

http://www.mindspring.com/~cityzoo/scrnsavr.html (3 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

Width = 89
Height = 34
Caption = 'Test...'
TabOrder = 5
Kind = bkIgnore
end
Once we have the form layout, we need to add some code to make it work. First, we need to be able to load and save
the current configuration. To do this, we should place the Spheres, Size, and Speed values into an initialization file
(*.INI) in the user's Windows directory. Delphi's TIniFile object is just the thing for this.
Switch to the code view for the Setup form, and add the following uses clause to the implementation section of the
configuration form's unit:

uses
IniFiles;
Then, add the following procedure declarations to the private section of the TCfgFrm declaration:

procedure LoadConfig;
procedure SaveConfig;
Now add the following procedure definitions after the uses clause in the implementation section:

const
CfgFile = 'SPHERES.INI';

procedure TCfgFrm.LoadConfig;
var
inifile : TIniFile;
begin
inifile := TIniFile.Create(CfgFile);
try
with inifile do begin
spnSpheres.Value := ReadInteger('Config', 'Spheres', 50);
spnSize.Value := ReadInteger('Config', 'Size', 100);
spnSpeed.Value := ReadInteger('Config', 'Speed', 10);
end;
finally
inifile.Free;
end;
end; {TCfgFrm.LoadConfig}

procedure TCfgFrm.SaveConfig;
var
inifile : TIniFile;
begin
inifile := TIniFile.Create(CfgFile);
try
with inifile do begin
WriteInteger('Config', 'Spheres', spnSpheres.Value);

http://www.mindspring.com/~cityzoo/scrnsavr.html (4 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

WriteInteger('Config', 'Size', spnSize.Value);


WriteInteger('Config', 'Speed', spnSpeed.Value);
end;
finally
inifile.Free;
end;
end; {TCfgFrm.SaveConfig}
All that remains for the configuration form is to respond to a few events to properly load and save the configuration.
First, we need to load the configuration automatically whenever the program starts up. We can use the setup form's
OnCreate event to do this. Double- click the OnCreate field in the events section of the Object Inspector and enter
the following code:

procedure TCfgFrm.FormCreate(Sender: TObject);


begin
LoadConfig;
end; {TCfgFrm.FormCreate}
Next, double-click the OK button. We need to save the current configuration and close the window whenever OK is
pressed, so add the following code:

procedure TCfgFrm.btnOKClick(Sender: TObject);


begin
SaveConfig;
Close;
end; {TCfgFrm.btnOKClick}
In order to simply close the form (without saving) when the Cancel button is pressed, double-click on the Cancel
button and add:

procedure TCfgFrm.btnCancelClick(Sender: TObject);


begin
Close;
end; {TCfgFrm.btnCancelClick}
Finally, to test the screen saver, we will need to show the screen saver form (which we haven't yet created). Go
ahead and double-click on the Test button and add the following code:

procedure TCfgFrm.btnTestClick(Sender: TObject);


begin
ScrnFrm.Show;
end; {TCfgFrm.btnTestClick}
Then add "Scrn" to the uses clause in the implementation section. Scrn refers to the screen saver form unit that we
will create in the next step. In the meantime, save this form unit as "Cfg" by selecting Save File As from the File
menu.

http://www.mindspring.com/~cityzoo/scrnsavr.html (5 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

Screen Saver Form


The screen saver itself will simply be a large, black, captionless form that covers the entire screen, upon which the
graphics are drawn. To create the second form, select New Form from the File menu and indicate a "Blank form" if
prompted by the Browse Gallery.

BorderIcons []
biSystemMenu False
biMinimize False
biMaximize False
BorderStyle bsNone
Color clBlack
FormStyle fsStayOnTop
Name ScrnFrm
Visible False
To this form, add a single component -- a timer from the System category of the Delphi component palette. Set its
properties accordingly:

object tmrTick: TTimer


Enabled = False
OnTimer = tmrTickTimer
Left = 199
Top = 122
end
No other components will be required for this form. However, we will need to add some code to handle drawing the
shaded spheres. Switch to the code window accompanying the ScrnFrm form. In the TScrnFrm private section, add
the following procedure declaration:

procedure DrawSphere(x, y, size : integer; color : TColor);


Now, in the implementation section of the unit, add the code for this procedure:

procedure TScrnFrm.DrawSphere(x, y, size : integer; color : TColor);


var
i, dw : integer;
cx, cy : integer;
xy1, xy2 : integer;
r, g, b : byte;
begin
with Canvas do begin
{Fill in the pen & brush settings.}
Pen.Style := psClear;
Brush.Style := bsSolid;
Brush.Color := color;
{Prepare colors for sphere.}
r := GetRValue(color);
g := GetGValue(color);
b := GetBValue(color);

http://www.mindspring.com/~cityzoo/scrnsavr.html (6 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

{Draw the sphere.}


dw := size div 16;
for i := 0 to 15 do begin
xy1 := (i * dw) div 2;
xy2 := size - xy1;
Brush.Color := RGB(Min(r + (i * 8), 255), Min(g + (i * 8), 255),
Min(b + (i * 8), 255));
Ellipse(x + xy1, y + xy1, x + xy2, y + xy2);
end;
end;
end; {TScrnFrm.DrawSphere}
As you can see from the code, we are given the (x,y) coordinates of the top, left corner of the sphere, as well as its
diameter and base color. Then, to draw the sphere, we step through brushes of increasingly bright color, starting
with the given base color. With each new brush, we draw a smaller filled circle concentric with the previous ones.
You will also notice, however, that the function refers to another function, Min(). This is not a standard Delphi
function, so we must add it to the unit, above the declaration for DrawSphere().

function Min(a, b : integer) : integer;


begin
if b < a then
Result := b
else
Result := a;
end; {Min}
In order to periodically call the DrawSphere() function, we must respond to the OnTimer event of the Timer
component we added to the ScrnFrm. Double-click the Timer component on the form and fill in the automatically
created procedure with the following code:

procedure TScrnFrm.tmrTickTimer(Sender: TObject);


const
sphcount : integer = 0;
var
x, y : integer;
size : integer;
r, g, b : byte;
color : TColor;
begin
if sphcount > CfgFrm.spnSpheres.Value then begin
Refresh;
sphcount := 0;
end;
Inc(sphcount);
x := Random(ClientWidth);
y := Random(ClientHeight);
size := CfgFrm.spnSize.Value + Random(50) - 25;
x := x - size div 2;
y := y - size div 2;
r := Random($80);

http://www.mindspring.com/~cityzoo/scrnsavr.html (7 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

g := Random($80);
b := Random($80);
DrawSphere(x, y, size, RGB(r, g, b));
end; {TScrnFrm.tmrTickTimer}
This procedure keeps track of the number of spheres that have been drawn in sphcount, and refreshes (erases) the
screen when we have reached the maximum number. In the meantime, it calculates the random position, size, and
color for the next sphere to be drawn. (Note: The color range is limited to only the first half of the brightness
spectrum in order to provide greater depth to the shading.)
As you may have noticed, the tmrTickTimer() procedure references the CfgFrm form to retrieve the configuration
options. In order for this reference to be recognized, add the following uses clause to the implementation section of
the unit:

uses
Cfg;
Next, we will need a way to deactivate the screen saver when a key is pressed, the mouse is moved, or the screen
saver form looses focus. One way to do this is to create an handler for the Application.OnMessage event that looks
for the necessary conditions to terminate the screen saver.
First, add the following variable declaration to the implementation section of the unit:

var
crs : TPoint;
This variable will be used to store the original position of the mouse cursor for later comparison. Now, add the
following declaration to the private section of TScrnFrm:

procedure DeactivateScrnSaver(var Msg : TMsg; var Handled : boolean);


Add the corresponding code to the implementation section of the unit:

procedure TScrnFrm.DeactivateScrnSaver(var Msg : TMsg; var Handled : boolean);


var
done : boolean;
begin
if Msg.message = WM_MOUSEMOVE then
done := (Abs(LOWORD(Msg.lParam) - crs.x) > 5) or
(Abs(HIWORD(Msg.lParam) - crs.y) > 5)
else
done := (Msg.message = WM_KEYDOWN) or (Msg.message = WM_ACTIVATE) or
(Msg.message = WM_ACTIVATEAPP) or (Msg.message = WM_NCACTIVATE);
if done then
Close;
end; {TScrnFrm.DeactivateScrnSaver}
When a WM_MOUSEMOVE window message is received, we compare the new coordinates of the mouse to the
original location. If it has moved more than our threshold (5 pixels in any direction), then we close the screen saver.
Otherwise, if a key is pressed or another window or dialog box takes the focus, the screen saver closes.
In order for this procedure to go into effect, however, we need to set the Application.OnMessage property and get

http://www.mindspring.com/~cityzoo/scrnsavr.html (8 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

the original position of the mouse cursor. A good place to do this is in the form's OnShow event handler:

procedure TScrnFrm.FormShow(Sender: TObject);


begin
GetCursorPos(crs);
tmrTick.Interval := 1000 - CfgFrm.spnSpeed.Value * 90;
tmrTick.Enabled := true;
Application.OnMessage := DeactivateScrnSaver;
ShowCursor(false);
end; {TScrnFrm.FormShow}
Here we also specify the timer's interval and activate it, as well as hiding the mouse cursor. Most of these things
should be undone, however, in the form's OnHide event handler:

procedure TScrnFrm.FormHide(Sender: TObject);


begin
Application.OnMessage := nil;
tmrTick.Enabled := false;
ShowCursor(true);
end; {TScrnFrm.FormHide}
Finally, we need to make sure that the screen saver form fills the entire screen when it is shown. To do this add the
following code to the form's OnActivate event handler:

procedure TScrnFrm.FormActivate(Sender: TObject);


begin
WindowState := wsMaximized;
end; {TScrnFrm.FormActivate}
Take this opportunity to save the ScrnFrm form unit as "SCRN.PAS" by selecting Save File from the File menu.

The Screen Saver Description


You can define the text that will appear in the Control Panel Desktop list of screen savers by adding a {$D text}
directive to the project source file. The $D directive inserts the given text into the module description entry of the
executable file. For the Control Panel to recognize the text you must start with the term "SCRNSAVE", followed by
your description.
Select Project Source from the Delphi View menu so you can edit the source file. Beneath the directive "{$R
*.RES}", add the following line:

{$D SCRNSAVE Spheres Screen Saver}


The text "Spheres Screen Saver" will appear in the Control Panel list of available screen savers when we complete
the project.

Active Versus Configuration Mode


Windows launches the screen saver program under two possible conditions: 1) when the screen saver is activated,
and 2) when the screen saver is to be configured. In both cases, Windows runs the same program. It distinguishes

http://www.mindspring.com/~cityzoo/scrnsavr.html (9 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

between the two modes by adding a command line parameter -- "/s" for active mode and "/c" for configuration
mode. For our screen saver to function properly with the Control Panel, it must check the command line for these
switches.

Active Mode
When the screen saver enters active mode (/s), we need to create and show the screen saver form. We also need
create the configuration form, since it contains all of the configuration options. When the screen saver form closes,
the entire program should then terminate. This fits the definition of a Delphi Main Form -- a form that starts when
the program starts and signals the end of the application when the form closes.

Configuration Mode
When the screen saver enters configuration mode (/c), we need to create and show the configuration form. We
should also create the screen saver form, in case the user wishes to test configuration options. However, when the
configuration form closes, the entire program should then terminate. In this case, the configuration form fits the
definition of a Main Form.

Defining the Main Form


Ideally, we would like to identify ScrnFrm as the Main Form when a /s appears on the command line, and CfgFrm
as the Main Form in all other cases. To do this requires knowledge of an undocumented feature of the TApplication
VCL object: The Main Form is simply the first form created with a call to Application.CreateForm(). Thus, to define
different Main Forms according to our run-time conditions, modify the project source as follows:

begin
if (ParamCount > 0) and (UpperCase(ParamStr(1)) = '/S') then begin
{ScrnFrm needs to be the Main Form.}
Application.CreateForm(TScrnFrm, ScrnFrm);
Application.CreateForm(TCfgFrm, CfgFrm);
end else begin
{CfgFrm needs to be the Main Form.}
Application.CreateForm(TCfgFrm, CfgFrm);
Application.CreateForm(TScrnFrm, ScrnFrm);
end;
Application.Run;
end.
Just by changing the order of creation, we have automatically set the Main Form for that instance. In addition, the
Main Form will automatically be shown, despite the fact that we have set the Visible properties to False for both
forms. As a result, we achieve the desired effect with only minimal code.
(Note: for the if statement to function as shown above, the "Complete boolean eval" option should be unchecked in
the Options | Project | Compiler settings. Otherwise, an error will occur if the program is invoked with no command
line parameters.)
In order to use the UpperCase() Delphi function, SysUtils must be included in the project file's uses clause to give
something like:

uses

http://www.mindspring.com/~cityzoo/scrnsavr.html (10 of 11) [1/28/2005 3:46:05 PM]


How to Make a Windows Screen Saver in Delphi

Forms, SysUtils,
Scrn in 'SCRN.PAS' {ScrnFrm},
Cfg in 'CFG.PAS' {CfgFrm};

Blocking Multiple Instances


One difficulty with Windows screen savers is that they must prevent multiple instances from being run. Otherwise,
Windows will continue to launch a screen saver as the given time period ellapses, even when an instance is already
active.
To block multiple instances of our screen saver, modify the project source file to add the outer if statement shown
below:

begin
{Only one instance is allowed at a time.}
if hPrevInst = 0 then begin
if (ParamCount > 0) and (UpperCase(ParamStr(1)) = '/S') then begin
...
end;
Application.Run;
end;
end;
The hPrevInst variable is a global variable defined by Delphi to point to previous instances of the current program. It
will be zero if there are no previous instances still running.
Now save the project file as "SPHERES.DPR" and compile the program. With that, you should be able to run the
screen saver on its own. Without any command line parameters, the program should default to configuration mode.
By giving "/s" as the first command line parameter, you can also test the active mode. (See Run | Parameters...)

Installing the Screen Saver


Once you've tested and debugged your screen saver, you are ready to install it. To do so, simply copy the executable
file (SPHERES.EXE) to the Windows directory, changing its filename extension to .SCR in the process
(SPHERES.SCR). Then, launch the Control Panel, double-click on Desktop, and select Screen Saver | Name. You
should see "Spheres Screen Saver" in the list of possible screen savers. Select it and set it up.
® Delphi is a registered trademark of Borland International.

keeper@mindspring.com

Copyright © 1995 Mark R. Johnson. This is a CITY ZOO production.


Last revised September 4, 1995.

http://www.mindspring.com/~cityzoo/scrnsavr.html (11 of 11) [1/28/2005 3:46:05 PM]


To contact Tom Boyd / Sheepdog Software (TM)

HOME

Contacting TK Boyd / Sheepdog Software (tm)


I'm usually glad to hear from readers. My eddress is:

I'm afraid that's a graphic and that you'll need to copy it by hand.... I'm removing machine readable copies of my eddress
from my webpages in an attempt to reduce the spam I get.

Also, at 15 Sept 04, Compuserve seems to be losing emails sent to me. Part of this may be due to efforts at their end to
reduce spam, but what is lost is erratic, and includes emails from sensible people with AOL accounts (Compuserve and
AOL are both part of the same company). If I get your email, I will usually send at least a "Got It" within 36 hours. Don't
hesitate to "pester" me by re-sending things.

I'm most pleased to hear from people who send plain text emails, without attachments. In fact, I usually delete
attachments unread, and ignore messages sent in html form. There's a fax number below, if you want to send me some
diagram.

I'm most likely to look at something with a subject that appears to have been composed by a human, and isn't a classic
spam subject, e.g. not "TK, you really want to read this...". Making intelligent reference to something in the page you are
responding to gives you an edge, as does something referring to a recent bit of world news, e.g. just after an election
"Only a human would know that Mr.Xxx won" would be an attention getting subject. "Hi" or "Help" or "Message from
internet" rarely get read.

If you use Outlook Express: First: My sympathies. Try Pegasus or Eudora! Second: If you put me in your address book,
please tick the "plain text only" box which (in some versions of OE) appears at the lower left of my page in the address
book.

I also usually discard unread things with odd characters in the subject line, e.g.
"?Big5?B?qETCvrvdqEQyMLhVpEikfrj...". Beware: You may be sending such emails without realizing it. The subject
might look fine on your machine, but appear as shown on mine. I think it arises from a legitimate mechanism to get
around the various character sets needed around the world, but my email client can't handle the protocol.

I also usually discard unread things with return addresses that look like spam engines.

Why don't I use a spam filter? a) I get (falsely!) filtered myself too often, and don't want to miss messages from other
people, b) I believe the spammers will get past what the filters devise, c) I download just my message headers and delete
the stuff that doesn't look good before I download the rest. I think the anti-spam software would require me to download
the messages before discarding them.

If you want to send one email to several people, PLEASE, PLEASE, PLEASE do not use "cc:", but, rather, use "bcc:" It
works like "cc:", except it often hides the list of who else has seen the email from each recipient. A small town
professional, let's call him a tax advisor, once sent "a friend" a "I want more work from you" email after he'd stopped
using the advisor because his work was unsatisfactory. He used "cc:". And the email came with a virus. The advisor

http://sheepdogguides.com/ctact.htm (1 of 2) [1/28/2005 3:46:17 PM]


To contact Tom Boyd / Sheepdog Software (TM)

didn't even thank my friend for being alerted to the problem. My friend felt a strong temptation to send an email to all the
other people the advisor had pestered. If he'd used "bcc:", it would have been no more work for him, and he would not
have supplied my friend with the eddresses of all those other people. (For more information, download Pegasus and read
the material on "bcc" in the help file.)

Want a link to your page from my page? I'm more likely to add one for you if when you ask, you say you've already
done a link to my site from yours.

I can be reached the old fashioned way as follows:

TK Boyd
PO Box 367
Essex, CT
06426 USA
(Do not put me on mailing lists, please!)

I can be reached via fax on this number in the USA: 1-413-826-7829, or on 0871-661-2767 in the UK.

Those, by the way, are free services from www.efax.com and www.pumaone.com, respectively. Signing up for it was
simple and the questions reasonable. I once received a very modest number of advertisements, and even they seem to
have stopped. You can "send a fax" to me, as if I had a "real" fax machine on a dedicated phone line, but I don't... I
receive what you sent as an email! (You can send the fax at any time of day or night, by the way... you won't wake the
household.) I've had it for a few years now, entirely happy with it. Recommended.

Worried I'm not who I say I am? You should be... the net makes life too easy for the dishonest. Do you know about the
Way Back Machine at www.archive.org? Besides being cool, it will show you that I've been around since at least
December 1998. Just look up...

http://ourworld.compuserve.com/homepages/TK_Boyd/homepage.htm

... and you'll find my old eddress (100665...) there, at the bottom. Or, you can check TKBoydChi's profile at eBay.. that's
me, too. Go to Google's newsgroup archives... you'll find many posts from me, especially years ago... and you won't find
the complaints that arise about scam artists. If I can reassure you some other way, let me know?

I also own the trademark "Sheepdog Software".

If you use an MS-DOS or Windows PC, please visit my freeware and shareware page, download something, and
circulate it for me?

Click here to visit editor's freeware, shareware page.

Link to editor's (Arunet) homepage

See the graphic near the start of this page for my eddress (email address). (By the way... I lay claim to having invented
that word. Again, the Way Back machine will show you how long I've been using it.)

http://sheepdogguides.com/ctact.htm (2 of 2) [1/28/2005 3:46:17 PM]


Delphi tutorial: Customising a standard control.

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for


programmers

Delphi tutorial: Customising a standard control


Click here if you want to know more about the source and format of these pages.
This tutorial follows on from the Level Three tutorial about making arrays of controls. (Originally (and
probably still!) called DT3a).
There is a search button at the bottom of the page.

It will show you how you can customise a standard Delphi component to give it the features you wish
Borland had incorporated in the first place.

This is an early draft... apologies if there are mistakes. Please send me an email if you encounter any... or to
say that you worked through successfully?
Tom Boyd

As you work through it, you might feel that you could accomplish what is here by more direct means. There
is a penalty to pay, too, in that the component we are going to develop cannot be placed on the design-time
form that is a major aid to the 'visual' aspect of Delphi programming. (I suspect that there are ways you
COULD add your component to the Components Palette... but they are not covered here.) If you find those
thoughts a serious problem, consider this: How else would you produce AN ARRAY of edit boxes, even
without customisations?

All the completed program will do is provide an inches to centimeters converter. It won't even work both
ways! However, by keeping the program simple, the essentials of customising a component should be kept
clear.

I am endebted to Mr. Alan Lloyd of comp.lang.pascal.delphi.misc newsgroup for showing me how to


customising a component. There is also a welth of information in the Delphi help file (of course) if you can
find it (not always easy)... look under components, overviewof component creation.

Start a new project. I called my Demo, with my usual suffixes to distinguish forms, units, etc. In particular,
to make the following work, name the form DemoF1.

http://sheepdogguides.com/dt4a.htm (1 of 7) [1/28/2005 3:46:36 PM]


Delphi tutorial: Customising a standard control.

Add StdCtrls to the Uses section. The TEdit control is defined in StdCtrls, so the compiler needs StdCtrls to
create our customised TEdit.

Put a label on the form. Autosize=false. Top=50,Left=50,height=50,width=50.

Select the label. Do ctrl-c. Do ctrl-v three times. You should now have 4 labels.

Leaving the first where it was, drag the others so that you have two rows of two, neatly spaced. Now delete
the first... our customised edit box will go there.

Make the captions of the upper and lower right hand labels 'Inches' and 'Cms'.

Make the name of the lower left label lOutput.

Just to get everything else working, put an ordinary edit box where the first label was.

Save what you've got so far. Run it and debug if necessary.. it shouldn't do anything yet, but it should run!

Program the edit box's OnChange event as follows:

As a first step, make it just

lOutput.caption:=FloatToStrF(4.5,ffFixed,4,2);

With that, any change in the edit box should put 4.50 in lOutput.

Next make edit box's text 0 and make the OnChange event

procedure TDemoF1.Edit1Change(Sender: TObject);


var rInches:real;
begin
try

http://sheepdogguides.com/dt4a.htm (2 of 7) [1/28/2005 3:46:36 PM]


Delphi tutorial: Customising a standard control.

rInches:=StrToFloat(Edit1.text);
except
on EConvertError do rInches:=0
end;
lOutput.caption:=FloatToStrF(rInches*100/39.37,ffFixed,4,2);
end;

Delphi will report the EConvertError if you make the contents of the edit box invalid for conversion to a
number, but just click OK and then Run again.

Also, the insertion point indicator in the edit box disappears... but you can edit the edit box contents
normally. (If someone could tell me how to avoid losing the IPI, I'd be grateful.)

When you've got this working, save. Next we will replace the standard edit box control with one of our own
devising.

In the unit's Type section, add:

TBoydEdit = class(TEdit)
public
constructor Create(AOwner:TComponent;iTop,iLeft,iSize:integer);
destructor Destroy;
end;(*Declare type TBoydEdit*)

As you can guess, the name TBoydEdit is up to you, though convention suggests starting it with a T. The
names AOwner,iTop and iLeft are also up to you. (I would have used something like compOwner, but
Borland used AOwner) The first parameter of the Create method will always (?... comment form any expert
who knows otherwise will be welcomed!) be there, and be of type TComponent. The other parameters are up
to you... include whatever is needed for your customisation requirements. In this example, we are going to be
able to say where the edit box will be and how big. It will always be square.... but you should be able to
re-define it for some other rule, once you've studied this tutorial.

(You can't run the program at this stage)

Add the following to the implementation section of the program:

constructor TBoydEdit.create(AOwner:TComponent;iTop,iLeft,iSize:integer);

http://sheepdogguides.com/dt4a.htm (3 of 7) [1/28/2005 3:46:36 PM]


Delphi tutorial: Customising a standard control.

begin
end;

destructor TBoydEdit.destroy;
begin
end;

Your program should run again, though it won't yet do anything it didn't do before.

revise the constructor (in the implementation section) as follows:

constructor TBoydEdit.create(AOwner:TComponent;iTop,iLeft,iSize:integer);
begin
inherited create(AOwner);
parent:=TWinControl(AOwner);
with Self do begin
top:=iTop;
left:=iLeft;
width:=iSize;
height:=iSize;
visible:=true;
enabled:=true;
color:=clGreen;
end;(*...with self*)
end;

Again, your program should run, though it still won't yet do anything it didn't do before.

What properties can you set? What names do you use? Just look in the Delphi help file. If you are making a
customised TEdit control, then the TEdit properties are available to you... and you must use the names
defined by the TEdit. E.g., in the example above, top, left, width, height, visible, enabled, color.

Drag the edit box you gave your form to some out of the way place.

In the Var section, add

BoydEdit1:TBoydEdit;

http://sheepdogguides.com/dt4a.htm (4 of 7) [1/28/2005 3:46:36 PM]


Delphi tutorial: Customising a standard control.

Add a OnCreate event to your form, and program it as follows:


BoydEdit1:=TBoydEdit.create(DemoF1,50,50,50);

If you run the program now, you should see a green edit box where the old one used to be. Entering data
won't do anything yet. (Why green? Just to show it's not an ordinary edit box!)

Now we come to a further problem connected with the fact that the TBoydEdit version of the edit box is not
registered and so it cannot be 'seen' by the object inspector. How do we get the program to process events
arising from BoydEdit1? In particular, we need to write an event handler to react to changes in
BoydEdit1.text. With the standard edit box, we just turned to the object inspector and clicked the OnChange
event, and a skelton for a handler appeared.

First: What events can you attach code to? The answer is similar to the answer to the question above about
what properties are available. If you are customising TEdit, then use the object inspector to look at TEdit's
events. You'll see OnChange, OnClick, OnDblClick, etc.

The first step is to choose a name for the procedure that will handle the event from your customised control.
For this example, I'm using the name BoydOnChange.

Now, in the With Self block, add a line to the control's create constructor saying

OnChange:=BoydOnChange;

It will look as if you are merely declaring another property default. In a loose sense you are... you are
declaring what procedure to execute when OnChange events arise from the control. Note that you have no
choice over the name 'OnChange', though of course you could specify handlers for other events.

The next thing you must do is put

private
procedure BoydOnChange(Sender:TObject);

in the declaration of the TBoydEdit type near the top of the program. It can go just before the word 'public'.
(Sorry... at this point my understanding of public/private/published and implementation is too hazy to

http://sheepdogguides.com/dt4a.htm (5 of 7) [1/28/2005 3:46:36 PM]


Delphi tutorial: Customising a standard control.

explain or defend details... but what I've aasid to do does work!)


And lastly, copy the old TDemoF1.Edit1Change, and make changes in the (**)'d lines to make it

procedure TBoydEdit.BoydOnChange(Sender: TObject); (**)


var rInches:real;
begin
try
rInches:=StrToFloat(BoydEdit1.text); (**)
except
on EConvertError do rInches:=0
end;
DemoF1.lOutput.caption:=FloatToStrF(rInches*100/39.37,ffFixed,4,2); (**)
end;

That should do it! Of course, the ordinary edit box put on the form early in the tutorial could now be deleted.
If you decide to do this, you'll want to turn things like

procedure TDemof1.Edit1Change(Sender: TObject);...

will have to be taken out as well.

Tom Boyd

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

http://sheepdogguides.com/dt4a.htm (6 of 7) [1/28/2005 3:46:36 PM]


Delphi tutorial: Customising a standard control.

Notes to self...
>>> Write up as lower level tutorial Try..except..end

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However..
this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt4a.htm (7 of 7) [1/28/2005 3:46:36 PM]


Delphi tutorial, A program to massage a pre-existing file. (Level 4).

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for


programmers

Delphi tutorial: A program to massage a


pre-existing file. (Level 4)
This is still in a draft form.... it is probably mostly right, but I make no promises just
yet!!!

This has good information, and there's a search button at the bottom
of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Dt4b: A Little File Massaging program.


This is a level 4 tutorial not because it is very complicated, but because I want to go quickly, skim many
details.

The tutorial describes the start of creating a program I wrote for converting Notepad files into crude
HTML pages, the pages used in these tutorials!

The program....

Asks the user what file is to be massaged. (Called the source program from here on, and a file named
Source.txt is going to be the example.)

Renames it from, e.g., Source.txt to Source.bak


(If there was already a Source.bak, the user can either delete the old Source.bak, or give a different name
for Source.txt to be renamed.)

Copies Source.Bak to Source.txt, but changes any lower case 'e's to upper case 'E's. This is a simple
thing, useful only as an exercise for the muscles of this program. (In the version I use, the program adds
[br] before each isolated CR/LF, and two [br]s before a double cr/lf.)

So..

Broad outline:

http://sheepdogguides.com/dt4b.htm (1 of 6) [1/28/2005 3:46:40 PM]


Delphi tutorial, A program to massage a pre-existing file. (Level 4).

Open old file


Rename it
Copy from it, inserting [br]s
Close output file
Close input file

Details of Open/ Rename:

Set TestFlag false


Repeat
If TestFlag=true then explain why file unsatisfactory
Get name of source file
Set TestFlag true
Until file named is more than 8 bytes long

Set NameToGiveIt to [previous].bak


Set TestFlag false
Repeat
If FileExists(NameToGiveIt)=true then
....Ask 'Delete the old file called NameToGiveIt'?
....If Yes then begin
.........delete NameToGiveIt
.........Set TestFlag true
.......else (may not delete)
.........Get new NameToGiveIt from user
...else (did not exist)
.....Set TestFlag true
Until TestFlag true
Rename as NameToGiveIt

So... that's the plan for how we do the filename shuffling.

Now... the code!....

Start a project as explained in Tutorial 1. Call it DD06.

Make the form about 300 high, 400 wide.


Put a label called lMsgs in the bottom part of the form; caption:='Welcome to file massager';
wordwrap:=true;

Add a button captioned 'Select and process file'

From the dialogs tab, put an OpenDialog component on DD06's form. Set option ofFileMustExist=true

In the unit's var declaration add...

http://sheepdogguides.com/dt4b.htm (2 of 6) [1/28/2005 3:46:40 PM]


Delphi tutorial, A program to massage a pre-existing file. (Level 4).

dfin,dfout:file of byte;(*DataFiles for INput, OUTput*)


dfinName, dfoutName:string;

Use the object inspector to make DD06f1.Button1Click and fill it as follows...

procedure TDD06f1.Button1Click(Sender: TObject);


var TestFlag,DidNotCancel:boolean;
begin
TestFlag:=true;(*to suppress message on first pass*)
repeat
if TestFlag=false then
showmessage('The file you specified is too short for this program to '+
'process. Name another.');
TestFlag:=false;(*will stay false til good file spec'd*)
opendialog1.filter:= 'Text files (*.TXT)|*.txt|All files (*.*)|*.*|';
DidNotCancel:=opendialog1.execute;
AssignFile(dfin,opendialog1.FileName);
dfinName:=opendialog1.FileName;
reset(dfin);
if Filesize(dfin)>5 then TestFlag:=true;
closefile(dfin);
application.processmessages;
until (not DidNotCancel) or (TestFlag=true);
end;

...and get that much working... it should provide for finding a suitable file, even though it does nothing
with it yet.

Next, we need to save and then strip off any extension the filename may have had, e.g. .txt, so to the
unit's vars add...
sExtn:string

and to the ButtonClick handler's vars add ...


c1:byte

and after ...


until (not DidNotCancel) or (TestFlag=true);

... add ...


If DidNotCancel then begin
sExtn:='';(*in case no extension*)
c1:=pos('.',dfinName);
if c1>0 then begin
sExtn:=copy(dfinName,c1,1+length(dfinName)-c1);
dfinName:=copy(dfinName,1,c1-1);
lTmp.caption:=dfinName;

http://sheepdogguides.com/dt4b.htm (3 of 6) [1/28/2005 3:46:40 PM]


Delphi tutorial, A program to massage a pre-existing file. (Level 4).

(*note that the '.' of, e.g., '.txt' saved in sExtn,


and that dfinName is now extensionless*)
end;
end;(*DidNotCancel*)

Now the selection of a new name for the source can begin. In a simple case, something like Source.txt
simply becomes Source.bak, but we are providing for the case where Source.bak already exists.

To ButtonClick's vars add ...


...add sTmp:string t

and just before the...


end;(*DidNotCancel*)

... add ...


TestFlag:=false;
sTmp:=dfinName+'.bak';
repeat
if FileExists(sTmp) then begin
if MessageDlg('File called '+sTmp+' already exists. Delete it?',
mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin
if DeleteFile(sTmp) then TestFlag:=true
(*no ; here*)
else (*handle failed deletes*);
end(*No. ; here. This ends do a delete*)
else (*not permitted to delete old .bak, so a new name
will have to be provided, which will then be tested.*)
sTmp:= InputBox('Make Change', 'Give a different extension', '.bak');
if copy(sTmp,1,1)<>'.' then sTmp:='.'+sTmp;
if length(sTmp)>4 then sTmp:='.bak';{already known to be invalid}
sTmp:=dfinName+sTmp;
end(* no ; here. File Existed*)
else TestFlag:=true;(*File didn't exist*)
until TestFlag;
RenameFile(dfinName+sExtn,sTmp);
dfinName:=sTmp;
dfoutName:=dfinName+sExtn;
(*dfin/outNames now hold current name of source file and name
of file output to go to, with their extensions*)

That completes the renaming of the source file, probably as Source.bak.

N.B. The frequent changes of what is in dfinName, which reflect the progress of the processing, give
opportunities for confusion.

Now we start on the code for reading through it, writing it out to a new file, making changes along the

http://sheepdogguides.com/dt4b.htm (4 of 6) [1/28/2005 3:46:40 PM]


Delphi tutorial, A program to massage a pre-existing file. (Level 4).

way.

Just before...
end;(*DidNotCancel*)

... add ...


ReadMassageWriteToNew;
lMsgs.caption:='Done!';

... and just after ...


procedure TDD06f1.Button1Click(Sender: TObject);
var TestFlag,DidNotCancel:boolean;

... add ...

procedure ReadMassageWriteToNew;
(*On entry, dfinName and dfoutName should hold the full path+name+exten
specification of the file to be read from, and the file to be written to.
The first should exist and the second shouldn't*)
var wBytesDone:word;
bTmp:byte;
begin
wBytesDone:=0;
assignfile(dfin,dfinName);
lTmp.caption:=dfoutName;
reset(dfin);
assignfile(dfout,dfoutName);
rewrite(dfout);
repeat
inc(wBytesDone);
if wBytesDone mod 32=0 then application.processmessages;
read(dfin,bTmp);
if bTmp=ord('e') then bTmp:=ord('E');
(*Change lowercase es to Es, as a simple test of prgm*)
write(dfout,bTmp);
until eof(dfin);
closefile(dfout);
closefile(dfin);
end;

Obviously, a program to change es to Es is of limited use, but it illustrates a number of points, and will, I
hope, be useful as a starting point for your own needs.

N.B. the application.processmessages which appears within the Repeat..until loop. Without this, your
computer can be trapped within the loop if for some reason (typo?) the 'until' condition is never met.
Even if it IS met, without the processmessages, this program will take over the computer for its exclusive

http://sheepdogguides.com/dt4b.htm (5 of 6) [1/28/2005 3:46:40 PM]


Delphi tutorial, A program to massage a pre-existing file. (Level 4).

use until the loop finishes, which is not a good situation to create.
Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt4b.htm (6 of 6) [1/28/2005 3:46:40 PM]


Delphi tutorial, A Code Solver... and competition. (Level 4).

Delphi tutorial: A Code Solver... and competition.


(Dt4c)
This is a link to another of my pages. (The page you are reading is not typical of my "Tutorial" pages.)
On the linked page you will find a proposal for a programming competition which would be fun for a
class or club. Included in that, however, are two programs, one with its source code in downloadable
form. (That program was written to be functional as it is, but extendable for the ambitious) They derive
from the simple file manipulation program developed in the related tutorial on this site.

The programs are not useful as encryption software, only as a fun exercise for programmers.

Click here to go to the page.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt4c.htm [1/28/2005 3:46:42 PM]


Re-creating parts of Windows Explorer.

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for


programmers

Delphi tutorial: Re-creating parts of Windows


Explorer. Multiple windows. (Level 4)
This has good information, and there's a search button at the bottom
of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Dt4d: A start towards a Windows Explorer-like program


The ideas in this are not especially arcane. Some of the matters raised are relatively central to Delphi
programming. Even so, I've put it in Level 4. We are going to see some inter-action between objects,
which might be a little alarming for people who are just getting started.

This tutorial was written using Delphi 2. SOme of the components used may not be available to Delphi 1
programmers. Some unusual good news for you: The source code for this will be posted in a zip file.

It is in two parts. The first shows you how to build Windows Explorer-like access to your backing store,
and how to pick a single file from it. Part Two shows a way display the file's contents. It also shows the
use of multiple windows.

Part One: Navigating Your Backing Store


I use the classic Compuserve email software. (Too) many people send their emails twice, once as plain
text, and a second time in an HTML version. My primitive email browser doesn't cope well with this, and
I don't often open attachments. Thus I end up with dozens of mystery files. I drag them into Notepad, see
if I see anything important, and then delete 99% of them. This is tedious! I wanted a better way of
weeding my disc. What follows is not a complete solution to that problem, but maybe if you know where
I was going, it will help you follow the tutorial.

The program's main form is similar to Windows Explorer, but not as good. It lets you see what is on a
floppy or hard disc. You can then select files an open them up to see their contents. (In the tutorial, the
examination of the contents is not very sophisticated, but the basic idea is covered.) After you've looked
at a file, you can add it to a list of files to be deleted later, or simply go on to check another file. When

http://sheepdogguides.com/dt4d.htm (1 of 6) [1/28/2005 3:46:46 PM]


Re-creating parts of Windows Explorer.

you're done for the day, you can delete the files whose names you've been accumulating.

Start a new application in the usual way. Name the form DD13f1 (Delphi Demo). From the System tab of
the component pallette, add to your form one each of the following:
DirectoryListBox FileListBox

(You can leave them with the names assigned by Delphi). Save (in it's own folder) what you have so far.
Call the current unit DD13u1, and the project DD13.

Create an OnDirectoryListBox1Change event handler consisting simply of:


FileListBox1.directory:=DirectoryListBox1.directory;

.... and try running the embryonic application. If you click in the DirectoryListBox, you should be able to
change which directory you are in, and when you do, the list of files in the FileListBox should change.
(Don't worry if folders (directories) are not showing in the FileListBox). This is pretty cool. If you don't
believe me, try programming the functionality we have so far without using either of the components I've
specified. The more I work with Delphi, the more I find that it is really easy (that's to good news) IF
(that's the bad news) you can find (amongst the hundreds... thousands?... of available bits) the thing you
need. I'm also learning not to fight Redmond. Don't try to do things YOUR way. Try to figure out how
Bill wants it done, and then find the tools to do it that way.... and when you've managed those two hard
things, you'll find you've reached the place where things are easy!!

Now we're going to more or less repeat the above. First put a formatted floppy in your A: drive. Now,
also from the System tab, add a DriveComboBox. To make it work, give it an
OnDriveComboBox1Change handler consisting of...
DirectoryListBox1.drive:=DriveComboBox1.drive; FileListBox1.drive:=DriveComboBox1.drive;

The above works fine, and is not "too" clever. If you like being clever, there is a property of the
DirectoryListBox you may want to use: FileList. If you set that to FileListBox1, then you can leave out
the FileListBox1.drive... line in the OnDriveComboBox1Change code above. No doubt there are other
such tricks available if you sek them out.

An aside: The program, as developed so far, doesn't cope well if you click on a drive which doesn't have
a disc in it. I'm afraid I haven't sorted out what you'd need to add to a commercial application.

Also from the System tab, add a FilterComboBox1, and, surprise, surprise an event handler:
FileListBox1.mask:=FilterComboBox1.mask;

The Filter property of the FilterComboBox determines what filters are available to your user.
Doubleclick on the cell beside "Filter" in the Object Inspector to access an editor for the Filter property.
As an exercise: Try to add to the list an entry with name: "Text files (*.txt)", filter: "*.txt"

So far so good? This would be a good place to save the project, by the way.

"Yes, but it doesn't DO anything", I hear you cry! ("Yes, yes, but you don't go"... who said that?)

http://sheepdogguides.com/dt4d.htm (2 of 6) [1/28/2005 3:46:46 PM]


Re-creating parts of Windows Explorer.

Add a label to the form. Then add an OnFileListBox1Click event handler


label1.caption:=FileListBox1.filename;

Now when you click on, or use the cursor keys to move between, file names, the name of the file appears
in the label.

You do what you like with the file! I've given you access to your backing store, and showed you how to
pick a file from it. The rest of this tutorial addresses just one of many things you might do with what you
have so far.

Part Two: Multiple Windows, Reading Files

This application doesn't NEED multiple Windows, but I wanted to have them. We're going to add one
window for the display of files, and another to hold a list of files which we have decided to delete in a
minute. The "in a minute" approach allows the user to be put through an "Are you sure?" check, but only
one, not one for each file to be deleted.

So: create two new windows for the application by....

....using File|New Form. Name the new form FileViewer. Save the project, naming the new unit
DD13FVu

Repeat the process, naming the third form ToDelete. Adjust sizes and positions to taste. Resave the
project, naming the third unit DD13TDu.

As we now have three forms (windows), and each has their own code (unit), the screen can get a bit
cluttered! The code is in a nice tabbed window. If you can get to the code for one, you can switch to
another just by clicking on the relevant tab. If you are looking at the code for a form you want to access,
just press F12. If you are looking at a form and need its code: F12 will work for that, too.

Put a label across the top of the FileView window. "Label1" will do for a name. (In general, using
meaningful names is wise, but where you know there are going to be few of any particular type of
component, you can be lazy.)

Go back to the already existing (DD13f1) OnFileListBox1Click event handler. Add


FileViewer.show; FileViewer.label1.caption:=FileListBox1.filename;

You also need to add DD13FVu to the Uses clause near the top of DD13u1.

It is inefficient to do a FileViewer.show every time you change the file selected, but I couldn't find a
better place to put it!

To FileViewer add a button. Call it buExamine. Also add a large memo. Add the following as

http://sheepdogguides.com/dt4d.htm (3 of 6) [1/28/2005 3:46:46 PM]


Re-creating parts of Windows Explorer.

buExamine's OnClick handler:

procedure TFileViewer.buExamineClick(Sender: TObject);


var dfFile:file of byte;
c1,c2:integer;
bTmp:byte;
sTmp:string;
begin
assignfile(dfFile,Label1.caption);
reset(dfFile);
memo1.clear;
for c1:=0 to 15 do begin(*c1*)
sTmp:='';
for c2:=0 to 60 do begin
if not(eof(dfFile)) then begin
read(dfFile,bTmp);
if (bTmp<>31) and (bTmp<127) then
sTmp:=sTmp+chr(bTmp);
end;
end;
memo1.lines.add(sTmp);
end;(*c1*)
closefile(dfFile);
end;
That should "work", but adding FileViewer.memo1.clear; to the OnFileListBox1Click handler in
DD13f1 is a good idea. Don't, by the way, attempt to use this program to view the contents of DD13.exe
while it is running. It will raise an error.

The file viewer is nothing special!! It is just something basic you can refine to meet your needs!

Add another button to DD13FileViewer. Call it buAddToDeleteList. In minute, we'll give it an OnClick
handler, but first add a memo to ToDelete. Make it quite wide. Set its Wrd Wrap property to false.
(Explained later.) Go to the new memo's Lines peoperty via the Object Inspector. Double click on the
cell beside "Lines" to bring up the String List Editor. Remove everything from the memo... be sure to
achieve "0 lines" in the upper left of the window. Also, add ToDelete.show to
DD13f1.FileListBox1Click. It can go just before the FileViewer.show; which is there already. Add
DD13TDu to DD13f1's Uses clause.

An aside. (You can skip this if you already make a lot of use of CtrlC/ Ctrl-V.) Use Copy/ Paste a lot. It
avoids typos, takes the pain out of long names, etc. To add DeleteList.show to
DD13f1.FileListBox1Click, all you need to do is...
Put your cursor just in front of FileViewer.show
Press and keep down the shift key
Press the down arrow key once
(The effect of the previous two lines can also be accomplished by a drag of the mouse.) Release the shift

http://sheepdogguides.com/dt4d.htm (4 of 6) [1/28/2005 3:46:46 PM]


Re-creating parts of Windows Explorer.

key
Do Ctrl-C, Ctrl-V, Ctrl-V
Select the first FileViewer
Type DeleteTo

Odd at first, but eventually your fingers will fly! (End of aside)

Add DD13TDu to FileViewer's Uses clause. Now you can build FileViewer.buAddToDeleteListClick,
which is simply...
ToDelete.memo1.lines.add(Label1.caption);

That takes care of almost everything! All that is left is a way to delete whatever files have been listed on
ToDelete.

Put a buDeleteThese button on ToDelete. The following is suitable for the OnClick:

begin
if MessageDlg('Last chance! Abort delete?',
mtInformation, [mbNo, mbYes], 0) = mrNo
(*Reversing mbNo/Yes does not resquence them
in message box*)
then begin (*Delete the files*)
while memo1.lines.count>0 do begin
deletefile(memo1.lines[0]);
memo1.lines.delete(0);
end;(*while..*)
end; (*Delete the files*)
end;

BE CAREFUL!!!! You now have a "live" file delete


capability. I used Notepad to create a bunch of files
I could safely examine and/or delete.

That should do it!

One little chuckle for you. The final part of this, the buDeleteTheseClick handler, was simple copied
from a working elaboration of the program in this tutorial. I was late for getting away to something, but
just wanted to get the job DONE! Pasted the code in, ran the program, it "worked"... but the files weren't
deleted! No error messages. The memo was cleared properly. So why no file deletes? Eventually, I
noticed that my memo was narrow and I had not set WordWrap to false. In the original, the memo was
wide. Thus, before I fixed things, the program was trying to delete things like...

http://sheepdogguides.com/dt4d.htm (5 of 6) [1/28/2005 3:46:46 PM]


Re-creating parts of Windows Explorer.

C:\Program Fil
es\Borland\aTmpFi
le.txt

... which the memo had split into three lines, and, not surprisingly, attempting Deletefile('C:\Program
Fil') resulted in no deletion!

Oh, the joys of programming....

There is a crudeness in this: After you've deleted the files, they are still listed in the FileListBox. I'm sure
there's some way to overcome that, but I leave that to you.... :-)

Anyway... I hope that was useful, and that you won't hesitate to bring errors to my attention.

You can download a zip file with the project and all relevant files by clicking here

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt4d.htm (6 of 6) [1/28/2005 3:46:46 PM]


Delphi tutorial: Color Graphics. (Level 4).

HOME &GT &GT TUTORIALS TABLE OF CONTENTS - - - / - - / - - / - - / - - - Other material for


programmers

Delphi tutorial: Color Graphics. Dynamic Resizing.


(Level 4)
This is a draft... it is probably right, but I make no promises!

There's a search button at the bottom of the page.


Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Dt4e: Color Graphics (and a bit about dynamic sizing)

This tutorial explores drawing an array of colored rectangles on the screen. The primary issue is how to get
the colors you want. Along the way, some attention will be given to the problems inherent in Windows
programming which arise from the fact that you don't know what screen resolution your user has in effect,
and that users like to be able to resize windows. The program is written for (256 and higher) color displays.

We will not be using the Delphi grid objects, althought they might well be appropriate.

The application will be split into two parts: a fairly trivial "main" program to "drive" the second part, a unit
which can be used with other programs. The subordinate unit will contol its own window, which will have be
a eight rows of eight rectangles. The use of subordinate units like this is explained in more detail in other
tutorials. Although this tutorial will be self contained, if you want more explanation of the multiple unit
aspect, it is available elsewhere.

The main unit will have a form with buttons for selecting various color schemes. It will have an array
(baRectColo) of 64 bytes, one for each rectangle in the display. It will be responsible for designating the
mapping between numbers and colors. The mapping will be held in a 256 longint array called liaColoMap.
That is to say if you want rectangle 0,0 to be bright red when baRectColo has 25 in it, then you have to put
the code for "bright red" in liaColoMap[25].

The subordinate unit will be called DD14sau ("Stand Alone Unit")

The main unit will...


Establish initial values for liaColoMap
Establish initial values for baRectColo

http://sheepdogguides.com/dt4e.htm (1 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

Call dd14.setupPalette... this will prepare the way for...


Call dd14.drawRects... which draws rectangles of the specified colors.

After that, you can "play" with what has been created, the "work" is done!

Perhaps it is already clear, but just in case....

TWO things determine what you will see on the screen in the first rectangle...

The value in baRectColo[0,0]. If it is 25 then the value in liaColoMap[25] is the other determinant.
Typically, the user will, once and for all, prepare a palette of all the colors potentially wanted by filling
liaColoMap with suitable values and calling dd14sau.setupPalette. He/she will then fill baRectColo with the
colors wanted in the rectangles at the moment, and call d14sau.drawRects. Changing the display thereafter
will usually be a simple question of changing values in baRectColo and calling again dd14sau.DrawRects.

To start the the program's delevopment, we are going to build something that draws just a square of one
color. The arrays are going to be part of the program from the beginning, but we're going to use just ba[0,0]
and liaColoMap[0].

Set up a folder called dd14.


Start a project, name the form dd14f1, save the unit as dd14u1 and the project as dd14

Click on File|New Form, select a blank form. Name it dd14sauf. Resave the project. You should get the
"Save As" dialog box again, asking for a name for "unit1". This isn't the unit1 you saved as dd14u1 a
moment ago; it is the code for the form you added and named dd14sauf, so name the unit dd14sau.

Add a label to dd14sauf called laTmp. Add dd14sauf to the uses clause of the main form (dd14f1). Add a
button to the main form. Name it buDoIt, caption "Do It". Give it an OnClick handler that says...

dd14sauf.show;
if dd14sauf.laTmp.caption<>'Mary' then dd14sauf.laTmp.caption:='Mary' (*no ; here*)
. else dd14sauf.laTmp.caption:='Fred';

Once you position the windows suitably, you should be able to click on buDoIT and see the laTmp change
from Fred to Mary to Fred....

So far so good. (This might be a good time to re-save the project.)

In dd14sau, revise the object declaration as follows. (You have to add the two "... of byte" lines. We're
putting the declarations in the public section so that we can access the arrays from dd14u1. I believe it is
correct to call the arrays "fields" of the object. They behave like what in the old days I called a variable.
"Proper" OOP practice, I believe, entails avoiding direct changes to what is stored in the fields, but that's
something for another day!

type
Tdd14sauf = class(TForm)
laTmp: TLabel;

http://sheepdogguides.com/dt4e.htm (2 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

private
{ Private declarations }
public
{ Public declarations }
liaColoMap:array [0..255] of longint;
baRectColo: array[0..7,0..7] of byte;
end;

Once you've done this, to the OnClick handler in dd14u1, you should be able to add..

dd14sauf.liaColoMap[0]:=5;
dd14sauf.baRectColo[0,0]:=5;

... and compile without errors. (The new stuff doesn't do anything you can see yet.)

From the "Additional" tab of the component palette, add a TShape object to dd14sauf. Name it shTmp.

In dd14u1's buDoItClick, replace the

if dd14sauf.laTmp.caption<>'Mary'...

with...

if dd14sauf.shTmp.brush.color<>0 then dd14sauf.shTmp.brush.color:=0 (*no ; here*)


. else dd14sauf.shTmp.brush.color:=random(255*255)+255*255;

Remove laTmp from the dd14sauf. Save the project and run it.

You will now PROBABLY see the color change when you click DoIt.

Here begins a little digression. Windows is wonderful. I write this out ten time before every Windows
programming session, just to try to eep myself convinced. The trouble is, it is SO wonderful that sometimes
it won't do the same thing twice. (And no, I'm not talking about anything connected with my use of the
Random function in the code above.) Just before I descend into the Sough of Despond, let me assure you that
what follows "should" work... most of the time... but: If you're getting weird results, don't immediately
conclude that you are doing something wrong.

(Continuing digression) Windows tries to be all things to all people and pcbs. You "should" be able to plug
any video card into your computer and see what you saw before. To achieve this, color management has
evolved. When I started, you had two colours: the paper in your KSR-33 teleprinter, and the ink in the
ribbon. Then things got better: store 4 in the right place, and things were red. You could choose between 16
colors! Red was always 4, and it was always the same red.

(Continuing digression) Under modern color management, first, the system sends some codes to the graphics
card. These say "From now on, when I send you (say) 56, use the bluey-greeny yellow I just described" The
describing can be a little complex, and the card is CAPABLE of far more colors, in general, that it is
CON-CURRENTLY capable at any particular instant. Hence the "When I say 56..." system. Inside

http://sheepdogguides.com/dt4e.htm (3 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

Windows, there are sophisticated permutations of this basic idea.

(Continuing digression) All this is well and good... when it works. Of course, when it doesn't, the Windows
people say that the card isn't responding as it should, and the makers of the card will tell you that something
must be wrong with the messages the card is being sent.

(Ending digression) So! You have been warned and, I hope, (somewhat) enlightened. By the way- the system
we are building in software works in a manner analogous to what was just described. The "color 56 is a
yellow for the moment" data is held in what is called a palette. Several are involved, so I'll try to avoid using
the term for anything in our program, but be sure when consulting other refernce material that you keep clear
in your mind WHICH palette you are reading about. In a moment, we are going to look at using numbers to
specify colors. The Delphi Help entry for TColor talks about part of the number as follows... I'm going to
ignore this stuff and hope for the best, I recommend the same to you! (I don't mean to reject the efforts
Borland made to help me... but life is only so long. In Windows programming, you have to walk a tightrope
between delving deeply enough to get the job done, and trying to understand thihngs. Learning to spot the bit
that needs further exploration when something doesn't work is a major part of the art of programming.)
Enough philosphy! What the Delphi Help says: "If the highest-order byte is zero ($00), the color obtained is
the closest matching color in the system palette. If the highest-order byte is one ($01), the color obtained is
the closest matching color in the currently realized palette. If the highest-order byte is two ($02), the value is
matched with the nearest color in the logical palette of the current device context. To work with logical
palettes, you must select the palette with the Windows API function SelectPalette. To realize a palette, you
must use the Windows API function RealizePalette."

Back to work!

Our program at the moment makes the square a random color. (I hope! If it doesn't, you need to get it that far
before proceeding!)

Change...

random(255*255)+255*255

to

256*256*256

Your square should now alternate between black and blue.

Also try

256*255

and

255

They should give black/green and black/red, respecively.

http://sheepdogguides.com/dt4e.htm (4 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

(All of this is a little easier if you understand hexadecimal numbers, by the way... by we'll struggle on in
decimal for those who don't. If you see, say, $00FF0000 in other reference materials, that's just a more
suitable way of writing 16711680 which is 256*256*255)

In general: With bb,br and bg each equal to something from 0-255 (inclusive), you can descrive a color
with...

(256*256*bb) + (256*bg) + br

The higher each variable part is, the more blue, green, and red (respecively) there wil be in the resulting
color. For black, make all 0. For while make all 255.

You could have a little fun writing a program with three edit boxes on dd14f1. They would accept values for
how much blue, green, and red you wanted, and then your DoIt button would display a square of the color
you'd described... but I'm not going to explore that here!

I am going to put a function in dd14sau which can be used to "assemble" color description numbers:

In dd14sau, just after the "baRectColo: array[0..7,0..7] of byte;" in the type declaration, add..

function liColorNumber(r,g,b:longint):longint;

and just before the "end." of dd14sau, add...

function Tdd14sauf.liColorNumber(r,g,b:longint):longint;
begin
result:=65536*b+256*g+r;
end;

(Note that r,g and b are declared as type longint. If they are, as might seem reasonable, byte type variables,
the result will not be calculated as you would like.... Prior to the final transfer to "result", the number could
be altered.)

Then go into dd14u1, and change...

else dd14sauf.shTmp.brush.color:=....

to read...

else dd14sauf.shTmp.brush.color:=dd14sauf.liColorNumber(0,255,255);

Run the program; the square should alternate black/cyan (light blue). Whatever three numbers you supply to
ColorNumber will determine how much red, green and blue there is in the alternative to black.

So much for colors! Now for color management!

http://sheepdogguides.com/dt4e.htm (5 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

Then go into dd14u1, and change...

else dd14sauf.shTmp.brush.color:=....

to read...

else dd14sauf.shTmp.brush.color:=dd14sauf.liaColorMap[0];

and, a few lines above, change

dd14sauf.liaColoMap[0]:=5;

to...

dd14sauf.liaColoMap[0]:=dd14sauf.liColorNumber(0,255,255);

(Run thr program to be sure it survived this trivial change.)

In our progress to our final goal, we've now reached the point were we're going to generate a list of the colors
we want to use. This topic will reward many hours of exploration, so I'm going to just give you an answer.
There are many, many solutions.

OnFormCreate add.....

Just before dd14f1.buDoItClick's "begin" add...

var c1,c2:byte;

(we won't need c2 for a while, but will later) and just after it's "begin" add
begin
for c1:=0 to 255 do begin
if c1<80 then dd14sauf.liaColoMap[c1]:=
dd14sauf.liColorNumber(40,c1*2+80,40);
if (c1>79) and (c1<160) then dd14sauf.liaColoMap[c1]:=
dd14sauf.liColorNumber(random(255),0,255);
if c1>159 then dd14sauf.liaColoMap[c1]:=
dd14sauf.liColorNumber(255,random(255),0);
end;

Take out the old line saying

dd14sauf.liaColoMap[0]:=.....mber(random(256),random(256),random(256));

An aside: It is a pity that this code, and the "dd14sauf.show;" just after it cannot be put in dd14f1's
OnFormCreate. Both do not need to be re-executed every time you click on "Do It". However, there is a
problem with accessing dd14sau objects before dd14f1's OnCreate has been completed, and I don't know
where to put these things. (End aside)

http://sheepdogguides.com/dt4e.htm (6 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

Also, further down dd14f1.buDoItClick make...

else dd14sauf.shTmp.brush.color:=dd14sauf.liaColoMap[0];

into...

else dd14sauf.shTmp.brush.color:=dd14sauf.liaColoMap[random(80)];

(For the moment I'm not using the colors in the map at locations 81-255)

Run the program again. Clicking DoIt gives you (I hope!) black and various shared of green.

Tired of clicking "DoIt"? So am I. Time for something better.

(You can skip from here down to "End of "You can skip"" if you wish...)

First a simple answer....

Add 8 more TShape objects to dd14say. They can keep their system assigned names. Arrange them and
shTmp ROUGHLY in three rows of three. (The result is nicer if they are not all exactly the same size and
shape, and not all lined up precisely.)

Replace DoIt's old

if dd14sauf.shTmp.brush.color<>0
then dd14sauf.shTmp.brush.color:=0 (*no ; here*)
else dd14sauf.shTmp.brush.color:=dd14sauf.liaColoMap[random(80)];

with... (the word "with" is not a typo! Use copy/paste to generate most of this)...

with dd14sauf do begin


shTmp.brush.color:=liaColoMap[random(80)];
Shape1.brush.color:=liaColoMap[random(80)];
Shape2.brush.color:=liaColoMap[random(80)];
Shape3.brush.color:=liaColoMap[random(80)];
Shape4.brush.color:=liaColoMap[random(80)];
Shape5.brush.color:=liaColoMap[random(80)];
Shape6.brush.color:=liaColoMap[random(80)];
Shape7.brush.color:=liaColoMap[random(80)];
Shape8.brush.color:=liaColoMap[random(80)];
end;(*with*)

(The "with dd14sauf.. do .. end" saves you specifying dd14sauf repeatedly.)

Run this, and you should get the nine rectangles in different shades of green each time you click "Do It".

http://sheepdogguides.com/dt4e.htm (7 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

When all is well, from DoIt's code, delete what we just added, and from dd14sauf remove all 9 shapes.

(End of "You can skip")

If you skipped the simple answer, delete DoIt's old

if dd14sauf.shTmp.brush.color<>0
then dd14sauf.shTmp.brush.color:=0 (*no ; here*)
else dd14sauf.shTmp.brush.color:=dd14sauf.liaColoMap[random(80)];

before proceeding.

Now we need to create an array of shapes of type TShape. (If the following is too streamlined, see Dt3a.htm
"Creating an array of edit boxes", which covers the issues more throughly. By the way, sorry: Unless I've
edited that since writing this, there's an error about a quarter of the way through that. Where it says...

"Use the Object Inspector to create an OnCreate event handler for TEdit",

it should say

"Use the Object Inspector to create an OnCreate event handler for Demof1")

All of the following are in dd14sau...

In the public section, between

baRectColo: array[0..7,0..7] of byte;

and...

function liColorNumber(r,g,b:longint):longint;

add...

ashRect:array[0..4,0..4] of TShape;

(N.B.: This is not exactly the approach used in my "Creating an array of edit boxes" tutorial.

Also N.B.: The line cannot go after the "Function..." line. (I would guess that the rule is that all fields have to
appear after "Public" before any function or procedure headers, although the Delphi Help file would seem to
imply that they can be intermingled.)

(Further details of "Also N.B.": In Delphi I, anyway...

public

http://sheepdogguides.com/dt4e.htm (8 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

liaColoMap:array [0..255] of longint;


baRectColo: array[0..7,0..7] of byte;
ashRect:array[0..4,0..4] of TShape;
function liColorNumber(r,g,b:longint):longint;
end;

compiles, but...

public
liaColoMap:array [0..255] of longint;
baRectColo: array[0..7,0..7] of byte;
function liColorNumber(r,g,b:longint):longint;
ashRect:array[0..4,0..4] of TShape;
end;

complains "END expected". Can anyone shed light on this?)

Use the Object Inspector to create an OnCreate event handler for dd14sauf1. Make it...

procedure Tdd14sauf.FormCreate(Sender: TObject);


var c1,c2:byte;
begin
for c1:=0 to 3 do
for c2:=0 to 3 do begin
ashRect[c1,c2]:=TShape.create(self);
ashRect[c1,c2].parent:=TWinControl(self);
ashRect[c1,c2].top:=c2*24;
ashRect[c1,c2].left:=c1*24;
ashRect[c1,c2].width:=24;
ashRect[c1,c2].height:=24;
end;
end;

.. and run it. When you click "DoIt", you should get 16 neatly spaced white boxes on dd14sauf1.

Now go back to dd14u1. In DoItClick, just after dd14sauf.show, just to get started, add....

dd14sauf.ashRect[0,0].brush.color:=256*255;

Once that works, replace the previous feeble line with....

for c1:=0 to 3 do
for c2:=0 to 3 do

http://sheepdogguides.com/dt4e.htm (9 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

application.processmessages;
dd14sauf.ashRect[c1,c2].brush.color:=dd14sauf.liaColoMap[random(80)];

Clicking DoIt now draws and redraws a grid of green squares... but it does it more

elegantly than by the means used in the "You can skip this" section!!

_________
Before we forge ahead, we ought to go back and change something to make it more elegant. Our program, as
written, produces a 4x4 array of TShape objects. To change the number of elements in the grid would be a
pain.

After dd14sau's "Uses" clause, add...

const kx=4;
ky=2;

and change

ashRect:array[0..3,0..3] of TShape;

to

ashRect:array[0..kx,0..ky] of TShape;

and go through the rest of the program (both units) changing 4 hard coded "3"s to kx, ky, dd14sau.kx or
dd14sau.ky as appropriate. After several hours' work, I changed the kx, ky settings from 4/2 to 10/5.. and had
a crash, by the way. There may be a problem with what I've told you... create may need to be balanced by an
explicit destroy... but it may just be that dear old Windows 3.11 does crash from time to time. I'd saved the
delphi work just before the crash... but had to re-write a chunk of this, sigh. Oddly(?) enough, I later had a
similar crash as soon as I re-ran the application having just changed the values of kx and ky. The overhead of
all those TShape objects may be too much for my poor little system, but I'd prefer that Delphi decile more
graciously! Any ideas? By the way... if you want to use something like this program, but without the TShape
objects... that aspect can be written out quite easily.

_____________
In a similar "let's make it elegant" vein: In dd14sau, just after "Public", add...

bRectHeight,bRectWidth:byte;

and change the four 24s in the OnCreate handler to bRectHeight or bRectWidth as appropriate.

Alter kx,ky,bRectHeight,bRectWidth to taste... after saving your open files!!


_____________

I did't like the black lines between rectangles. I tried adding

http://sheepdogguides.com/dt4e.htm (10 of 14) [1/28/2005 3:46:51 PM]


Delphi tutorial: Color Graphics. (Level 4).

ashRect[c1,c2].pen.width:=0;

to the ashRect[] init section, but it didn't do a good job. I made it

ashRect[c1,c2].pen.width:=1;

and then went to the place in dd14u1 which did

for c2:=0 to dd14sau.ky do


dd14sauf.ashRect[c1,c2].brush.color:=dd14sauf.liaColoMap[random(80)];

and made it (note the added "begin")..

for c2:=0 to dd14sau.ky do begin


application.processmessages;
liTmp:=dd14sauf.liaColoMap[random(80)];
dd14sauf.ashRect[c1,c2].brush.color:=liTmp;
dd14sauf.ashRect[c1,c2].pen.color:=liTmp;
end;

===============
Well! We've got a pretty program. To make it look nice, all of the rectangles change color whenever we click
"DoIt", but it would be fine to change just one at a time from code in dd14u1. It is as simple as...

x:={some value};
y:={some value};
liTmp:=dd14sauf.liaColoMap[{some value}];
dd14sauf.ashRect[x,y].brush.color:=liTmp;
dd14sauf.ashRect[x,y].pen.color:=liTmp;

============================

Two problems remain:

a) We re-initialise all of aliColoMap and call dd14sauf.show every time we call "DoIt". These two jobs
should be done just once, as the program lauches... unless for some reason we want to change the range of
colors available at some point in the program. I don't know how to fix this at present. (Putting the relevant
code into dd14f1's OnFormCreate triggered error messages.) I can live with this.

b) When I started, I said that this tutorial would also illustrate some of the solutoins to the fact that the
programmer does not know what resolution the user will have in effect, nor what window size will be used.
These issues are not tightly tied to the rest of what we've done, but this is a reasonable chance to address
them.

_________
In the application's present form, the size of the second window (dd14sauf) and the size of the rectangles in it

http://sheepdogguides.com/dt4e.htm (11 of 14) [1/28/2005 3:46:52 PM]


Delphi tutorial: Color Graphics. (Level 4).

are not connected. It would be nice if the rectangles changed size to use as much of the window as possible. I
must admit that when I set out to accomplish this I didn't "know" exactly what to do. By dumb luck, I rapidly
found that Windows makes it all very easy... at least that seems to be the case.

First, for dd14sauf, create an OnResize event, as follows. Most of the lines can be takes straight from the
existing OnCreate event. Remove them from the OnCreate handler. It seems that, in effect, at least, the
OnResize code is called at some point during the form's creation. It is also called any time the form is
resized, e.g. by the user.

var c1,c2:byte;
begin
for c1:=0 to kx do
for c2:=0 to ky do begin
ashRect[c1,c2].top:=c2*bRectHeight;
ashRect[c1,c2].left:=c1*bRectWidth;
ashRect[c1,c2].width:=bRectWidth;
ashRect[c1,c2].height:=bRectHeight;
end;
end;

Even though it will not behave differently than the previous version of the program, get this much
"working".

Now, from OnCreate, remove the...

bRectHeight:=40;
bRectWidth:=20;

and in OnResize add...

bRectHeight:=clientheight div (ky+1);


bRectWidth:=clientwidth div (kx+1);

dd14sau's form can now be maximized, minimized, restored, and made any size or shape you like... and the
rectangles adjust to fill the available space!! Amazing.

One small blemish remains: at certain sizes, there's a small border at the bottom and/or at the right. This
arises as follows: suppose there are six rectangles across the window. Suppose the window is 62 units wide.
If each rectangle is 10 units wide, they won't quite fill the window. If each is 11 units wide, they will more
than fill it.

Add the following two lines at the beginning of OnResize...

while (clientheight mod (ky+1)>0) and (height>0) do height:=height-1;


while (clientwidth mod (kx+1)>0) and (width>1) do width:=width-1;

http://sheepdogguides.com/dt4e.htm (12 of 14) [1/28/2005 3:46:52 PM]


Delphi tutorial: Color Graphics. (Level 4).

Hard to believe that's all it takes... but it works!

=====
That covers the material of the tutorial. Before I close, in less detail (and less thoroughly checked for
complete correctness!): Some of the games I played with the application, simply by making changes in
dd14u1. dd14sau was left unchanged.

Added Start and stop buttons and a timer. All were disabled at design. The buttons were enabled by buDoIt.
(This ensured a dd14sau.show and filling of liaColoMap before Start could be clicked.) The start button
enabled the timer. (Stop diabled it). The timer's event handler changed the colors of all the squares, just as
DoIt changed their colors. (In fact, I moved the "Change the colors" code out into a proc ("ChangeAll") that
could be called from more than one place.)

Added combobox, with possible values "Greens", "Band 1", "Band 2" and "All" Created
combobox.OnChange consisting of bCS:=combobox.itemindex;ChangeAll;

Revised ChangeAll, making it

procedure Tdd14f1.ChangeAll;
var c1,c2:byte;
begin
for c1:=0 to dd14sau.kx do
for c2:=0 to dd14sau.ky do begin
application.processmessages;
if bCS=0 then liTmp:=dd14sauf.liaColoMap[random(80)];
if bCS=1 then liTmp:=dd14sauf.liaColoMap[random(80)+80];
if bCS=2 then liTmp:=dd14sauf.liaColoMap[random(96)+160];
if bCS=3 then liTmp:=dd14sauf.liaColoMap[random(256)];
dd14sauf.ashRect[c1,c2].brush.color:=liTmp;
dd14sauf.ashRect[c1,c2].pen.color:=liTmp;
end;
end;
(N.B. The change of colors used only becomes evident on next ChangeAll)

_____________
Sorry to end a bit abruptly... but if you want this on the web instead of languishing in my computer.....

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

http://sheepdogguides.com/dt4e.htm (13 of 14) [1/28/2005 3:46:52 PM]


Delphi tutorial: Color Graphics. (Level 4).

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However..
this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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
Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt4e.htm (14 of 14) [1/28/2005 3:46:52 PM]


Delphi: Automating the creation of an HTML photo album

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

Delphi: Automating the creation of an HTML photo


album
This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

This particular tutorial is atypically sketchy... please don't judge the others from this. However, while it
may lack guidance, there is source code for a program. The source code is heavily commented... see it for
some of the "tutorial" element in this. I am working on a shareware version of the program, email me if
interested (c. $20) Click here to download a zip file with the source code.

First: What this ISN'T: It isn't a system to set up an image server for the internet.

What it is: The program reads a script file put together by the user. It generates some html which can be
posted on the web to display jpeg files located in the same location on the web. The results look like my
photo album of my South America trip, see the link below. The slow load ime, by the way, is a function
of the level of quality I chose for the images, not of the html delivering them...

Click here for my photos.

The script file is prepared using Notepad or similar. It essentially says "I want {this image}, {this size},
with {this caption}. That material is repeated once for each photo. The Delphi program in the zip file is
then run, and suitable html is generated, for posting, with the images, on the web.

The program is incomplete. However, you can see things working in it, and see how they work. I'm quite
pleased with the interlocking use I've made of OnExit and OnChange events for the edit boxes, and
{button}.enabled:=true/false to error check filename specifications, and prevent inadvertant overwriting
of already existing files.

You will also see a way to use memos to access small text files, e.g. ini files, or, as in this case, script
files.

Apologies for the sketchy notes... I have to post this as it is now, or leave the material unavailable even
longer!!! Let me know if anything here is seriously wrong or misleading?

http://sheepdogguides.com/dt4f.htm (1 of 2) [1/28/2005 3:46:55 PM]


Delphi: Automating the creation of an HTML photo album

Click here to download zip file with the source code.

Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt4f.htm (2 of 2) [1/28/2005 3:46:55 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

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

Delphi: A wind vane/ angle/ compass display. Event


handling. The tag property.
This has good information, and a search button at the bottom of the
page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

I was working on a weather logging program, and I wanted something to show the wind's direction. What
I used derives from this. The result is a circle on the screen with an arrow (well, almost) inside it, which
can point in any one of 16 directions... the well known North, NE, East, SE, South, SW, West and NW,
plus the less well known NNE, ENE, etc which lie between the directions already listed. While the result
probably seems somewhat trivial and useless, read on, because the project illustrated some useful general
techniques.

Start a new project, call it DD31.


Name the form DD31f1.

Put an image on it. Make it 150 units high, and 150 units wide.

We're going to start with a simple answer, and then develop that into something more clever. Don't
despair if the start seems pedestrian.

Add two buttons, named buNorth, buEast, captions 'North' and 'East'.

Provide the following handlers...

procedure TDD31f1.buNorthClick(Sender: TObject);


begin
image1.canvas.moveto(75,150);
image1.canvas.lineto(75,0)
end;

procedure TDD31f1.buEastClick(Sender: TObject);


begin
image1.canvas.moveto(150,75);
image1.canvas.lineto(0,75)
end;
(Throughout, you might want to use "kMax" in place of 150, having put 150 into a variable or constant

http://sheepdogguides.com/dt4g.htm (1 of 9) [1/28/2005 3:46:59 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

called kMax early in the program. If you adopt this, then you'd use kMax div 2 where ever you see 75,
and 0 where ever you see 0.)

When you run the program, clicking "North" should give a vertical line, clicking "East" should give a
horizontal line. Each remains after drawn. Don't be alarmed that you do not see the image until the first
line is drawn.

In the "TDD31f1 = class(TForm)..." section near the top of the program, just after....

procedure buEastClick(Sender: TObject);


...add...

procedure buDirClick(Sender: TObject);


and, just before the program's terminal "end.", add...

procedure TDD31f1.buDirClick(Sender:TObject);
begin
if sender=buNorth then begin
image1.canvas.moveto(75,150);
image1.canvas.lineto(75,0)
end;
end;
Run the program, then stop it again. (Delphi may need this for the Object Inspector to become aware of
buDirClick)

Bring up a view of the form. Click on buNorth. Go to the "events" section of the Object Inspector, click
on the pull down arrow of the "OnClick" event handler line. Set buNorth's OnClick handler to
buDirClick.

Delete the two lines of human written code in the original buNorthClick handler, reducing it to....

procedure TDD31f1.buNorthClick(Sender: TObject);


begin
end;
Run the program again. Try buNorth. You should see what you saw before. When you quit the program,
and go back to editing it, all traces of buNorthClcik should have been cleared away by Delphi's
wonderful RAD environment.

Move the code for handling buEastClick into buDirClick, reset buEast's OnClick handler.

Add....
baX,baY:array[0..15]of byte;
... just after the

http://sheepdogguides.com/dt4g.htm (2 of 9) [1/28/2005 3:46:59 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

private
{ Private declarations }
...near the start of the program.

Create an FormCreate handler (double click on part of the form) with the following. Be sure to use
copy/paste creatively...

image1.canvas.moveto(0,0);
baX[0]:=75;baY[0]:=0;
baX[4]:=150;baY[4]:=75;
baX[8]:=75;baY[8]:=150;
baX[12]:=0;baY[12]:=75;
(The first line should clear the previous annoyance of the image not appearing until the first line is
drawn.)

Change buDirClick as follows....

if sender=buNorth then begin


image1.canvas.moveto(baX[8],baY[8]);
image1.canvas.lineto(baX[0],baY[0])
end;
if sender=buEast then begin
image1.canvas.moveto(baX[12],baY[12]);
image1.canvas.lineto(baX[4],baY[4])
end;
Make the first three lines of buDirClick...

procedure TDD31f1.buDirClick(Sender:TObject);
begin
image1.canvas.pen.width:=1;
image1.canvas.ellipse(0,0,150,150);
image1.canvas.pen.width:=4;
This will cause prior lines to be erased before the most recently requested line is drawn. (The two
pen.width lines are not essential to the line clearing, but they improve the overall result.)

If you want to get fancy, replace image1.canvas.ellipse(0,0,150,150); with....

with image1.canvas do begin


brush.color:=clBtnFace;
pen.color:=clBtnFace;
rectangle(0,0,150,150);
brush.color:=clRed;
pen.color:=clBlack;

http://sheepdogguides.com/dt4g.htm (3 of 9) [1/28/2005 3:46:59 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

ellipse(0,0,150,150);
moveto(0,0);
end;(*with...*)
That covers MOST of the underlying principles involved in this tutorial. Take a break, have a cup of
coffee.

===========
Now we're going to shift up a gear. Most of what is going to be done in the following section could be
done simply by extending what we've already seen... but the WAY we're going to do it in the following is
much more elegant... if a little less transparent!!

Use the object inspector to set buNorth's "tag" property to zero, and buEast's tag property to 4.

Then change buDirClick. You are going to reduce the whole thing to just...

procedure TDD31f1.buDirClick(Sender:TObject);
var bTmp:byte;
begin
bTmp:=((sender as tbutton).tag);
image1.canvas.pen.width:=1;
image1.canvas.ellipse(0,0,150,150);
image1.canvas.pen.width:=4;

image1.canvas.moveto(baX[bTmp+8],baY[bTmp+8]);
image1.canvas.lineto(baX[bTmp],baY[bTmp])
end;(*buDirClick*)
... and we're going to extend this program to be able to show 16 directions, with very little extra code in
buDirClick!! I said we could be elegant!

Change the labels of buNorth and buEast to merely 'N' and 'E' respectively. Move them to the appropriate
places on the edge of image1.
Add a button named buNorthEast
Caption it 'NE'
Set it's tag to 2
Set its OnClick handler to buDirClick

To FormCreate, add

baX[2]:=127;bay[2]:=27;
baX[10]:=27;bay[10]:=127;
Now for "arrowheads"... of a sort...

In the declarations just after "private" revise the existing line, to make it....

http://sheepdogguides.com/dt4g.htm (4 of 9) [1/28/2005 3:46:59 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

baX,baY,baX2,baY2:array[0..15]of byte;
.. and to FormCreate, add

baX2[0]:=75;baY2[0]:=10;
baX2[2]:=122;baY2[2]:=32;
baX2[4]:=140;baY2[4]:=75;
...and make buDirClick...

procedure TDD31f1.buDirClick(Sender:TObject);
var bTmp:byte;
begin
bTmp:=((sender as tbutton).tag);
image1.canvas.pen.width:=1;
image1.canvas.ellipse(0,0,150,150);
image1.canvas.pen.width:=4;

image1.canvas.moveto(baX[bTmp+8],baY[bTmp+8]);
image1.canvas.lineto(baX[bTmp],baY[bTmp]);
image1.canvas.pen.width:=12;
image1.canvas.lineto(baX2[bTmp],baY2[bTmp]);
end;(*buDirClick*)
(which only means adding 2 lines, if you did the first "pen" lines earlier)

Now... we have a "Draw line to North" button. A "Draw line to South button" shouldn't be so tricky....

Add the button


Set the tag to 8
Set its OnClick handler to buDirClick

Add

baX2[8]:=75;baY2[8]:=140;
Alter buDirClick as follows. Much is unchanged, but I've quoted it all to avoid problems...

procedure TDD31f1.buDirClick(Sender:TObject);
var bTmp:byte;
begin
bTmp:=((sender as tbutton).tag);
image1.canvas.pen.width:=1;
image1.canvas.ellipse(0,0,150,150);
image1.canvas.pen.width:=4;

if bTmp<8 then begin


image1.canvas.moveto(baX[bTmp+8],baY[bTmp+8]);

http://sheepdogguides.com/dt4g.htm (5 of 9) [1/28/2005 3:46:59 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

image1.canvas.lineto(baX[bTmp],baY[bTmp]);
image1.canvas.pen.width:=12;
image1.canvas.lineto(baX2[bTmp],baY2[bTmp]);
end (*no ; here*)
else begin
image1.canvas.moveto(baX[bTmp-8],baY[bTmp-8]);
image1.canvas.lineto(baX[bTmp],baY[bTmp]);
image1.canvas.pen.width:=12;
image1.canvas.lineto(baX2[bTmp],baY2[bTmp]);
end;(*of else*)
end;(*buDirClick*)
We're really doing little beyond what we were doing before the coffee break... it just looks hard because
elements have become abstract.

There's just one more thing to deal with. Until now, we have established the coordinates for points on the
edge of the circle by hand. The following contains no profound insights into the operation of Delphi, and
you can just copy it without close study if you wish. It sets up all the coordinates you need for doing
arrows in 16 directions. Add the appropriate buttons to your form, assign all of their OnClicks to
buDirClick, set their tag values (0-15, clockwise. N:0, E:4, S:8, W:12)... and you're done!

Add in form's "private" section...

kArrowLength,kPenFudge,kEighthFudge,
bTmpX,bTmpY:byte;
kPenFudge is used to slightly shorten the lines, so that the outside edge of the line is still inside the circle
drawn.

kEighthFudge is used to "twist" the arrows slightly on the arrows to directions 1,3,5, etc, i.e. NNE, ENE,
ESE, etc.

Replace earlier by-hand baX[], baY[] determinations with...

kWidthHeight:=150;(*This and next: to make


doing other sizes easy*)
kRadius:=kWidthHeight div 2;
kCentX:=kRadius;kCentY:=kRadius;
kArrowLength:=10;

(*Constants for N,E,S,W*)


baX[0]:=kRadius;baY[0]:=0;
baX2[0]:=baX[0];baY2[0]:=baY[0]+kArrowLength;
baX[4]:=kWidthHeight;baY[4]:=kRadius;
baX2[4]:=baX[4]-kArrowLength;baY2[4]:=baY[4];
baX[8]:=kRadius;baY[8]:=kWidthHeight;
baX2[8]:=baX[8];baY2[8]:=baY[8]-kArrowLength;

http://sheepdogguides.com/dt4g.htm (6 of 9) [1/28/2005 3:46:59 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

baX[12]:=0;baY[12]:=kRadius;
baX2[12]:=baX[12]+kArrowLength;baY2[12]:=baY[12];

(*Constants for NE,SE,SW,NW*)


kPenFudge:=4;
(*If you are using a "fat" pen for the "arrow" part
of the line, "ink" spills outside of the circle.
Adjust the size of kPenFudge to overcome this.
(Increase kPenFudge if you are experiencing
overspill after changing the arrow width.)*)
bTmpX:=trunc(cos(pi/4)*kRadius)-kPenFudge;
bTmpY:=trunc(sin(pi/4)*kRadius)-kPenFudge;
(*Yes, we'll need two variables... later*)

baX[2]:=kCentX+bTmpX;baY[2]:=kCentY-bTmpY;
baX2[2]:=baX[2]-kArrowLength;baY2[2]:=baY[2]+kArrowLength;
baX[10]:=kCentX-bTmpX;baY[10]:=kCentY+bTmpY;
baX2[10]:=baX[10]+kArrowLength;baY2[10]:=baY[10]-kArrowLength;

baX[6]:=kCentX+bTmpX;baY[6]:=kCentY+bTmpY;
baX2[6]:=baX[6]-kArrowLength;baY2[6]:=baY[6]-kArrowLength;
baX[14]:=kCentX-bTmpX;baY[14]:=kCentY-bTmpY;
baX2[14]:=baX[14]+kArrowLength;baY2[14]:=baY[14]+kArrowLength;

(*Constants for NNE,ENE,ESE,SSE,SSW,WSW,WNWnNNW*)


kPenFudge:=4;
(*If you are using a "fat" pen for the "arrow" part
of the line, "ink" spills outside of the circle.
Adjust the size of kPenFudge to overcome this.
(Increase kPenFudge if you are experiencing
overspill after changing the arrow width.)*)
kEighthFudge:=7;
(*This is used to "twist" the arrowheads slightly
for directions 1,3,5,7,9,11,13,and 15, i.e.
NNE,ENE, etc *)
bTmpX:=trunc(cos(pi/8)*kRadius)-kPenFudge;
bTmpY:=trunc(sin(pi/8)*kRadius)-kPenFudge;
{showmessage(inttostr(bTmpX)+' '+inttostr(bTmpY));}

baX[1]:=kCentX+bTmpY;baY[1]:=kCentY-bTmpX;
baX2[1]:=baX[1]-kArrowLength+kEighthFudge;
baY2[1]:=baY[1]+kArrowLength;
baX[9]:=kCentX-bTmpY;baY[9]:=kCentY+bTmpX;
baX2[9]:=baX[9]+kArrowLength-kEighthFudge;
baY2[9]:=baY[9]-kArrowLength;

http://sheepdogguides.com/dt4g.htm (7 of 9) [1/28/2005 3:46:59 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

baX[7]:=kCentX+bTmpY;baY[7]:=kCentY+bTmpX;
baX2[7]:=baX[7]-kArrowLength+kEighthFudge;
baY2[7]:=baY[7]-kArrowLength;
baX[15]:=kCentX-bTmpY;baY[15]:=kCentY-bTmpX;
baX2[15]:=baX[15]+kArrowLength-kEighthFudge;
baY2[15]:=baY[15]+kArrowLength;

baX[3]:=kCentX+bTmpX;baY[3]:=kCentY-bTmpY;
baX2[3]:=baX[3]-kArrowLength;
baY2[3]:=baY[3]+kArrowLength-kEighthFudge;
baX[11]:=kCentX-bTmpX;baY[11]:=kCentY+bTmpY;
baX2[11]:=baX[11]+kArrowLength;
baY2[11]:=baY[11]-kArrowLength+kEighthFudge;

baX[5]:=kCentX+bTmpX;baY[5]:=kCentY+bTmpY;
baX2[5]:=baX[5]-kArrowLength;
baY2[5]:=baY[5]-kArrowLength+kEighthFudge;
baX[13]:=kCentX-bTmpX;baY[13]:=kCentY-bTmpY;
baX2[13]:=baX[13]+kArrowLength;
baY2[13]:=baY[13]+kArrowLength-kEighthFudge;
That's it! The program is done! (There are some lovely symmetries in the block of code just presented.
Not "important", but you might enjoy them, if you enjoy mathematical beauties.)

You can fetch the source code for the above by clicking on "the source code" link to download a zip with
it and the exe.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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.

http://sheepdogguides.com/dt4g.htm (8 of 9) [1/28/2005 3:46:59 PM]


Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.

Link to Tutorials main page

Info on how to contact this page's editor, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dt4g.htm (9 of 9) [1/28/2005 3:46:59 PM]


Delphi: Extracting data from records in text files

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

Delphi: Extracting data from records in text files


Objectives:
First I'll explain what I wanted a program for. You can decide whether there will be elements of interest to you! I'll also be
taking you through my development process, which I think illustrates important skills.

I am a stock market investor. At the end of each day, I use a program called Personal Stock Monitor (link to their site) to fetch
data for a number of stocks. That program maintains text files, one for each stock I follow, with a line for each day's data. They
are in chronological order. The following is an example. It was a happy accident that I turned to this program just after my data
supplier changed the format of the data slightly! The files do not have the column headings....

Date Time Prices Volume


Prices
Close High Low
09/26/2003 21:53 18.4210 19.0500 18.3600 29403008 18.7500 11.8400
24.9900
10/06/2003 22:35 19.3100 19.6100 19.1000 17971696 19.5300 19.3000
19.3400
10/09/2003 22:57 20.5530 20.8200 20.1690 38441856 20.5900 20.5900
20.6400
10/21/2003 22:24 21.89 21.97 21.58 19685136 21.96 21.81 21.87
10/29/2003 03:46 22.55 22.60 21.34 47612796 21.42 11.58 33.41
10/31/2003 00:44 23.24 23.48 22.58 34529904 22.98 12.09 34.39
10/31/2003 00:44 23.24 23.48 22.58 34529904 22.98 12.09 34.39
All of the text files are named with the standard stock market abbreviation for the stock. They are all in one folder. What I
wanted was a program to scan all of these data files and produce a single file telling me the prices for all the different
companies on a given day.... typically a recent day. I.e., a file like the following should be generated from the data in APC.txt,
BORL.txt, CMX.txt, etc. (These are ficticious prices)

ABS 12.43 APC 45.25 BORL 8.94 CMX 56.24 EMC 28.41 ... etc

(This file will be used by other programs and used to supply the data to spreadsheets... but that is outside of the scope of this
tutorial.)

Anyone using the program regularly would soon become annoyed if he/ she had repeatedly to enter the path to the folder with
the datafiles. Additionally, I would think it reasonable to allow the user to specify where the output file should go, and what
name to give it just once. Information like this is, in "proper" Windows programming supposed to go in the registry... a
practice I dislike for various reasons. I still use the "old fashioned" approach: I keep such information in an "ini" (for
"initialization") file... but that refinement is also outside this tutorial's scope.

Any time you set out to write a program, think long and hard about where you are going before you start. Know what the
program will do, in detail. Start by thinking about the user's experience. What should the profram produce? What input will be
needed? What options will exist? Even think in detail about the appearance of the forms which will appear on the screen.
Think about what information needs to be tracked while the program runs. In a similar vein, think about what the program's
output is going to be. Lastly, you have to think how you will accomplish the things that have to go on behind the scenes. You
may have to revise your objectives at this stage!

From part of what I just said, it would seem that I should insert a graphic into this tutorial, to show you the basic form that the
user will encounter when running the program. I agree... but... forgive me?.... The writing of these tutorials is quite a bit of
work, and starting to create graphics is just one chore I'm shirking. I think the descriptions that follow should suffice. Perhaps

http://sheepdogguides.com/dt4h.htm (1 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

this is also the place to apologise: This tutorial needs some editing to make it more readable. The information is, I hope,
correct. I thought you'd rather have imperfect now vs. better much later?

Project's parts:
The project presents a number of interesting problems. They could be tackled in a variety of orders. Knowing which bit to start
with is part of the art of programming. As I said above, be sure that you know how you are going to do all parts of the project
before you start, but, once you have those plans laid, start "building your house" by assembling sub-units that can eventually
be bolted together. This tutorial illustrates that approach, I hope.

Project's parts:
Providing for the use of the ini file to "fill in" default requirements.
Opening, writing to, closing the output file.
Getting initial information from the user (e.g. What is the date for which prices are required.)
Looking at one file, to see if a price date is available for that stock.
Besides being able to fetch the detail from one file of prices, the mechanism to scan a bunch of prices files needs to be created.

Let's start...
I'm going to start the project by creating a program which will go to a specific price file and look for prices for a particular
date. I'm working in Delphi 2 for this tutorial.

Parts of what I suggest you type in the following are not "needed" in the final program. They are here so that you will
experience the route I took to the program I needed. The tutorial was merely a bonus added to obtaining a real program I
needed for a real job. If you follow the tutorial through, you see how a program can be developed without undue headache.
The final result is far from being the whole point.

Speaking of headache: I'm sorry there are so many fields in each of the data records. Three or four would have done for the
purposes of the tutorial, but the data records of my real world need were what you see here.

You'll find the following tutorials also address the questions of reading and writing to data files. They were written assuming
less familiarity with the concepts that is assumed here.
(Level 2) File Handling... How to read data from files on disc, and write to such files. (A long tutorial)
(Level 3) How to access database files... It is remarkably easy to write a program in Delphi which allows you to view and edit
files shared with Paradox, dBase, Access, etc. Learn how here!
Images and File Access... Display .bmp images on your form. Access all the files in a given folder on your disc, using that as
the basis for a "Can you recognise..." exercise. Tutorial has rough edges, but full source listing of working program given.

Time to start typing...


Create a folder for the project.
Create a folder within it called DemoData... to hold some files with price information.
Use Wordpad to create a file holding the data given above ("09/26/2003 21:53 18.4...") The data are separated by tabs within
each line, and a CR/LF pair at the end of each line.
Save that data several times, as: IBM.txt, PFE.txt, and MCD.txt... to simulate files for prices of IBM, Pfizer, and McDonalds.
(Yes, that really is McDonalds' ticker. Pity. (Think about it... extra credit to those who email (text only!) with the reason
why!)) Change the prices if you want to. Or the names, for that matter! These files are just for seeing if we can access some
test data, before trying to deal with "the real thing".

Start a new project. I called mine DD42 (42nd Delphi Demo program)
Name the form DD42f1.
Put a button called buDoIt, captioned 'Do It', on the form.

http://sheepdogguides.com/dt4h.htm (2 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

Put a lable on the form called laTmp.

Create the following event handler for buDoItClick:

procedure TDD42f1.buDoItClick(Sender: TObject);


begin
laTmp.caption:='At '+DateTimeToStr(time)+', button works';
end;
Save the unit and project as DD42u1 and DD42 respectively.

Hardly a finished project... but a start! Our "base camp" is going to be a program which will report the price for a given stock
on a given date when we click the "Do It" button.

Pressing on....

Just after the "private" in the TDD42f1 class definition, declare the following variables:

boDFInOpen,boDFOutOpen:boolean;
dfIn:file of byte;
dfOut:text;
sTmp:string;
bTmp:byte;
liTmp:longint;
The first two will be flags which we use to keep track of whether an input data file is open and whether the output datafile is
open. You might wonder, "Well, don't we know?" We know... but will your program know? Suppose a user decides to click
the little "x" in the form's upper right hand corner while the program is struggling through all the datafiles? We won't be using
the output file for a bit, but it was just easier to get those variables in place now.)

Create a function as follows....

function TDD42f1.ReadFromByteFile(liStrt:longint):string;
begin
ReadFromByteFile:='faked ReadFromByteFile';
end;
Put....

function ReadFromByteFile(liStrt:longint):string;
... in the TDD42f1 class definition, just before the word "public"

Revise DoItClick to make it....

begin
assignfile(dfIn,'DemoData/IBM.txt');
reset(dfIn);
boDFInOpen:=true;
sTmp:=ReadFromByteFile(1);
closefile(dfIn);
boDFInOpen:=false;
laTmp.caption:=sTmp;
end;

http://sheepdogguides.com/dt4h.htm (3 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

... and get that much "working". (It won't actually read from the file yet, but get the typos out of that much first!)

Click on your form, go to the Object inspector (by pressing F11, or other way), set the OnClose event handler to....

if boDFInOpen=true then closefile(dfIn);


This would be a good time, if you are inclined, to give yourself a "Quit" button which has....

application.terminate;
... for its OnClick event handler.

Time to read some data


Now.. let's actually read some data from the file. If you had small files, or if you only wanted to read things near the start of a
file, you could do things much more simply. Sadly, I have big files, and will typically want to read things from near their end.
To accomodate those needs, modify the ReadFromByteFile function to create the following:

function TDD42f1.ReadFromByteFile(liStrt:longint):string;
begin
sTmp:='';
repeat
seek(dfIn,liStrt);(*Move file's pointer to a place in file*)
read(dfIn,bTmp);
sTmp:=chr(bTmp)+sTmp;
dec(liStrt);
until ((bTmp=10)or(bTmp=13)or(liStrt=-1));
if liStrt>-1 then sTmp:=copy(sTmp,2,length(sTmp)-1);
result:=sTmp;
end;
... and add...

liTmp:=filesize(dfIn)-1;
sTmp:=ReadFromByteFile(liTmp);
... to buDoItClick, replacing the ... sTmp:=ReadFromByteFile(1); .. which was there previously.

Be sure your form is quite wide. If it isn't, you may think ReadFromByteFile is failing to read part of the line. Something else
to look out for: If your data file has a blank line at the end, or even just an extra "return", it will look as if "Do It" did nothing.

An aside: Using liTmp to keep track of where we are in the file made sense at this point in the programming. Later, the value
in liTmp was needed over a wider and wider scope, and it became quite badly exposed to inadvertant changes when you
thought the old value was no longer important. If it were not for the hassle of changing all of the program code AND the text
of this tutorial, I would have created and used a more meaningfully named variable to track our place in the file. Moral of the
story: Use variable named "Tmp" carefully. ("Tmp" or "Temp" for temporary. If you are ever doing work with temperatures,
use "Tture" for variables holding those values!)(Changing liTmp to liPlaceInFile within the Delphi... even if you don't want to
change all references to liTmp... is quite easy because Delphi is well written.)

Have data, must parse


Parse: Break record into separate fields.

So far, so good... I hope. You should by now have a program that will read the last line in a data file.

http://sheepdogguides.com/dt4h.htm (4 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

Next we're going to add a function to parse the data line that has been read. With care, we can put almost everything we need
to adapt the program for different data file format in just this and a few other procedures.

First put the following into your program just before the existing "type.. TDD42f1 = class(TForm).."

type
TParsed = record
sErr,sF1,sF2,sF3,sF4,sF5,sF6,sF7,sF8,sF9:string;
end;
You are creating a new data type which is just the right thing for the needs of this program.

Now, in the private declarations, add....

rtParsed:TParsed;
function ParseRecord(sTmp:string):TParsed;
... just before the existing "function ReadFromByteFile(liStrt:longint):string;..."

Just after the "{$R *.DFM}" after the word "implementation" add....

{$R+}

function TDD42f1.ParseRecord(sTmp:string):TParsed;
begin
ParseRecord.sF1:='in func';
end;
(The {$R+} has nothing to do with creating the new type, nor with ParseRecord, nor even with the {$R *.DFM}, but it is a
good idea, and this was an easy moment to mention it!)

In the buDoItClick procedure, just after the existing "boDFInOpen:=false;", add...

rtParsed:=ParseRecord(sTmp);
laTmp.caption:=rtParsed.sF1;
... (replacing the existing "laTmp.caption:=....")

Run the program again, click "Do it", and you should see "in func" appear in laTmp.

Add the following labels to the form. You don't have to do all of them if you see why not! laErr,
laF1,laF2,laF3,laF4,laF5,laF6,laF7,laF8,laF9

Change ParseRecord so that it says....

function TDD42f1.ParseRecord(sTmp:string):TParsed;
begin
ParseRecord.sErr:='no error reporting yet';
ParseRecord.sF1:='field 1';
ParseRecord.sF2:='field 2'; (*No need to do the others yet*)
end;
... and in buDoItClick, replace "laTmp.caption:=rtParsed.sF1;" with....

laErr.caption:=rtParsed.sErr;
laF1.caption:=rtParsed.sF1;
laF2.caption:=rtParsed.sF2;

http://sheepdogguides.com/dt4h.htm (5 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

Run the program again. Now clicking DoIt fills in some of the labels on the form, but only with the hard-coded text, so revise
ParseRecord to be....

function TDD42f1.ParseRecord(sTmp:string):TParsed;
begin
ParseRecord.sErr:='no error';
ParseRecord.sF1:='';
ParseRecord.sF2:='';
ParseRecord.sF3:='';
ParseRecord.sF4:='';
ParseRecord.sF5:='';
ParseRecord.sF6:='';
ParseRecord.sF7:='';
ParseRecord.sF8:='';
ParseRecord.sF9:='';
if length(sTmp)<9 then begin
ParseRecord.sErr:='String passed to ParseRecord was too short';
end (*no ; here*)
else begin
ParseRecord.sF1:=copy(sTmp,1,10);
sTmp:=copy(sTmp,12,length(sTmp)-12);
ParseRecord.sF2:=sTmp;
end;(*else*)
end;
We are relying on the first field always consisting of 10 characters, and on it being followed by a single tab character or space.
There is a single tab or space between the other fields in each record, too, and we could use that to break the string up.
However, that might be tedious, so a different approach will be used. Crude, but simple! But vulnerable to changes in the data
file format. (In fact, in the first edition of this program after the tutorial version was completed, this approach was abandoned.
In the new, better version, the record is assumed to be field/tab/field/tab/field/tab, etc. It worked, and was more robust.
Individual fields were validated against more strict format expectations.)

The next stage in programming this is to replace "ParseRecord.sF2:=sTmp;" with something that looks like a lot of typing.
However, with good use of copy and paste, it isn't as bad as it looks. The "if length(sTmp)=42..." arises because my data has
some fields in one format, others in the other. Sigh. (The field/tab/field/tab concept mentioned a moment ago made this
clumsyness unnecessary.) That's the bad news.. well part of it. The good news is that I'm not going to bother gathering the data
in the last three fields.

ParseRecord.sF2:=copy(sTmp,1,5);
sTmp:=copy(sTmp,7,length(sTmp)-7);
if length(sTmp)=42 then begin
ParseRecord.sF3:=copy(sTmp,1,5);
sTmp:=copy(sTmp,7,length(sTmp)-7);
ParseRecord.sF4:=copy(sTmp,1,5);
sTmp:=copy(sTmp,7,length(sTmp)-7);
ParseRecord.sF5:=copy(sTmp,1,5);
sTmp:=copy(sTmp,7,length(sTmp)-7);
end (*no ; here*)
else begin
end;(*else*)
end;(*else*)
end; (*Of ParseRecord*)
... and in buDoItClick, expand the obvious section thus....

laErr.caption:=rtParsed.sErr;

http://sheepdogguides.com/dt4h.htm (6 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

laF1.caption:=rtParsed.sF1;
laF2.caption:=rtParsed.sF2;
laF3.caption:=rtParsed.sF3;
laF4.caption:=rtParsed.sF4;
laF5.caption:=rtParsed.sF5;
laF6.caption:=rtParsed.sF6;
laF7.caption:=rtParsed.sF7;
laF8.caption:=rtParsed.sF8;
laF9.caption:=rtParsed.sF9;
"What," you may be asking, "was the other bit of bad news?". The 6th field can be of varialble length. At this point in the
program, we've nibbled off of sTmp all of the data we've moved to fields. Each time, so far, we've known how many bytes
long the field will be. (In fact, this assumption proved wrong, but you can stick with it for the purposes of the tutorial.) Not so
for the 6th field. We have to look for the next tab or space... and we're going to assume it is a tab... and chop the field off that
way. Not too hard, actually... it just looks scary. Just before the "end; (*Of ParseRecord*)" in what we have above, add....

bTmp:=pos(chr(9),sTmp);(*chr(9) is "tab"*)
ParseRecord.sF6:=copy(sTmp,1,bTmp-1);

Going loopy
Onward! Now we're going to add the programming that will make the program search backwards through the data file a record
at a time until either it finds the day it has been told to look for, or it finds that there is no record for that date in the file.

While we "have" the date in ParseRecord.sF1, it is held as a string... not good for comparing to a target date. For that matter,
we don't (yet!) have a target date available to the program. Add declarations for the following variables, just after the
declaration "rtParsed:TParsed;"...

dtTmp,dtTarget:TDateTime;
bTarMo,bTarDa,bDOW:byte;
liTarYr:longint;
... and add the following to buDoItClick, just after "rtParsed:=ParseRecord(sTmp);"....

bTarMo:=10;
bTarDa:=31;
liTarYr:=2003;
dtTarget:=encodedate(liTarYr,bTarMo,bTarDa);
sTmp:=rtParsed.sF1;
dtTmp:=encodeDate(strtoint(copy(sTmp,7,4)),
strtoint(copy(sTmp,1,2)),
strtoint(copy(sTmp,4,2)));
if dtTmp=dtTarget then laTmp.caption:='Date in record matches target' (*no ; here*)
else laTmp.caption:='Date in record does NOT match target';
The above gives a nice example of starting small and building. The very crude entry of the target date will (obviously?) be
replaced by more elegant and useful programming, but it serves at this stage to work while we develop other aspects of the
program. Also, before the program is revised to loop through records to find the one we want, setting the target date will be
moved elsewhere. We'll do that now.

Create a listbox on your form. Call it lbMonths. Populate the "items" stringlist with Jan, Feb, Mar, Apr, etc (one per line).
Adjust the size of the control so that all twelve months show.

Create an OnCreate event handler for the form with the following in it...

http://sheepdogguides.com/dt4h.htm (7 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

lbMonths.ItemIndex:=9;(*N.B. Set to 0 for January*)


Change the "bTarMo:=10;" in buDoItClick to...

bTarMo:=lbMonths.ItemIndex+1;
(The "+1" is needed as "Jan" is the "zeroth" item in the list, Feb the "first", etc)

Move...

bTarDa:=31;
liTarYr:=2003;
from buDoItClick to the form's OnCreate handler, for now.

A Snag!
ARGHH!!! Did you notice the flaw in my design? I didn't... and it took a while to pin down. I'm happy to say that it isn't going
to be a problem in the final version of the program.

As one always should, I was testing the program after this latest advance. Seemed to be working okay.... but once in a while I
got a "EConvertError" message, "Invalid arguement to EncodeDate" when I clicked DoIt after changing the month for the
target date. It seemed... at first... that odd numbered dates worked okay, even numbered dates not. June always misbehaved.
Eventually I realised I was asking for "June 31st" to be converted. Easy enough to understand... when you finally hit the right
question to ask!

We won't fix this problem for the moment. It won't exist in the final version of this.

Do you have a date?....


Next we'll turn to making the program search for the record for a particular date.

The first thing we need to do is to revise "function ReadFromByteFile( liStrt:longint):string;". Add "var" to the declaration as
follows...

function ReadFromByteFile(var liStrt:longint):string;


... and add var to the implementation header in the same place. Your program should still run after you add "var" in those two
places.

Add boDone to the list of global boolean variables.

Revise buDoItOnClick as follows. Most of the ingredients come from what we had before, but they've been rearranged.

procedure TDD42f1.buDoItClick(Sender: TObject);


begin
assignfile(dfIn,'DemoData/IBM.txt');
reset(dfIn);
boDFInOpen:=true;
liTmp:=filesize(dfIn)-1;
bTarMo:=lbMonths.ItemIndex+1;
dtTarget:=encodedate(liTarYr,bTarMo,bTarDa);
boDone:=false;
repeat

http://sheepdogguides.com/dt4h.htm (8 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

sTmp:=ReadFromByteFile(liTmp);
rtParsed:=ParseRecord(sTmp);
if rtParsed.sErr='no error' then begin (*1*)
sTmp:=rtParsed.sF1;
dtTmp:=encodeDate(strtoint(copy(sTmp,7,4)),
strtoint(copy(sTmp,1,2)),
strtoint(copy(sTmp,4,2)));
if dtTmp=dtTarget then begin (*2*)
laTmp.caption:='Date in record matches target';
boDone:=true;
end (*2 no ; here*)
else begin(*2*)
laTmp.caption:='Record with that date not found in dataset.';
if dtTmp'String passed to ParseRecord was too short'
then boDone:=true;
end; (*else 1*)
if liTmp=-1 then boDone:=true;
until boDone;
closefile(dfIn);
boDFInOpen:=false;
laErr.caption:=rtParsed.sErr;
laF1.caption:=rtParsed.sF1;
laF2.caption:=rtParsed.sF2;
laF3.caption:=rtParsed.sF3;
laF4.caption:=rtParsed.sF4;
laF5.caption:=rtParsed.sF5;
laF6.caption:=rtParsed.sF6;
laF7.caption:=rtParsed.sF7;
laF8.caption:=rtParsed.sF8;
laF9.caption:=rtParsed.sF9;
end;
I'm not convinced that the code above is the best I've ever written. I'm not even confident it will work in every case... but it
works in a number of cases I've tried, so we'll move on again.

Scanning multiple files


The next stop is a way to scan all of the files in a given folder, fetching the price for each stock on the target date. Sometimes it
is worth expressing your intentions in pseudocode. In this instance, we want something like....

set up any needed starting conditions


.. including:
....Get list of files
....Set "TooBigLastFile" to the number of files in the folder
....Set "this file" to 0 ("This file" being a number for which file we've got to)
repeat
check "this file" for datum
if found then
deal with datum
else deal with failure
add 1 to "this file"
until "this file">="TooBigLastFile"
The code that will derive from the above will be the new buDoItClick handler. Before we start building that, we need to move
all of what we currently have in the current buDoItClick handler to a new procedure called ProcessOneInputFile. Don't test

http://sheepdogguides.com/dt4h.htm (9 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

what you are going to do next until you get down to "Now you can test the latest changes". To do what we need....

Add...

procedure ProcessOneInputFile;
in the private declarations just after "function ReadFromByteFile(var liStrt:longint):string;"

Change the header "procedure TDD42f1.buDoItClick(Sender: TObject);" to....

procedure TDD42f1.ProcessOneInputFile;
... and, just before "procedure TDD42f1.ProcessOneInputFile;", insert....

procedure TDD42f1.buDoItClick(Sender: TObject);


begin
ProcessOneInputFile
end;
(It is a little dangerous to fool with the declarations and descriptions of event handlers "by hand" like this, but you can get
away with what we've done if you're careful!) Now you can test the latest changes. the overall effect of the program will be the
same, but the parts of the job are broken up differently.

Because it compartmentalises aspects of the work, which will be a big help if ever you go back to revise the code, we're going
to make ProcessOneInputFile a function. You may well need to revise the code. The supplier of the data may change its
format, for a start. The function is going to return a string which tells you there was no error within ProcessOneInputFile (or
describes the error) and a number: the price for that company on the target date. As we did with ParseRecord, we are going to
create a record (term used in slightly different sense) of our own to "wrap" the two data into a single "datum", so that we can
have ProcessOneInputFile as a simple function. The alternative is to pass information from ProcessOneInputFile in global
variables, which is a (widely used) Bad Idea which seems harmless enough at the time, but often makes tracking down bugs
tedious.

Regarding the term "record": If crops up in this tutorial in two senses. Within a database, it means a row of a table. In the work
we are doing, the files with prices for the different stocks are database tables. One line from any of those files is one "record"
in the database sense.

In Delphi (and the underlying Pascal), the term "record" is used when declaring a new data type. We've already used it this
way in this tutorial when we created the data type "TParsed". If you go to your Delphi sourcecode, put your insertion point
somewhere in the word "record", do ctrl-F!, and select the entry from OBPASCAL.HLP, you can read more in the Object
Pascal Language Reference.

So much for grand theory. To "just do it"... put the following into your program just before "type TParsed = record"...

type
TFromInput = record
sErr:string;
rValue:real;
end;
Just after "liTarYr:longint;", add....

rtFrmIP:TFromInput
(Be sure that much still runs) Change "procedure ProcessOneInputFile;" to...

function ProcessOneInputFile:TFromInput;
... and change "procedure TDD42f1.ProcessOneInputFile;" to...

http://sheepdogguides.com/dt4h.htm (10 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

function TDD42f1.ProcessOneInputFile:TFromInput;
... and make buDoItClick be....

procedure TDD42f1.buDoItClick(Sender: TObject);


begin
rtFrmIP:=ProcessOneInputFile;
end;

See that still runs.

Just before the "end;" at the end of ProcessOneInputFile, add...

ProcessOneInputFile.sErr:=rtParsed.sErr;
ProcessOneInputFile.rValue:=42.42;

See that still runs. One it does, add...

liErr:longint;
rTmp:real;
... to the program's global variables, add two labels to the form... laFromFile1 laFromFile2

and replace the original two ProcessOneInputFile lines with....

ProcessOneInputFile.sErr:=rtParsed.sErr;
ProcessOneInputFile.rValue:=999.999;(*Or any other rogue value you want.
Signals "not valid datum"*)
if rtParsed.sErr='no error' then begin
val(rtParsed.sF3,rTmp,liErr);
if liErr=0 then begin
ProcessOneInputFile.rValue:=rTmp;
end (*no ; here*)
else begin
ProcessOneInputFile.rValue:=liErr;
ProcessOneInputFile.sErr:='Error found during convert to real. '+
'Error has been passed back in ProcessOneInputFile.rValue';
end(*else*)
end;
(N.B.: The "end" you see above is IN ADDITION to the function's final "end") ... and revise buDoItClick, making it....

procedure TDD42f1.buDoItClick(Sender: TObject);


begin
rtFrmIP:=ProcessOneInputFile;
laFromFile1.caption:=rtFromIP.sErr;
laFromFile2.caption:=floattostr(rtFromIP.rValue);

Where have we been?


Set out here as it has been, it may seem that the road to the final product is long and tortuous. Not really... compared to trying
to write the whole thing in one gargantuan effort with all features added in a single push. What this tutorial illustrates, among

http://sheepdogguides.com/dt4h.htm (11 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

other things, is incremental development. We're getting to our goal one step at a time. Try to take two steps, and you'll waste a
lot of time getting to the bottom of which bit isn't working so that you can fix it.

The simple life:


Repeat....
...Change one thing.
...Repeat
.........See if program still works.
........If not, try fixing the one thing you fiddled with
........Until what you've done works
...Until the whole job is done.

Where are we going?


That little homily aside, we return to the joys of getting the project completed. Previously, I presented the pseudocode for what
needs to be done. We have already developed the essentials at the heart of that. Now we need to work up the details.

Almost everything before the repeat section of the pseudocode will be done outside of "DoIt".

The list of files will be held in a FileListBox, a useful built-in component. Put one on the form. (It can be found on the System
tab of the components palette, third item.) Call it fbFiles. Set TabStop false. You might eventually want to set its visible
property to false. The mask value can be set to *.txt for our needs, as all of the data files have the .txt extension.

Before we can collect the files, we need to designate which folder they are in. Declare a string variable sFilesPath. In the
form's OnCreate give it an initial value. If your data files are in C:\Delphi\DD42\DemoData, then set sFilesPath equal to
'C:\Delphi\DD42\DemoData'. We can get clever later about being able to designate different folders via the ini file, or
interactively.

Declare a variable called called liLimitToLoop. (We'll be using this to hold what was referred to as "TooBigLastFile" in the
pseudocode. Just after the line setting sFilesPath, add....

liLimitToLoop:=fbFiles.items.count+1;

Now we're set to return to "DoIt" and build it up.

I'll continue the description in the same style as I've used so far, but don't bother trying to enter the new material as the
description unfolds.... I'll give you the complete new DoIt in a moment.

For the moment, Put (* and *) around the three lines we have in that so far. Create a local variable called liLoopCounter. (This
is for what was called "this file" in the pseudocode.) Create an approximation of the final program, using commented material
to stand in for incomplete things, and showmessage statements to convey the program's progress.

That should bring you to....

procedure TDD42f1.buDoItClick(Sender: TObject);


var liLoopCounter:longint;
begin
liLoopCounter:=0;
repeat
sTmp:=fbFiles.items[liLoopCounter];
showmessage('Here will go check of file '+sTmp);
(*rtFrmIP:=ProcessOneInputFile;
laFromFile1.caption:=rtFromIP.sErr;

http://sheepdogguides.com/dt4h.htm (12 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

laFromFile2.caption:=floattostr(rtFromIP.rValue);*)
if true{datum found} then
{deal with datum}
else {deal with failure};
inc(liLoopCounter);
until liLoopCounter>=liLimitToLoop;
end;

Now that we're scanning the right files, so we need to go back to ProcessOneInputFile and modify it to accept a filename when
called. Add "(sFilePathAndName:string)" in the two places it is needed, replace 'DemoData/IBM.txt' within
ProcessOneInputDevice with sFilePathAndName, and then be sure program will still run. It won't do anything interesting yet,
but we can catch some typos.

Finally, make the changes in DoIt to create....

procedure TDD42f1.buDoItClick(Sender: TObject);


var liLoopCounter:longint;
sCoName:string;
begin
liLoopCounter:=0;
repeat
sTmp:=fbFiles.items[liLoopCounter];
sCoName:=copy(sTmp,1,pos('.',sTmp)-1);
showmessage('Here will go check of file '+sTmp);
rtFrmIP:=ProcessOneInputFile(sFilesPath+'\'+sTmp);
laFromFile1.caption:=rtFrmIP.sErr;
laFromFile2.caption:=floattostr(rtFrmIP.rValue);
if true{datum found} then
{deal with datum}
else {deal with failure};
inc(liLoopCounter);
until liLoopCounter>=liLimitToLoop;
end;
That will give us something that goes to the data files and fetches prices. Only a little more is now needed to process errors
which might arise, and send the collected data to an output file. Make the lines before and including the "until "....

if rtFrmIP.sErr='no error' then begin


showmessage('On the date requested, '+sCoName+'''s close was '+
floattostr(rtFrmIP.rValue));
end (* no ; here*)
else showmessage ('Error encountered when looking at '+sCoName);
inc(liLoopCounter);
until liLoopCounter>=liLimitToLoop;
You can take out the earlier "showmessage('Here will go check of file '+sTmp);" at this stage.

And finally...
All that's left to create a program that does the core job of what we set out to do is....

Open the output file. It will use the handle dfOut Put....

http://sheepdogguides.com/dt4h.htm (13 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files

writeln(dfOut,sCoName+' '+floattostr(rtFrmIP.rValue));
...in place of "showmessage('On the date requested, '+sCoName+'''s close was '+floattostr(rtFrmIP.rValue));" Arrange to close
dfOut in the relevant places.

To open the file crudely, just put the following into the early part of DoIt. It will cause existing DD42OP.txt files to be
overwritten without warning.. Eventually, a default output filename will be fetched from the ini file, if a file exists of that name
permission to overwrite will be sought, it will be possible to change the name. For now, the following works, if crudely...

assignfile(dfOut,'C:\My Documents\DD42OP.txt');
rewrite(dfOut);
boDFOutOpen:=true;
You should also put boDFOutOpen:=false; in the form's OnCreate handler.

To arrange the necessary closing, put...

if boDFOutOpen=true then closefile (dfOut);


in the FormClose procedure, and...

if boDFOutOpen=true then closefile (dfOut);


boDFOutOpen:=false;
... just before the "end" at the end of "DoIt"

Concluding remarks
Well... there you have... something! As I've got further into this, it has proven more and more difficult to convey sensibly the
changes and tweaks needed to evolve the program from the crude basic version into something with the smooth edges that a
program you'd enjoy using every day would have.

I will do more work on this program later, and, maybe release the sourcecode of that more polished version... but there are a
number of other projects clamouring for attention before then... not least getting this text onto the web for you! You'd be
surprised how much work that entails, even once the basic text is done. (About 90 minutes, to date, as I work through the file.
Much more to do.. the text editing is only part of the job.) In the meantime, I hope what IS in this tutorial was worth the time
you spent working through it!

When the program goes from delvelopment to real-life use, the date for which data is sought will default to the first
non-weekend day before the current day. The built in functions "now" and "dayofweek" will make the programming quite
simple.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search The search engine is not intelligent. It merely seeks the words you specify. It will not do
anything sensible with "What does the 'could not compile' error mean?" It will just return references to pages with "what",
"does", "could", "not".... etc.
Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

http://sheepdogguides.com/dt4h.htm (14 of 15) [1/28/2005 3:47:05 PM]


Delphi: Extracting data from records in text files
Ad from page's editor: Yes.. I do enjoy compiling these things for you... 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 an MS-DOS or
Windows 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

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi, and they
provide promotional services, too. Click the "Help get this site publicity" link above for more information.
{end}

http://sheepdogguides.com/dt4h.htm (15 of 15) [1/28/2005 3:47:05 PM]


Delphi: Reading joysticks and using Windows messages

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi: Reading joysticks and using Windows messages


(And making a stopwatch along the way)

This has good information, and a search button at the bottom of the page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

This tutorial is based on information found at The Unofficial Delphi Developers FAQ... thank you, UDDF! I've worked up
his information on how to read a joystick into a program which turns your computer into a stopwatch. Besides the joystick
specific information, the program also illustrates how to respond to Windows messages coming from elsewhere in the
computer. And finally, the program has, if I do say so myself, quite an elegant interface, slipping neatly between states. The
tutorial comes complete with sourcecode.

This tutorial is a more advanced version of ideas first explored in my Level 3 tutorial on joysticks. The program developed in
that tutorial is similar to the one developed in this tutorial. However, in the simpler program, a timer repeatedly "went and
looked at" the joysticks. Easy to understand, but not efficient. In this tutorial, a component of Window's mmSystem unit is
configured to send a message to our application when a fire button is pressed, our program then deals with that. We are using
event handlers to respond when there is a need. This is accomplished with calls of joyGetDevCaps, joySetCapture, and
joyReleaseCapture.

This tutorial is not presented in the unusual format of these tutorials. The main text of the tutorial is included, as a text file, in
the self extracting zip (SEZ) archive which also contains the application's source code. Click here to download that archive.
Save the SEZ on your disc. You can go offline at that point. Double click on the SEZ. It was created with WinZip, and will
allow you to select a destination folder for the material to be unzipped.

Here is some of what I worked from in preparing the tutorials....

Adapted from: http://cpcug.org/user/clemenzi/technical/Languages/Joysticks.htm#Delphi

A) Windows itself, regardless how you write programs for it, provides two ways to read the joystick, an input only device:

winmm.dll - 10 functions including joyGetPos and joyGetDevCaps.


DirectX

B) Delphi 5 does not supply joystick support via the vcl.

Windows API support is defined in rtl\win\mmsystem.pas (At least some of what follows applies even to Delphi 2, but none
of it, I think to Delphi 1)

The following code snippet is from The Unofficial Delphi Developers FAQ.

uses
... , mmSystem;
var

http://sheepdogguides.com/dt4i.htm (1 of 3) [1/28/2005 3:47:08 PM]


Delphi: Reading joysticks and using Windows messages

myjoy: tjoyinfo;
begin
joygetpos(joystickid1,@myjoy);
trackbar1.position := myjoy.wypos;
trackbar2.position := myjoy.wxpos;
radiobutton1.checked := (myjoy.wbuttons and joy_button1)>0;
radiobutton2.checked := (myjoy.wbuttons and joy_button2)>0;
end;
This snippet is pretty good, but only one radio button can be set at a time. Also note that the position range is 0 to 65,535
when calibrated. Be sure to set the trackbar max values appropriately. (On my test system, the center position is 38,500 x
26,900.)

Using a Message Handler

mmsystem.pas does a pretty good job of encapsulating the Windows joystick interface - all the functions in the Windows
SDK Help file appear to be available. The only thing missing is a record definition so that you can use a message handler.
This is the one I use.

type
TMMJoyStick = packed record
Msg: Cardinal; // The message ID
Buttons: Longint; // The wParam
XPos: word; // The lParam
YPos: word;
Result: Longint;
end;

There is one interesting inconsistency:

The x and y positions are passed to a message handler as unsigned words (16 bits), but the associated Max and Min values in
TJoyCaps and the x/y values in TJoyInfo are 32 bits (UINT).

The following code implements a message handler.

procedure MMJOY1BUTTONDOWN (var LocMessage: TMMJoyStick); message MM_JOY1BUTTONDOWN;


procedure MMJOY1BUTTONUP (var LocMessage: TMMJoyStick); message MM_JOY1BUTTONUP;
procedure MMJOY1MOVE (var LocMessage: TMMJoyStick); message MM_JOY1MOVE; //
ButtonDown and Move are not shown, they just call ButtonUp
procedure TForm1.MMJOY1BUTTONUP (var LocMessage: TMMJoyStick);
begin
trackbar1.position := LocMessage.ypos;
trackbar2.position := LocMessage.xpos;
Edit1.Text := IntToStr(LocMessage.ypos); // so you can see
Edit2.Text := IntToStr(LocMessage.xpos); // what is happening
CheckBox1.checked := (LocMessage.Buttons and joy_button1)>0;
CheckBox2.checked := (LocMessage.Buttons and joy_button2)>0;
end; procedure TForm1.FormCreate(Sender: TObject);
var
myJoyCaps: TJoyCaps;
begin
joyGetDevCaps(joystickid1,@myJoyCaps, sizeof(myJoyCaps)); // for test
joySetCapture(self.Handle, joystickid1, 100, true);
end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

http://sheepdogguides.com/dt4i.htm (2 of 3) [1/28/2005 3:47:08 PM]


Delphi: Reading joysticks and using Windows messages

begin
joyReleaseCapture(joystickid1);
end;

(Here ends material quoted from other sources)

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar Top 200
Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay
my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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


To email this page's editor, Tom Boyd....
Editor's email address. Comments appreciated!

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi, and they
provide promotional services, too. Click the "Help get this site publicity" link above for more information.

http://sheepdogguides.com/dt4i.htm (3 of 3) [1/28/2005 3:47:08 PM]


MicroLan and 1-Wire and Delphi Programming

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

MicroLan and 1-Wire and Delphi


Programming
(and some information on hardware issues)
The distribution across my web pages of my material about the MicroLan (aka "1-Wire") has become
somewhat confused... sorry!
If you dig successfully, you'll find information to help you use the product. There is information is about
how to write Delphi programs for that hardware. Source code is provided. There are general overview
articles, and articles with specifics of how to access particular functions of individual chips.
There is also information about using the MicroLan for sense and control work, in particular information
about sensing and recording the weather using various with MircoLan based devices products.
MicroLan and 1-Wire are registered trademarks of Dallas Semiconductor, aka Dalsemi, now part of
Dallas/Maxim. I have no connection with them apart from being a happy user of their products. My use
of the chips is primarily in weather logging applications, though they can be used for many things; a
hamster's night-time wheel use was monitored with MicroLan chips, for instance.
There are more notes at the bottom of the page about other offerings, my editorial philosophy, how to
email me, and a search engine to help you find things.
Here begins what Mr Reagan called "The Beef":
(Actually, it was Mr. Mondale, challenging Mr. Reagan. So why didn't one of you, faithful readers,
challenge me on this point before I added this note? Mr. Mondale was riding the coat tails of an
advertising campaign by Wendy's. While we're into trivia, did you know that Wendy was the real life
daughter of the man who founded the chain?)
......."The Beef"................

While all of the code "works", some examples are better than others, hence the "star ratings". Unless you
need to use a particular chip, start with the examples with more stars.

Before you try to write code... a word about data types.

Introduction to Dallas MicroLan... Source code for accessing the Dallas MicroLan, aka 1-Wire system,
as used in iButtons Dallas is now part of Maxim. Has specifics relating to DS2405 and DS1820 or
DS1920. (The DS1920 is just an 1820 in an enclosure.) While this only deserves one star as far as the
sophistication of the code is concerned, it has important general introductory material... you should
probably give it a look.

http://sheepdogguides.com/dst1main.htm (1 of 4) [1/28/2005 3:47:12 PM]


MicroLan and 1-Wire and Delphi Programming

Dallas MicroLan Counter, DS2423, 2 star... Source code for accessing a DS2423 counter.
.. or see...
Accessing the counter in a DS2422 or DS2423 (Source code available.) I seem to have written two
tutorials on the same subject, both working from the same example program!

Dallas MicroLan ADC, DS2450, 2 star... Source code of almost working software to read 4 channel
analog to digital converter. If you know the Dallas chips well, I'd be very grateful if you could look at
this, even if you're not a Delphi programmer, to see if you can spot my mistake! Channels A, C and D
read properly, but not channel B! Yes... I've checked the signal being sent to channel B.

Dallas MicroLan Wonder Chip: DS2438, 4 star... Information and source code. Dallas designed this chip
to monitor rechargeable batteries, but you and I can use it for its ADC (one channel, wide range) and
high resolution temperature sensing. This program is the best MicroLan access demo I've written as of
8/30. While earlier programs work most of the time, they may include errors that I was wise enough
NOT to make when I wrote this code. This program uses an approach different from that in the two-star
programs on offer. The two-star programs conform more closely to the Dallas demos, but I think my
approach to robustness is better... and your code does need to be robust! The MicroLan is, in general,
great, but instead of designing something that never fails, the Dallas team gave us a product that fails
from time to time... but does so gracefully. I have a weather monitoring application running. At the
moment, there have been 12,000 cycles since the last system boot. The MicroLan has "failed" to reply
correctly three times. Not a bad percentage of right answers, but you do need to write your software to
handle the occasional bad read.

Dallas MicroLan PIO Chip: DS2408, 4 star... Information, help file and source code. The 2408 is an 8 bit
addressable switch according to Dallas. I think of it as a parallel port chip: There are 8 pins on it, and
each can be an input from or output to devices in the "outside world". This software derives from the
program for the DS2438, see the comments about that in the previous paragraph.

AAG Digital I/O using PIO Chip: TAI 8558, DS2408, 4 star... AAG is a supplier of 1-Wire related
hardware with quite a reputation for good customer support. They did a nice 4 bits in, 4 bits out digital
i/o card based on the DS2408. The inputs are opto-isolator protected (AC or DC input accepted), and the
outputs are via relays (Common, NormallyOpen and NormallyClosed contacts available via screw
terminal.) The link at the start of this paragraph will connect you to a .pdf document discussing using a
TAI8558 for a burglar alarm and heating control. The application is merely an illustration to show you
about the device. You can download the relevant Delphi sourcecode by clicking here, and the exe file is
available here. The latter two files are self extracting archives which will merely install some files, not
interfere with your registry, etc.

Here ends da beef:

Editorial Philosophy

http://sheepdogguides.com/dst1main.htm (2 of 4) [1/28/2005 3:47:12 PM]


MicroLan and 1-Wire and Delphi Programming

I dislike 'fancy' websites with more concern for a flashy appearance than for good content. For a pretty
picture, I can go to an art gallery. Of course, an attractive site WITH content deserves praise... as long as
that pretty face doesn't cost download time. In any case....
<PS.... I wrote the following before getting into the fine points of what I intended. Implementation has
proved to be a pain, and I'm experimenting with different solutions. You'll find some tutorials are heavily
infested with HTML code. Is this a problem? You can still save the pages from a browser, and re-load
them from your hard-disc later, off-line. OpenOffice takes HTML in its stride. With WordPerfect, you
can load the .htm file, select all, copy to clipboard, start a new WordPerfect document, then paste in the
text, mostly intact and cleaned of HTML. (Hard to describe, easy to do.)>
You should be able to read the tutorials on-line without difficulty. However, you should ALSO find it
easy to capture them for off line use, including editing for your own purposes. The following should
work. I would suggest that you create a folder for the tutorials so that you can retain my filenames with
no risk of clashes:
On-line, use your browser to view the tutorial you want to capture.
Use File|Save As... to save the web-page to your disc. At this point you can log off, or visit other pages,
perhaps saving them, too.
When you have logged off, start Notepad (or Wordpad, or anything you like, but then you're on your own
<g>). Load the file you saved. Turn word-wrap on. (Notepad: Edit|Word-wrap.)
Snip off the html header and footer. <In one 'solution', you will also have to remove all <BR>. and
<BR>s from the text (Wordpad can to this.) Sorry... working on it!>
Re-save... you should now have the tutorial in a nice, tidy, uncomplicated text file.
________
Filenames: I've tried to be organized: Names start PT or DT for Pascal/ Delphi Tutorial. Next is a digit,
for the level, then I've used letters one after the other, e.g. DT1a, DT1b, DT1c. The letter doesn't mean
much... it just shows when I got around to that particular topic! With the MicroLan stuff, that is getting a
little confused. Files about MicroLan created after 8/03 may be prefixed DST, but that is not all of the
MicroLan stuff.
Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search BEWARE: There is stuff at my other two sites that this search won't
reveal. Go to either site (see links below) and use that site's FreeFind search button.
In addition to the tutorials for which this page serves as Table of Contents, I have other sites with
material you might find useful.....

Sheepdog Software homepage.


My Arunet homepage.

http://sheepdogguides.com/dst1main.htm (3 of 4) [1/28/2005 3:47:12 PM]


MicroLan and 1-Wire and Delphi Programming

... and some links to specific pages within them you might want....

Main index to MicroLan stuff.


Some pages for programmers.
Using the parallel port with programs written in Delphi.

Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at
Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200
Delphi, and they provide promotional services, too. Click the "Help get this site publicity" link above for
more information.

http://sheepdogguides.com/dst1main.htm (4 of 4) [1/28/2005 3:47:12 PM]


Delphi: A program from start to finish

HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi: Development of a Program


This has good information, and a search button at the bottom of the page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

Welcome!
This tutorial is a chance to sit at my elbow as I put a program together. It will not contain as much "now type
this..." information as a typical tutorial from this series. Not every detail will be explained for you. Several topics
on which this is based are discussed in more detail in other tutorials... used the search button, maybe? (E.g. File
handling, graphics programming.)

You can obtain the sourcecode....

....by clicking on download source code That will transfer a file called GP2SU.exe to your machine. Virus check it,
and then double click on it. It is a WinZip8 created self-extracting archive. The program was written for Delphi 1,
but it will load into Delphi 2 (and, I would guess, higher Delphis) for study. (Filename derived as follows:
GP2SU:Graphics Program, number 2, Set Up file)

The tutorial is, at present, in a "first draft" state. After three days, frankly, I'm sick of it! I'll try to come back to it
another time. For now, apologies for the typos, etc. I'll refund what you've paid me for it to anyone submitting their
receipt.

The program is to display data collected about access to a storeroom with a computer connected to its door logging
when the door is open. Note: This program only looks at a data file created by the computer connected to the door.
This program doesn't do any of the data collection.

The data file is in simple ASCII. The following is the start of a typical file. the REM: statement is hand entered,
and all such will be ignored by the graphing program. The other statements are computer generated. Eventually, all
will contribute to the graphic display.

REM: Log file restarted mon 29 July 02

LA16, ver 29/7/2002 restarted at 17:21 on (DMY) 29-7-2002


Switch was open.
Closed: 17:21 on (DMY) 29-7-2002
Opened: 17:23 on (DMY) 29-7-2002
Closed: 17:23 on (DMY) 29-7-2002
Opened: 17:23 on (DMY) 29-7-2002
Closed: 17:23 on (DMY) 29-7-2002

http://sheepdogguides.com/dt5d.htm (1 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

LA16, ver 29/7/2002 restarted at 17:24 on (DMY) 29-7-2002


Switch was closed.
Opened: 17:24 on (DMY) 29-7-2002
Closed: 17:25 on (DMY) 29-7-2002
Opened: 17:25 on (DMY) 29-7-2002
Closed: 17:25 on (DMY) 29-7-2002

LA16, ver 29/7/2002 restarted at 17:27 on (DMY) 29-7-2002


Switch was open.
Closed: 17:27 on (DMY) 29-7-2002
Opened: 17:27 on (DMY) 29-7-2002
Closed: 17:27 on (DMY) 29-7-2002
Opened: 17:27 on (DMY) 29-7-2002
Closed: 17:27 on (DMY) 29-7-2002
Opened: 17:28 on (DMY) 29-7-2002
Closed: 17:28 on (DMY) 29-7-2002

LA16, ver 29/7/2002 restarted at 17:46 on (DMY) 29-7-2002


Switch was closed.

LA16, ver 29/7/2002 restarted at 17:46 on (DMY) 29-7-2002


Switch was closed.
--------day changed at 0:0 on (DMY) 30-7-2002
--------day changed at 0:0 on (DMY) 31-7-2002

LA16, ver 29/7/2002 restarted at 8:17 on (DMY) 31-7-2002


Switch was closed.
--------day changed at 0:0 on (DMY) 1-8-2002
--------day changed at 0:0 on (DMY) 2-8-2002
--------day changed at 0:0 on (DMY) 3-8-2002
Opened: 19:57 on (DMY) 3-8-2002
Closed: 20:01 on (DMY) 3-8-2002
--------day changed at 0:0 on (DMY) 4-8-2002
The "----day changed..." records are present to confirm at least once a day that the computer is still running, i.e. not
crashed through power failure or Windows "feature".

Initially, the program will plot a "-" for each "day changed", a "^" for each "opened", a "v" for each "closed", a ">"
for each "restarted". It would be nice if the graph had lines to show when we can presume a state for a given
period, i.e. a "closed" line for all of 2 August 02... but that would require a much more sophisticated program. Our
initial plans allow each record (line) of the log file to be processed in isolation, with no need to "connect" events.

If there were no "open" or "close" events, the graph would look a little like...

-___-___-___-___-___-___-___

-___-___-___-___-___-___-___

-___-___-___-___-___-___-___

http://sheepdogguides.com/dt5d.htm (2 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

... each line is the record for a week. The bottom line is the most recent week. The hyphens in the above are the
"day changed" reports.

In broad terms, the program will consist of the following:

A) Prepare a 'blank page' of graph paper. During this process, various values needed subsequently in the program
will be calculated and stored for future reference. (Details later.) (In "FormCreate" part of program.)

B) Look for, and open if found, the file of data. If found, also determine first date, last date in file. Check the
format is right for this program. (In "CheckFile" part of program)

C) Ask user for the time period of interest, and from that and information obtained previously determine first and
last dates to be plotted. (Handled by edit box event handlers, with some help from "CheckFile".)

D) Read file from end to oldest record of interest. (I am writing the program to read backwards through the data
because I presume that it will be recent data that is most often requested. This approach avoids long reads forward
from the start of a file. (Part of "DoGraph" part of program.)

E)
Set boDone:=false;
Repeat (*1*)
Plot record;
bRecordType:=0; (*rogue for "Useless to us"*)
Repeat (*2*)
Try to read prior record, moving pointer back in process;
If no prior record, then boDone:=true;
Fill bRecordType;
If suitable recordtype, put records DateTime in dtTmp;
If not boDone then if record pre-dates period of interest, then boDone:=true;
Until bRecordType<>0 or boDone; (*2*)
Until boDone;(*1*)
Close file.
(All of E part of "DoGraph" part of program.)

Sounds simple enough... let's get started....

==========
(By the way: Beginners: I have a much clearer, much more detailed idea in my head of all of the above, and most
parts of it I have done before in other programs. You can never spend too much time planning in advance what a
program is going to do. I am pressing ahead thus a) because I have bad work discipline, b) to keep this readable.)

I'm calling the program GP2, and will first create a "shell" into which the various elements can be fitted.

The shell will have a form with an image created during the form's onCreate.

Eventually, there will be a way to specify which data file you want to look in. For now, it will look in a specific
file in the local folder when the user clicks on the "Chk File" button. The form will have labels to display the

http://sheepdogguides.com/dt5d.htm (3 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

earliest and latest data in the datafile.

Once the file has been opened and checked, the user will be able to alter the setting in some edit boxes for start and
end dates. (The dates of the period to be shown on the graph.) (Editing before the data file will not be possible
because there will be checks to see that there is data for the dates selected.) If you edit one of the dates, the
computer will show you what the other date will be. (This is going to be a pain, because each line of the graph will
start on Monday, so it won't be a simple "calculate the date 21 days forward (back)" for a three week graph. (As if
even that would be simple!) Once suitable dates are established, and the data file has been opened up, checked, a
"Do Graph" button will be enabled. Click the button, get the graph! (The setting of the graphing range is not
complete at the time this tutorial is being published... but parts of the above work!)

Note that the enabling of "Do Graph" is going to be complex, relying on two Booleans. This is because once the
datafile can be changed, provision must be made for situations where a user goes back and changes the data file
after specifying some dates. The Booleans will be boFileReady and boPlotDatesSet. (As the programming
progressed, I realised that these were not being used as much as I'd thought they would be.) Note that buDoGraph
and the dates-to-plot edit boxes start in the enabled=false state.

When I had completed the initial form design, and just a little of the program's coding, I saved what I had in the
folder "StateA", so have a look at that, if you want to see how the project began.

===
I'm going to start with the CheckFile part of the program. There's more detail on reading datafiles in my datafile
tutorial.

To make it easy to add a "Choose which file" option later, the name of the file to be opened will be in a variable,
sFileName.

All of the following were written to support parts of CheckFile, but they will be useful later in the program, too.
Ah, the joys of breaking things into general purpose procedures and functions! Note that some of them are quite
intolerant of the format of the records in the datafile. ReadLineForward, ReadLineBackwards, DecodeRecord,
GetNumberFromString, TimeStrToParts, DateStrToParts. Note that each was painstakingly de-bugged as it was
added to the program. One of a programmer's skills is finding ways to debug as bits are added, not in one
nightmare at the end when there are all sorts of untested things clashing with one another.

This portion of the program proved tedious, with a lot of string manipulation in order to transform dates and times
expressed as strings into dates and times held in word variables for day, month, year, hour, minute. Delphi's
EncodeTime and EncodeDate were useful for turning the date/time specifications into the internal code used in
Delphi for DateTimes. In that code, the day determines the whole number part of the DateTime value, and the hour
of the day determines the fractional part of the DateTime value. A few examples....

0.0 is midnight on Dec 30, 1899


0.5 is noon on Dec 30, 1899
36526 is midnight Jan 1, 2000
(N.B. Delphi 1 used a similar system, but day 0 was in year 0001.)

The Delphi way of storing DateTimes will make finding the right place on the DateTime axis of the graph easy.
You no longer have to worry about the number of days in September, nor where leap years fall.

Once the "Check (and do lots more with it)File" procedure was working, it made sense to at least get a rough

http://sheepdogguides.com/dt5d.htm (4 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

version of part "C" of the program working. That's the part that gets and checks the user's wishes as regards to the
range of dates to be plotted. At this stage, a start was made, using the edit boxes and their handlers. The job wasn't
finished at this point, as some of the "will these values work?" tests, and some of the automatic generation of the
other bound of the range could not be done until the "create blank sheet of graph paper" work is done. However, a
start was made, and some enabling/ disabling of the buDoGraph was programmed.

Features to check out include...

Use of one event handler to cover multiple controls (eGDSD,eGDSM and eGDSY share eGDSDExit)
Use of bMostRecentlyVisited. (I think this could be done with something more clever.... Perhaps var oMostRecent,
oMostRecent:=self, with oMostRecent do setfocus?... or something along these lines? but my more transparent
system works. "Bad" in that simple typos in the assignments to bMostRecent would confuse the system.)
Interlocking OnKeyPress/ OnKeyDown events and enabling of buDoGraph.
Use of Try... Except... End in eGDSDExit.
Use of EConvertError in eGDSDExit.

I haven't saved the state of the program at this point because what comes next is more or less independent of the
above.

Once the file was open, and control of the range of dates to be plotted at least started, rather than go directly to the
graphing of the data, I wanted to implement parts "D" and "E", but with the numbers to be plotted being displayed
as numbers when the program worked past that part of the data file. I did not want to start struggling with turning
the numbers into a graph until a sensible stream of numbers is being generated!

When I had got this far with the program, I saved the sourcecode again, in the "StateB" folder.

===
Now to add the graph drawing.....

See my (written but not yet published... Pester me if you want it!) earlier tutorial on re-sizable windows, if things
in what follow are too obscure.

First I set up the basics in the OnResize event, code which prevents the window being made too small, and code
that keeps changing the image control's size to suit the current size of the form.

Note the bit of bad programming "necessary" due to my ignorance of something I've yet to get to the bottom of: I
set up two "constants" in OnFormCreate...

wImagePicHeight:=285;
wImagePicWidth:=285;
These are set to 285 because, using the RAD IDE, I made the image 285 x 285 in the design phase. If the size of
the image is changed, the values in wImagePicHeight and wImagePicWidth need to be changed. I think that both
the control's size, and the size, in pixels, of the underlying object you draw on (image1.canvas) are set during the
design process. Once the program is running, the control's size can be changed, and if you remembered to set the
image property "stretch" true, whatever's on the canvas will fill the control's area. However, even though you are
changing the number of pixels used, you are not changing the number of "pixels" in the virtual canvas inside the
machine. With the figures above, lineto(142,142) will always draw a line to the center of the image, regardless of
its current size.

http://sheepdogguides.com/dt5d.htm (5 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

Sadly, the "stretch" mechanism in Windows (or is it Delphi?... anyway: it is beyond your reach!) doesn't work
entirely as I would wish. Suppose you had five horizontal lines on the image. If you re-size it smaller, not all five
lines remain visible at all zoom levels. Another approach might give better results, but the programming overhead
would be large, and execution time for the re-size might become unacceptable.

I couldn't see the image until I put a moveto(10,10) in OnFormCreate. Eventually, that was replaced by something
more useful, but don't worry about why you see no image until something is done to/ with the image.

We now have a drawing area. If we say...

image1.canvas.moveto(0,0);
image1.canvas.lineto(140,140);
... we will get a line from the upper left hand corner to nearly the middle of the drawing area. If, while program is
running, we re-size the form to a bigger size, the line will now be more pixels, but it will still go to near the center
of the drawing area.

"Forget" the details of the program's internals for a moment, and try to fix the overall requirements in your mind,
and the details of their components:

The program is going to generate several rows with 7 columns in each. Each cell is going to display events from a
single day. The programming will be organized in several layers

While it might not be the most obvious approach, for a variety of reasons, I decided that the way to approach the
project was to think of the picture as building from the lower right, doing a row at a time. I.e. in the reverse order
that we would normally use in reading.

The position of the table of cells will be the net effect of a programmer chosen RIGHT margin, a BOTTOM
margin, and the number of pixels chosen for the width and height of each cell. Again, not the usual way of
formatting something, but it worked well.

Almost all of the relevant numbers (e.g. number of pixels for the margin on the right) are placed in variables, and
then the contents of those variables are not changed. Thus, they are being used as if they were constants. Some of
the numbers go in true constants.

The benefit of this can be illustrated by a trivial example. Suppose you want to change the size of the right margin?
Say it was 5 pixels initially. If you used a 5 each place there was need, changing the margin becomes a pain
fraught with chances for error. If you used bRtMargX:=5 and then put bRtMargX each place there was need, then
"re-programming" the program for a different margin is almost trivial.

A little trick for you: Assuming for the moment that bRtMargX is one of these constant "variables" (or, indeed, a
true constant), then if you are going to want to do something like....
x:=wCell1x-bRtMargX+1
... especially if it is going to happen in an oft repeated loop, it pays to put the following somewhere early in the
program:
bRtMargXPlus1:=bRtMargX+1
Then your x assignment becomes...
x:=wCell1x-bRtMargXPlus1
... and (in crude terms) you've reduced the calculation overheads by 33%.

http://sheepdogguides.com/dt5d.htm (6 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

Moving on....

How do we get from the data to the picture? Think again about the sort of data involved.....
LA16, ver 25/7/2002 restarted at 1:21 on (DMY) 26-7-2002
Switch was open.
--------day changed at 0:0 on (DMY) 27-7-2002
Opened: 7:23 on (DMY) 27-7-2002
Closed: 17:21 on (DMY) 27-7-2002
--------day changed at 0:0 on (DMY) 28-7-2002
Opened: 17:23 on (DMY) 28-7-2002
--------day changed at 0:0 on (DMY) 29-7-2002
Closed: 17:23 on (DMY) 29-7-2002
That can be thought of as a wordy version of....
Restart 0:0, 27-7-2002
DayChg 0:0, 27-7-2002
Opened: 7:23, 27-7-2002
Closed: 17:21, 27-7-2002
DayChg 0:0, 28-7-2002
Opened: 17:23, 28-7-2002
DayChg 0:0, 29-7-2002
Closed: 17:23, 29-7-2002
Dates! Woe is me! "Thirty days hath September..." They are a REAL PAIN.

Happily, Delphi has good tools for working with dates. January 1st, 2000, in Delphi's internal representation, is
day number 36526. (Beware: Delphi 1 used a very similar scheme, but with a different base date.) Very sensibly,
they allow you to specify a certain time on a certain day by using the fractional part for the time. Midnight
1/1/2000 is 36526.000. Noon 1/1/2000 is 36526.500. Midnight Jan 2, 2000 is 36527.000, and so on. Don't worry...
there's a whole host of built in functions and procedures to convert back and forth between Delphi DateTimes and
human dates and times. Start exploring the help file at EncodeDate.

The program calls procedure SetConst just once. It is here that the various constant "variables" are assigned the
values we want in them.

The program calls procedure PrepImage to draw the lines which appear on every display generated by this
program. They are horizontal lines along the bottom of each week's row, with small vertical lines to show where
midnights occur.

At the start of buDoGraph's handler, the program looks at a few things it already knows like the last date to be
shown on the graph and the day of week the programmer has selected for the first column. During this process
other constant "variables" are given values.

When the data is processed, a line like "Opened: 7:23, 27-7-2002" is converted to:
a code for the event to be reported on the graph.
a number for which day column the datum should go in
a number for which week row the datum should go in
a number for how far across the day's cell the datum should go.

This was quite a bit of work!

http://sheepdogguides.com/dt5d.htm (7 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

The payoff came because once the record had been converted to the 4 data, a procedure called PlotSymbol became
easy.

Within PlotSymbol there are four routines, DrawCaret, DrawPtRight, DrawVee and DrawDot. Each puts a symbol
at the x/y location specified by PlotSymbol. PlotSymbol takes care of combining all of the things like the size of
the drawing area, the margins required, which day/ week the datum relates to, the width of columns, etc, etc, and
producing the x/y values used by PlotCaret, etc.

... And that just about does it! You'll find the final code in the folder StateFinal, and with it a NEW, bigger file of
test data.

Enjoy. Please remember that the application that this is based on is copyright, TK Boyd, 9/02. You are welcome to
study the sourcecode and learn things, but you'll be chancing problems if you try to distribute anything too closely
resembling my program. If you want to buy a license to use the program, or something similar I could produce to
your requirements, don't hesitate to get in touch!! Tell me a little about who you are, where you want to use it, for
what... (I can also supply the program that produces the datafile. That runs in a DOS box.)

==== P.S......

Here are two things I've discovered while writing a derivative of GP2. They don't really belong here(Pester me to
give DD27 it's own Tut!), but maybe you've found them anyway with my site search engine, thank you FreeFind.
Before I start on them, two even smaller points: 1) bTmp:=bTmp+1 may be better than inc(bTmp), because range
checking isn't applied to the latter, even with {$R+} and 2)

image1.canvas.pixels[10,20]:=clRed;
Makes the pixel 10 to the right and 20 pixels below the upper right hand corner of image1 red.

On to the larger points...

a) You need an application.processmessages from time to time in the following, or you don't see any points plotted
until the loop finishes. Of course, you should have application.processmessages calls within any long loop anyway.
Don't be distracted by the fact that I've used a repeat...until loop to make a for...to... loop. I know what I'm saying is
true with repeat...until, and am only guessing that the same would happen with a for...to... For example, the
following....

liTmp:=0;
repeat
image1.canvas.pixels[random(50),random(50)]:=clRed;
liTmp:=liTmp+1;
application.processmessages;
until liTmp=4000;
... would work nicely, whereas without the application.processmessages, you wouldn't see the pixels until the loop
finished. (Of course, for just a few pixels, the delay wouldn't matter, but I recently wrote a program which prints
tens of thousands of pixels within such a loop.)

Without the application .processmessages, the loop finishes MUCH more quickly. You may want to incorporate
the following compromise....

http://sheepdogguides.com/dt5d.htm (8 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

Before loop:

bTmp2:=0;
Inside loop:

bTmp2:=bTmp2+1;
if bTmp2>100 then begin
bTmp2:=0
application.processmessages;
end;

b) I don't often use menus as my programs usually only need a few "Do It" buttons to meet my needs. I almost
always have a "Quit" button. Usually, the OnQuitCLick handler is simply application.terminate. However, this
does not always kill programs for me. Recently, I've begun to suspect that the following may be what's needed
when the program is in a loop....

Before the loop:

boDone:=false;
In the OnQuitClick handler, and in the main form's OnClose handler:

boDone:=true;
An additional condition with the repeat:

or boDone

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar Top
200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this
doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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

http://sheepdogguides.com/dt5d.htm (9 of 10) [1/28/2005 3:47:16 PM]


Delphi: A program from start to finish

Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi,
and they provide promotional services, too. Click the "Help get this site publicity" link above for more

http://sheepdogguides.com/dt5d.htm (10 of 10) [1/28/2005 3:47:16 PM]


Delphi: RS-232, serial comms, COM1, COM2

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

Delphi: RS-232, serial comms, COM1, COM2


This has good information, and a search button at the bottom of the page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

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

The RS-232 serial interface is a wonderous thing. It has many marvelous capabilities. It is also something I've put of wrestling
with for a long time. Search the web for "How To"s and you may see why. It turns out that things are not as bad as you might
think. (But I must admit, the last program below doesn't work yet! But online resources assure me it "should"! Read on?)

The programs presented here will do certain jobs, but they do not implement everything specified within RS-232. The big gap
in my "solution" is that there is no handshaking.

I wanted to be able to communicate with a nice little PIC based microcontroller called the Pascalite. You can learn more about
that (there's a free compiler and hardware simulator) in my Pascalite pages.

My quest for serial communications took a leap forward thanks to Robert Clemenzi's FAQ answers.

Much of the following is taken from there, with alterations. He himself credited Borland's Borland's FAQ 16400 as the
inspiration and source of what he posted.

I subsequently did a Google search on "commtimeouts delphi" and turned up a number of useful things, not least Peter
Johnson's good essay. Peter has written a number of articles, components and applications, all of which can be found on his
web page. He also addresses how you can set the port's baud rate, etc, which I have not covered here. (Yet!)

If you need help with the low level electronics, cables, pinouts, connectors of RS-232, visit Arc Electronics' helpful page.

Still with me, I hope? First we'll write a Delphi program which can send RS-232 data to the Pascalite (or other RS-232
receiving device!) The Pascalite will display what is sent to it on the Pascalite's LCD display.

The program in the Pascalite will be:

program Demo3RS232;
var bTmp,bFrmRS232:byte;

begin {main}
write(LCD,255); {clears LCD}
repeat
if RS232_New_Byte then begin
read(RS232,bFrmRS232);
write(LCD,bFrmRS232);
end;
until 4=5;
end.
If only Windows programming was so straigthforward! (You may want to visit my Pascalite tutorial if the above isn't clear to
you.)

The Pascalite Plus has a one byte RS-232 receive buffer. If a second byte of data is received before the first has been

http://sheepdogguides.com/dt5f.htm (1 of 8) [1/28/2005 3:47:21 PM]


Delphi: RS-232, serial comms, COM1, COM2

processed, the first is lost. Happily, the filling of the buffer is done by an interrupt-triggered routine. The Pascalite can be
doing something else at the moment the byte's bits begin to arrive. Furthermore, the RS232_New_Byte allows the PAscalite to
know if there is an unused byte waiting in the buffer for processing. (The Plus has a 32byte buffer). In our simple approach to
serial communication over the comm port, we're going to have to do in software what can be done in hardware with more
sophisticated solutions.

If you think about the code given above, and the fact that there's only a single byte buffer, you will see that the machine
sending information to the Pascalite must send it a character at a time, slowly enough to ensure that the Pascalite has dealt with
the previous byte before the next one is sent. There are lots of ways to overcome the problems inherent in that situation, which
I'll try to discuss later, but for now: let's get the essentials working.

We're still not ready to start our Delphi program. RS-232 is fraught with many connection issues. The cable between the
machines has to be right. At each end, baud rates and other things have to be set. In respect of connecting a Pascalite to a
Windows machine, these issues are discussed at my Pascalite RS232 tutorial. For the rest of you, I will point out that the
program I am going to develop here does not have parameter setting routines. Set up your Windows comm port via the Settings
| System Settings | Device manager. Set up your remote device however it has to be done. Note in particular that you should
select no handshaking, not RTS/CTS, not XON/XOFF.

Before embarking on the Delphi program here, it would probably be best to see if you can send to your remote device using
Hyperterminal. (Again, my Pascalite RS232 tutorial discusses aspects of this.)

So! At last! The Delphi Program. I've tested it with Delphi 2.

It is pretty simple! The form has one button. When you clcik the button, the machine the Delphi program is running in sends a
phrase to the other machine via the RS-232.

First I'll list the whole program, then I'll explain odds and ends. I used the power of Delphi to add a button to the form, and to
generate the shell of Button1Click. I've put (***** n *) after lines I had to type in by hand.

unit DD28;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type
TDD28F1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure SendChar(sToSend:string);(***** 1 *)
private
{ Private declarations }
public
{ Public declarations }
end;

var
DD28F1: TDD28F1;
NumberWritten:dword; (***** 2 *)
sPhraseToSend,CommPort:string; (***** 3 *)
hCommFile:THandle; (***** 3 *)
c1:byte; (***** 3 *)

implementation

http://sheepdogguides.com/dt5f.htm (2 of 8) [1/28/2005 3:47:21 PM]


Delphi: RS-232, serial comms, COM1, COM2

{$R *.DFM}

procedure TDD28F1.SendChar(sToSend:string);
begin
CommPort := 'COM1'; (***** 4 start *)
hCommFile := CreateFile(PChar(CommPort),
GENERIC_WRITE,
0,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
WriteFile(hCommFile,
PChar(sToSend)^,
Length(sToSend),
NumberWritten,
nil); (***** 4 end *)
CloseHandle(hCommFile); (***** 5 *)
end;

procedure TDD28F1.Button1Click(Sender: TObject);


begin
sPhraseToSend:='Testing 1 2 3'; (***** 6 start *)
for c1:=1 to length(sPhraseToSend) do begin
SendChar(copy(sPhraseToSend,c1,1));
application.processmessages; (***** 6 end *)
sleep(10); (***** 7 *)
end;
end;

end.
(I'll try to give you more in the way of comments another time. For now, two things to note....

If your comm link is via COM2, you need to alter the code in the line marked "(***** 4 start *)"

In the line marked "(***** 2 *)", I've declared NumberWritten to be of type dword. This disagrees with Borland's FAQ
answer, but agrees with something in the other source I mentioned... and it works!

=============
So much for sending things FROM the Delphi program. Now we'll move on to receiving things by the Delphi program.

Remember that it will be up to you to organise things so that the machines in "conversation" don't interrupt each other, i.e.
remember that hardware handshaking has been replaced with careful programming.

For the exercise below, we are going to have the "main" computer (i.e. the one running the Delphi program" be in charge. The
"slave" (a Pascalite in my case) will wait on the big machine, and speak after it is spoken to.

Specifically, the slave's program will be a loop looking for a message from the main machine. If an "f" is sent, the slave will
"reply" with "I saw an f". If something else is sent, the slave will reply with "I saw something other than an f". (The reply will
be displayed as the caption of a label on the Delphi program's form.)

The Pascalite program... which can be tested with the main machine running Hyperterminal.... is as follows....

http://sheepdogguides.com/dt5f.htm (3 of 8) [1/28/2005 3:47:21 PM]


Delphi: RS-232, serial comms, COM1, COM2

program Demo3RS232;
var bTmp,bFrmRS232:byte;

begin {main}
repeat
bFrmRS232:=255;
if RS232_New_Byte then begin
read(RS232,bFrmRS232);
end;
if bFrmRS232<255 then begin
{delay(200); see below}
if bFrmRS232=102 {102 is code for "f"}
then write(RS232,'I saw an f') {no ; here}
else write(RS232,'I saw something other than f');
end;{not 255}
until 4=5;
end.
The following SHOULD work!! with the above... but it doesn't yet, sigh. It RUNS... but it doesn't seem to pick up the message
coming back from the Pascalite. The Pascalite is working fine with Hyperterminal. (And yes, I did remember to disconnect the
Hyperterminal connection before trying to run the above.) I tried putting in the delay(200) remmed out in the Pascalite code
above in case the response from the Pascalite was appearing before the main PC was looking... but it didn't help.

The following is the code behind a simple Delphi form with two buttons, two labels....

unit DD29u1;

(*DOESN'T WORK... but NEARLY does.... I think!*)

(*Yes! I know this could be more elegant! Furthermore, it is "badly written"


in a number of respects. In particular, it is not very robust and fails to
incorporate sundry available error detection and handling provisions of
Windows. Improve it... without obscuring the basic things it is trying to
illustrate... and send me the improved version!!*)

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TDD29F1 = class(TForm)
buSendf: TButton;
buSendx: TButton;
Label1: TLabel;
Label2: TLabel;
procedure buSendfClick(Sender: TObject);
procedure buSendxClick(Sender: TObject);
procedure SendChar(sToSend:string);
procedure EstablishHandle;
function ReadStringFrmRS232:string;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }

http://sheepdogguides.com/dt5f.htm (4 of 8) [1/28/2005 3:47:21 PM]


Delphi: RS-232, serial comms, COM1, COM2

public
{ Public declarations }
end;

var
DD29F1: TDD29F1;
sPhraseToSend:string;
hCommFile:THandle;
c1:byte;

const ver='18 Apr 03';


CommPort = 'COM1';

implementation

{$R *.DFM}

function TDD29F1.ReadStringFrmRS232:string;
(*hCommFile must be valid before this is called*)
var sTmp:string;
c1:integer;
chBuffer:array[0..255] of char;
NumberOfBytesRead : dword;

begin
if hCommFile=INVALID_HANDLE_VALUE then exit;

if not ReadFile (hCommFile, chBuffer, sizeof(chBuffer),


NumberOfBytesRead, Nil) then
showmessage('Problem with ReadStringFrmRS232')
{ Better: Raise an exception } ; { <- semicolon IS needed here!}

{The program will go off and watch the RS-232 data source
for incoming data. It will continue to watch (and collect
data as it appears) for a time determined by the CommTimeouts
settings... thus you don't need to know in advance how many
bytes will be coming, nor does the connected device need
to send a flag marking the last byte.... though that
protocol could be incorporated on top of the other
provisions for signalling the end of the data.}

label2.caption:='Bytes seen: '+inttostr(NumberOfBytesRead - 1);


for c1:= 0 to NumberOfBytesRead - 1 do
sTmp:= sTmp+chBuffer[c1];

result:=sTmp;
end;

procedure TDD29F1.SendChar(sToSend:string);
(*hCommFile must be valid before this is called*)
var NumberWritten:dword;
begin
if hCommFile = INVALID_HANDLE_VALUE then
showmessage('Problem with SendChar')
{Better: raise an exception } ; (* <- semi colon IS needed here*)

http://sheepdogguides.com/dt5f.htm (5 of 8) [1/28/2005 3:47:21 PM]


Delphi: RS-232, serial comms, COM1, COM2

WriteFile(hCommFile,
PChar(sToSend)^,
Length(sToSend),
NumberWritten,
nil);
end;

procedure TDD29F1.EstablishHandle;
var CommTimeouts : TCommTimeouts;
begin
hCommFile := CreateFile(PChar(CommPort),
GENERIC_READ or GENERIC_WRITE,
0,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0); {Delphi 2 helpfile said use "NULL" here,
and program compiled, but raised error when
it was run. Two references said use 0}
{Ever been frustrated by something that wouldn't work when it
"should"? I spent about an hour tinkering with this program
with "generic_write or generic_write" (WRITE twice instead of
one read, one write) in the parameters above.....
ARGHH!!, as Snoopy would say.}
with CommTimeouts do
begin
{put cursor on 'CommTimeouts', press f1 to learn
about what the following specify. The numbers here
are crude, and need consideration.... though they
MAY work for yoyu in your situation! The 'right'
numbers depend on many things, including the settings
in the device you are communicating with. If the
numbers are too small, the Delphi program won't
"see" the attached device. If they are too large,
the program will appear to hang while communicating....
If too large, they may also interfere with Windows'
proper functioning.... but may not.}
ReadIntervalTimeout := 0;
ReadTotalTimeoutMultiplier := 0;
ReadTotalTimeoutConstant := 1500;
WriteTotalTimeoutMultiplier := 0;
WriteTotalTimeoutConstant := 500;
end; {with}

if not SetCommTimeouts(hCommFile, CommTimeouts) then


showmessage('Problem with SetCommTimeouts')
{ Better: raise an exception } ; (* <- semi colon IS needed here*)

end;

procedure TDD29F1.buSendfClick(Sender: TObject);


begin
sPhraseToSend:='f';
EstablishHandle;
for c1:=1 to length(sPhraseToSend) do begin

http://sheepdogguides.com/dt5f.htm (6 of 8) [1/28/2005 3:47:21 PM]


Delphi: RS-232, serial comms, COM1, COM2

SendChar(copy(sPhraseToSend,c1,1));
application.processmessages;
sleep(10);
end;
label1.caption:='hardcoded f'{ReadStringFrmRS232};
CloseHandle(hCommFile);
end;

procedure TDD29F1.buSendxClick(Sender: TObject);


begin
sPhraseToSend:='x';
EstablishHandle;
for c1:=1 to length(sPhraseToSend) do begin
SendChar(copy(sPhraseToSend,c1,1));
application.processmessages;
sleep(10);
end;
CloseHandle(hCommFile); {Probably not necessary.... but was trying....}
EstablishHandle; {.... things in desperation!}
label1.caption:=ReadStringFrmRS232;
CloseHandle(hCommFile);
end;

procedure TDD29F1.FormCreate(Sender: TObject);


begin
caption:='DD29, sheepdogsoftware.co.uk, '+ver;
end;

end.

Sorry to have to leave this "half-baked". If you find the bug in my program, I'd be very pleased to hear from you! I was
working with Delphi 2 and Windows 95... but online resources suggested it should" work. (Ha!). I hope what I've presented
makes a start for you.

If you want to wade through an untidy collection of various things I harvested from the web in the work leading up to this
turtorial, you'll find it at my collection of serial io information.

Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Site Map What's New Search


Jazar 200
Please click on this to rate this tutorial.... Delphi Vote Click this, please, to help get this site publicity at Jazar Top 200 Delphi

.. and click here, too, if you're feeling really kind! (Promotes my site via "Top100Borland")

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay my
bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows 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.

http://sheepdogguides.com/dt5f.htm (7 of 8) [1/28/2005 3:47:21 PM]


Delphi: RS-232, serial comms, COM1, COM2

Link to Tutorials main page


Here is how you can contact this page's author, Tom Boyd.

Why does this site cause a script to run? I have the traffic to this page monitored for me by Jazar Top 200 Delphi, and they
provide promotional services, too. Click the "Help get this site publicity" link above for more

http://sheepdogguides.com/dt5f.htm (8 of 8) [1/28/2005 3:47:21 PM]


Pascalite Programming: First Steps

HOME - - - - - - - - - Other material for programmers - - - - - - - - - Pascalite Tutorial Table of Contents

Pascalite Programming: First Steps


I am trying to start at the beginning. A ten year old working at home without help should be writing
Pascal, using the Pascalite after applying him or herself to the following... if I've done it right! For those
of you who are NOT new to programming, can I ask you to skim through the "Level One" material
anyway? There are some things you might find useful. I'm working on a Windows 98 machine. Windows
95 or the higher Windows should work as well.

Everyone: Please make use of the good helpfile that comes with Pascalite. My tutorials are not meant to
supplant those, merely to take you through what is there in an easy (I hope) sequence. A useful feature of
Pascalite (and Delphi): If you are editing your program, and you want to look up say, GetTime, in the
compiler's helpfile: Just type "GetTime" (without the quotes), leave the cursor in the word, or just past it,
press F1, and, hey presto, you'll be taken to the right entry in the help file!

"First catch your rabbit", in this case download and install the free software. I know: Its a hassle. It will
take disc space. There are risks. Well, Pascalite installed for me with minimal hassle; it takes little space.
As the man said... Try it, you (may) like it.

Launch Pascalit.exe. You get a simple window with a menu. Click on "File" and then, from the drop
down menu that results, goto "New" and then select "Empty". I'll give instructions for something like that
thus in future: "Click on File|New|Empty".

A blank page will result. On it enter the following:

program first;
begin
write(lcd,'Hi');
end.
Some of the text will appear in different colors. More on that later; more on what's going on later, but for
now: Let's make something happen! But before we do, let's save your typing. (The machine will invoke
the save if you don't, anyway.) the saving is like any other Windows saving, if you are already familiar
with it. But I'll take you through things, just in case:

Click File|Save. This will actually bring up the "Save As" dialog box, because this is the first time you
are saving the program you've just typed in. You could just enter "My Program" in the file name box and
click "ok", but I'm going to suggest a slight improvement.

You are likely to be in the folder (directory) into which you installed Pascalite. What you see may vary
slightly from what I saw, but the first three files I had were Adv_text.pas, Average.pas and Avgarray.pas.
I would suggest for the files you create making a folder within that folder. In Windows 98, you can
simply put the mouse pointer amoung the file names and right click. Then select "New", "Folder", and

http://sheepdogsoftware.co.uk/plt1a.htm (1 of 4) [1/28/2005 3:47:26 PM]


Pascalite Programming: First Steps

give it some suitable name, e.g. "My Pascalite Prgms". There's also an icon you can use for creating a
new folder: A folder with a radiating star on the upper right corner.

Double click on the new folder, once created, to move into that folder. Assign a name for the file, I'd
suggest "First", or "PLT1a" (PascalLite 1a, to match this tutorial's filename). Click "Save".

(A little aside for people very new to Windows. The following is true not only for Pascalite, but for most
Windows applications. If you've started something from srcatch, i.e. by using File|New, then the first
time you save it, you get the "Save As" dialog, as I've already said. From that point on, if you use
File|Save, your work is simply saved whereever, and under whatever name you specified during the first
save. The previous version of your work is over-written. Also, when you load something pre-existing,
then doing File|Save will again simply replace the previous version. If you have been working on
something, and you don't want to destroy the previous version, then use File|Save As, and change the
name used for saving what you have.)

So... you've typed in the little program I gave you. You've saved your typing. Now click Tools|Simulate
Program (or just press F2.. equivalent.) You may well get an error message, in which case a line of your
program will be displayed in red. find the error, fix it, maybe re-save, and try Tools|Simulate Program
again. (The line in red is where the compiler noticed the problem. It is not uncommon for the underlying
flaw to be earlier in the program. Often you have failed to end the previous line with a semicolon (;). Not
every line ends with a semicolon, but they are easily forgotten.)

Don't be alarmed if it seems that nothing has happened. First you need to tell the program to run. Isn't
that what "Tools|Simulate Program" said??? Not exactly... that only switches you out of the program
editor into the simulation environment. Once there, you need to click on the green, right pointing,
triangle on the simulator toolbar to run the program in the simulator. Even when you do that, our little
program doesn't appear to do much. Look carefully at the "Simulator" panel that opens when the system
is in simulation mode. Near the bootm, on the left, is a simulated LCD display with the following text:
"Pascalite II Pro / (c) Control Plus / V2.50 / 2000". Watch the space just after the "2000" when you click
the green "Run Program" triangle- you should see "Hi" appeara briefly. That's your program running!
(The LCD simulation starts with the copyright message, and after your program has run, the panel clears
itself and restores the message... that's why the "Hi" appears so briefly. Don't worry... we can make the
computer do things our way!

Just one last little detail to finish off this first tutorial. You won't finish a program on the first try. After
typing a start, and clicking Tools|Simulate Program, you'll have to leave the simulator, which will send
you back to the editing environmet. All you need to do to leave the simulator is click on the red X on the
simulator toolbar. Try adding a second write line, e.g. "write(lcd,'Bye');" Click Tools|Simulate Program
again, see your new masterpiece in action (or fix the typos!) and then pat yourself on the back... you're a
programmer.
Oh yes... I said I'd take you through the program....

Every Pascal program begins with the word "program". After that, you supply a name; I chose "First" in
this case. And then the line is finished with a semicolon. You get a lot of those in Pascal. More on them
another time.

http://sheepdogsoftware.co.uk/plt1a.htm (2 of 4) [1/28/2005 3:47:26 PM]


Pascalite Programming: First Steps

Next in our simple first program came the word "begin". For every "begin" there is an "end". You can
have many begin/end blocks, and they always nest. Leaving out the rest, a complex program might look
like.....

begin
begin
begin
end;
end;
begin
begin
begin
end;
begin
end;
end;
end;
end.
Did I scare you? Hope not... just look forward to the excitement of a really sophistocated project!
Anyway. Begins are always paired with ends, as I said. You do NOT put a semicolon after the begin
(unusual), but you do put one after the end... usually. (I'll discuss the exceptions another time.) After the
final "end" in a program, you put a period (full stop) instead of the semi-colon.

"write" is a word built into Pascal.


"lcd" says where we want to write to... there aren't many choices. More on them another time.
Note that we put apostrophes around the text we want written, rather than the quotation marks we would
use in everyday English.

And we've already covered the "end.", so we're done! Go give yourself a treat!

To search THIS site.... (Go to the site's above, and use their search buttons if you want to seach them.)...
Way to search this site without using forms
Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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.

http://sheepdogsoftware.co.uk/plt1a.htm (3 of 4) [1/28/2005 3:47:26 PM]


Pascalite Programming: First Steps

Link to editor's (Arunet) homepage


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

http://sheepdogsoftware.co.uk/plt1a.htm (4 of 4) [1/28/2005 3:47:26 PM]


Pascalite Programming: First Steps

HOME - - - - - - - - - Other material for programmers - - - - - - - - - Pascalite Tutorial Table of Contents

Pascalite Programming: Second program


Enter the following program....

program second;
begin
write(lcd,255);
repeat
write(lcd,'Hi');
until 4=5;
end.
... and start the simulator and (click green arrow, remember?) run the program. You should see HiHiHi...
appear on the LCD simulation. Before the screen gets very full, try clicking on the black arrows either
side of the speed indicator, which is probably saying "Med" (for medium) at the moment.

The write(lcd,255) line is what clears the LCD screen. If you said write(lcd,65), an A would appear on
the screen, 65 being the ASCII code for "A". Notice there are no apostrophes around the 65. If you wrote
write(lcd,'65'), then you would get 65 on the LCD. 255 is what programmers call a rogue value. It is
special; it isn't treated like other numbers. Its meaning to the LCD unit is "Clear the screen". (It isn't a
rogue value in general, only when sent to the LCD).

The word Repeat is one of the rare instances of something that is not followed by a semicolon, like
Begin, discussed in the first tutorial. "Repeat" is always paired with an Until. The Until is always
followed by something which is either true or false. The "something" is called a condition, in this case
"4=5". 4 doesn't equal 5, of course, so the condition is false. You will soon meet more complex (and
sensible!) conditions. (People with some experience of programming may wonder why I didn't say "until
false". Pascalite won't accept this, even though "false" is aceptable in other circumstances.)

Our program, because of the "repeat/until" pair will perform the "write(lcd,'Hi');" instruction over and
over again. This is called an infinite loop. Loops are powerful and useful, though you rarely make infinite
loops... on purpose! Some bugs are based on inadvertant infinite loops.

Modify the program so that it says

program second;
begin
repeat
write(lcd,255);
write(lcd,'Hi');
until 4=5;
end.

http://sheepdogsoftware.co.uk/plt1b.htm (1 of 4) [1/28/2005 3:47:30 PM]


Pascalite Programming: First Steps

(The word "repeat" has been moved up one line. You can do this by obvious means, but you can also do
it by selecting the text, and then dragging it to where you want it!)

When you've made the change, and re-run the program, it almost looks as though "nothing" is happening.
All right, the "Hi" appears and disappears.... but that's not much, is it? None-the-less, the program is
doing write(lcd,255); and write(lcd,'Hi'); over and over again. Notice the big effect on the results that
arises from moving the "repeat" just one line. You should be able to see why the program behaves
differently....
Pascalite, being written for a specific piece of hardware, has a few special features not found in more
general Pascals. As the hardware is a microcontroller, the usual way you give it input is more basic than
is usual on a pc.... but don't worry! We'll talk more about input later, and our first example of Pascalite
input is actually easier to understand than typical pc input. This is also the moment that you learn about
the if... then... structure.

Change the line in your program that says....


write(lcd,'Hi');
... so that it says...
if b0 then write(lcd,'b0 true');
N.B.: That's b-zero, not b-oh.

Add, just after the previous...


if not(b0) then write(lcd,'b0 false');

... and run the program again. (F2 and click green arrow).

Once the program is running, click on the virtual toggle switch labelled b0. It is near the middle of the
simulator panel. The message that is flashing on the LCD panel should be "b0 true" when the switch is
down, and "b0 false" when the switch is off.

If you are lucky enough to have a real Pascalite, the LCD panel is an optional extra. We'll deal with
getting around the need of it in a minute. The real equivalent of the virtual switch b0 is very, very simple:
An ordinary toggle switch. The wire from one side goes to one place on the Pascalite, the other side gets
a wire and a resistor connected. That wire connects to a second point on the Pascalite, and the other side
of the resistor to a third point on the Pascalite. Obviously, you may need a little more detail, but I hope
that persuades you that the hardware is simple.

By the way.. a little aside: the word "then" has at least two meanings in English. It can be a matter of
sequence: I put on my socks, THEN I put on my shoes. Or it can be a matter of consequence: If you eat
three pizzas, THEN you will be sick. While time comes into that, too, I hope you'll see the more
significant "consequence" element. In programming, "then" is used in the consequnce sense.

There's nothing "wrong" with our program as it stands, but programmers often want to choose between
two alternatives, and have been given the following shortcut. The two "if..." lines can be replaced with....

if b0 then write(lcd,'b0 true') else write(lcd,'b0 false');

http://sheepdogsoftware.co.uk/plt1b.htm (2 of 4) [1/28/2005 3:47:30 PM]


Pascalite Programming: First Steps

Did the author of Pascal anticipate the internet? I ask that because I don't know how the line above
appears on your screen.... and, I'm glad to say, it doesn't matter! If your browser window isn't narrow,
from "if..." to "...false');" is perhaps on a single line, and it is logical to write it thus in the Pascalite
editor. However, it is also acceptable to write it as two lines.... (make your browser window wide enough
to redue the following to two lines)...

if b0 then write(lcd,'b0 true')


else write(lcd,'b0 false');
Note how I have indented the second line. It is optional, but it makes reading through your program
easier, because it emphasises the fact that the "else..." line is just a continuation of what started on the
previous line. Everything from the "if..." to the "...false');" is ONE statement. The concept of what is a
statement is important in Pascal, and gets subtle in more complex cases. The big thing to notice here is
that there is no semicolon before the semicolon. The concept of statements is a little like the concept of
sentences in everyday English. Both of the following are valid (regardless of where you break the lines,
as in Pascal), and comparable to single statements in Pascal:

I will go to town.
I will go to town if it is raining.

It is incorrect to write:

I will go to town. If it is raining.

Pascal's semicolon is a bit like English's period (full stop). Because so many lines in Pascal end with a
semicolon, and because putting one before an "else" causes problems, and because if...then...else
statements are usually split across two (or more) lines, I still alter similar lines in my programs as
follows:

if b0 then write(lcd,'b0 true') {no ; here}


else write(lcd,'b0 false');
The text between the curly brackets is ignored by Pascalite. The chance to add comments thus can be a
real help to the programmer. Comments are also called remarks, or rems. In other dialects of Pascalite,
comments can be included thus...
(*This is a rem*)
... or
//All of the rest of this line is a rem

Just before I end this tutorial, let's lift our eyes from the mud in front of our feet on this trek towards
programming proficiency, and gaze at more interesting projects in the middle distance. Suppose you had
your Pascalite wired to your six disc CD player, and you wanted to be able to use switches (like b0) to
select which CD will play. Of course, you could simply use six switches... but with a little cleverness a
mere three will do. I the following, a 0 stands for "switch in off position", and a 1 stands for "switch in
on position" Each group of 3 digits shows the settings of the three switches.

http://sheepdogsoftware.co.uk/plt1b.htm (3 of 4) [1/28/2005 3:47:30 PM]


Pascalite Programming: First Steps

000 could stand for "play CD1"


001 could stand for "play CD2"
010 could stand for "play CD3"
011 could stand for "play CD4"
100 could stand for "play CD5"
101 could stand for "play CD6"

... and you's still have 2 codes spare! If you want to switch between 256 options, a mere 8 switches is
enough. Cool?

The work so far may have seemed "boring", but you have to walk before you run. If
you're not determined (stubborn?) enough to slog through this dull stuff, you're
probably not tempermentally suited to programming, anyway. But that's okay: Higher
wages for those of us who are! Even if you aren't looking for wages, hang in there? It
does get fun!

To search THIS site.... (Go to the site's above, and use their search buttons if you want to search them.)...
Way to search this site without using forms
Search this site or the web powered by FreeFind

Find! Site Map

Site search Web search

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful.
However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows
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 editor's (Arunet) homepage


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

http://sheepdogsoftware.co.uk/plt1b.htm (4 of 4) [1/28/2005 3:47:30 PM]


TextPad - the text editor for Windows

Search | Contacts | Home

What's New Products Support Download Buy Forums


TextPad.com home page
English | Japanese | Polski

TextPad® 4.7.3 is a powerful, WildEdit® 1.1 is an interactive


general purpose editor for plain tool for power users to make the
text files. Easy to use, with all the same changes to a set of text files
features a power user requires. in a folder hierarchy.
More ... More ...

Supported platforms for all International editions for TextPad


products are Windows 98, ME, in Dutch, English, French, German,
2000, XP and Server 2003. Italian, Japanese, Polish, Portuguese
TextPad also supports Windows (Brazilian) and Spanish.
95 and NT4.

Copyright © 2005 Helios Software Solutions.


All rights reserved.

TextPad integrates with CSE HTML Validator

http://www.textpad.com/ [1/28/2005 3:47:33 PM]


FreeFind

Search sponsors add search to your site


PopUpCop.com stops popups and restores tranquility to the net
Findia.net the clean, clear search that matches merchants and consumers
Webmaster freebies including hit counters, message boards, site monitoring, and more

Enter Search Keywords powered by FreeFind.com

Find

Find pages matching ALL words

Site search technology by FreeFind.com Webmasters: get your own site search engine

http://search.freefind.com/find.html?id=46682545 [1/28/2005 3:47:40 PM]


FreeFind

Search sponsors add search to your site


PopUpCop.com stops popups and restores tranquility to the net
Findia.net the clean, clear search that matches merchants and consumers
Webmaster freebies including hit counters, message boards, site monitoring, and more

Findia Net Search - Enter Keywords

Find

Site search technology by FreeFind.com Webmasters: get your own site search engine

http://search.freefind.com/find.html?id=46682545&t=w [1/28/2005 3:47:42 PM]


Web Site Search Engine, Free and Pro Versions - FreeFind.com

Let your visitors Search Your Website


Add a site search engine to your website today.
Get your search engine for free, or select an ad-free professional version.

Advanced site search and navigation technology can be added to your website in minutes. You'll
get high speed, high availability, hosted search technology from the company that pioneered the
field. There's nothing to download or install. It's free and easy.

features Enter your website address


pricing
(e.g. www.yoursite.com)
sign-up
Enter your email address
(we keep it private)
FAQ
library
search Click the button. You're done!
Instant Sign-up
site map
policies Your password and setup instructions will be e-mailed to you automatically.
contact

Login No fixed page limit Phrase matching (3 types)


Daily re-indexing Simple or boolean searching
partners Complete customization Multiple starting points
Reports track visitors' searches Professional version

Redundant search servers High availability


Hardware load balancing Dedicated NOC
Lightning-fast searches Multihomed network

Proven technology -- used by over 100,000 websites


Full templating -- give the results the look and feel of your site
Adjustable relevance scoring -- tune the results for your site
Flexible searching -- use simple searching or advanced boolean expressions
Phrase matching -- choose from exact phrase, near phrase or far phrase
Scheduled re-indexing -- have your site re-indexed as often as daily
Manual re-indexing -- anytime you want it
PDF indexing -- include your PDF files in your search results
Automatic site map -- generate site maps in three customizable styles
Language support -- works with many different languages
Search subsections -- visitors can search all of your site or a subsection
Frame support -- flexible handling of framed sites
Free optional web search -- search your site, the web, or both
Automatic what's new list -- keep your repeat visitors up-to-date
Adjustable indexing speed -- select to match your server speed
Complete indexing logs -- your current and prior logs are available online
Password authentication -- index password protected areas of your site
Fully hosted -- all website search engines run on our servers
Data search -- database style searching without a database
Professional version -- with unconditional 30-day money-back guarantee
No FreeFind branding -- no advertising or FreeFind logo in pro version*
Private domain labeling -- i.e. search.yourdomain.com in address bar *
Parallel indexing -- index using multiple simultaneous connections *
All features are available in the free version except those marked with "*"

http://www.freefind.com/ (1 of 2) [1/28/2005 3:47:48 PM]


Web Site Search Engine, Free and Pro Versions - FreeFind.com

Just enter your web site address in the form above and you'll have website search and navigation
engines in less than ten minutes. There is no software or "CGI" to download or install on your
server. All search engine software is hosted on our servers. It's easy and you can do it today!

See site search engine features for screen shots and a detailed description.
Quick answers How many pages can FreeFind index?
to common questions: How often can I have my site re-indexed?
Is there a Professional version?

home | search engine sign-up | features | pricing | search | site map


control center login | FAQ | library | policies | advertising | contact | link to us

Questions? See our search engine FAQ or check out our library. Need to get in touch with us? See our contact info.
Before you use FreeFind or add FreeFind to your site, read and agree to the site policy.
FreeFind partners include The Free Site, Freeware Files and Search Engine Guide
Other FreeFind sites Findia Net Search and Change Detection

FreeFind and FreeFind.com are trademarks of FreeFind.com.


Copyright 1998 - 2005

http://www.freefind.com/ (2 of 2) [1/28/2005 3:47:48 PM]


Site Map

Search sponsors add search to your site


PopUpCop.com stops popups and restores tranquility to the net
Findia.net the clean, clear search that matches merchants and consumers
Webmaster freebies including hit counters, message boards, site monitoring, and more

Site Map powered by FreeFind.com

Search: Search

http://sheepdogguides.com/
■ Delphi and Pascal Programming Tutorials Table of Contents
● Delphi tutorial introducing access to database files. (Level Three).
❍ Delphi tutorial: Notes on editorial policy
● Delphi tutorial, A Code Solver... and competition. (Level 4).
❍ Offers
● Delphi tutorial, A component for use and reuse in other programs, part 1 (Level
3)...
❍ Delphi tutorial, A Component for Use and Re-use in other programs, part
2 (Level...
■ Delphi tutorial, A Component for Use and Re-use in other
programs, part 2 (Level...
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial, A program to massage a pre-existing file. (Level 4).
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial, Debugging.. and avoiding the need. (Level 1).
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial, Start Here (Level 1).
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: Color Graphics. (Level 4).
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: Command Line Parameters, an alternative to .ini, registry.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: Creating an array of Edit Boxes.
❍ Delphi tutorial: Notes on editorial policy

http://search.freefind.com/find.html?id=46682545&m=0&p=0 (1 of 4) [1/28/2005 3:47:52 PM]


Site Map

● Delphi tutorial: Customising a standard control.


❍ Delphi tutorial: Notes on editorial policy
● Delphi tutorial: File Handling
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: Introduction to Graphics.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: Menu, etc
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: Playing .WAV files with MediaPlayer. (Level Three).
❍ Delphi tutorial: Notes on editorial policy
● Delphi tutorial: Syntax Notation (Level 2).
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: TTimer component, Event Driven Environments.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: Typing Tutor. (Level 3).
❍ Delphi tutorial: Notes on editorial policy
● Delphi tutorial: Using an old project as the basis of a new one (Level 2).
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi tutorial: Where To Put Things (Level 2).
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: A program from start to finish
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: A wind vane/ angle/ compass display. Event handling. The tag property.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: A Word Search Program
❍ Offers
● Delphi: Automating the creation of an HTML photo album
❍ Delphi tutorial: Notes on editorial policy
● Delphi: Displaying Images / Accessing Files
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: DLLs <i>and</i> Accessing Port Hardware
❍ Offers
● Delphi: Extracting data from records in text files

http://search.freefind.com/find.html?id=46682545&m=0&p=0 (2 of 4) [1/28/2005 3:47:52 PM]


Site Map
❍ Offers
● Delphi: How to blank monitor
❍ Offers
● Delphi: How To: Make 'beep' or other sound.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: Inter-acting checkboxes and boolean variables
❍ Offers
● Delphi: Linking to Helpfiles.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: Reading joysticks and using Windows messages
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: Reading joysticks
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: RS-232, serial comms, COM1, COM2
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: Selecting cells, using "Sender", Etc
❍ Delphi tutorial: Notes on editorial policy
● Delphi: Some sourcecode to peruse.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: The String Grid component
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers
● Delphi: Writing to the printer a line at a time
❍ Offers
● MicroLan and 1-Wire and Delphi Programming
❍ Delphi: Accessing Dallas MicroLan (aka 1-wire) Devices
❍ Delphi: Data types with MicroLan
❍ Delphi: Using Dallas MicroLan (aka 1-wire) ADC Chip (DS2450)
❍ Delphi: Using Dallas MicroLan (aka 1-wire) Counter Chip (DS2423)
❍ Delphi: Using Dallas MicroLan (aka 1-wire) DS2408
❍ Delphi: Using Dallas MicroLan (aka 1-wire) DS2438
● Re-creating parts of Windows Explorer.
❍ Delphi tutorial: Notes on editorial policy
❍ Offers

http://search.freefind.com/find.html?id=46682545&m=0&p=0 (3 of 4) [1/28/2005 3:47:52 PM]


Site Map
■ To contact Tom Boyd / Sheepdog Software (TM)

Search: Search

Site search technology by FreeFind.com Webmasters: get your own site search engine

http://search.freefind.com/find.html?id=46682545&m=0&p=0 (4 of 4) [1/28/2005 3:47:52 PM]


What's new

Search sponsors add search to your site


PopUpCop.com stops popups and restores tranquility to the net
Findia.net the clean, clear search that matches merchants and consumers
Webmaster freebies including hit counters, message boards, site monitoring, and more

What's New

Site Map Search: Search

Oct 10, 2004 - http://sheepdogguides.com/


Oct 10, 2004 - Delphi: Using Dallas MicroLan (aka 1-wire) DS2408
Oct 10, 2004 - Delphi: RS-232, serial comms, COM1, COM2
Oct 10, 2004 - Delphi: Using Dallas MicroLan (aka 1-wire) DS2438
Oct 10, 2004 - Delphi: A program from start to finish
Oct 10, 2004 - Delphi: Using Dallas MicroLan (aka 1-wire) ADC Chip (DS2450)
Oct 10, 2004 - Delphi: Using Dallas MicroLan (aka 1-wire) Counter Chip (DS2423)
Oct 10, 2004 - Delphi: Accessing Dallas MicroLan (aka 1-wire) Devices
Oct 10, 2004 - Delphi: Reading joysticks and using Windows messages
Oct 10, 2004 - Delphi: Extracting data from records in text files
Oct 10, 2004 - Delphi: A wind vane/ angle/ compass display. Event handling. The tag
property.
Oct 10, 2004 - Delphi: Automating the creation of an HTML photo album
Oct 10, 2004 - Delphi tutorial: Color Graphics. (Level 4).
Oct 10, 2004 - Re-creating parts of Windows Explorer.
Oct 10, 2004 - Delphi tutorial, A Code Solver... and competition. (Level 4).
Oct 10, 2004 - Delphi tutorial, A program to massage a pre-existing file. (Level 4).
Oct 10, 2004 - Delphi tutorial: Customising a standard control.
Oct 10, 2004 - Delphi: Selecting cells, using "Sender", Etc
Oct 10, 2004 - Delphi: A Word Search Program
Oct 10, 2004 - Delphi: Writing to the printer a line at a time
Oct 10, 2004 - Delphi: DLLs <i>and</i> Accessing Port Hardware
Oct 10, 2004 - Delphi: Displaying Images / Accessing Files
Oct 10, 2004 - Delphi: Inter-acting checkboxes and boolean variables
Oct 10, 2004 - Delphi: Linking to Helpfiles.
Oct 10, 2004 - Delphi: Reading joysticks
Oct 10, 2004 - Delphi tutorial: Playing .WAV files with MediaPlayer. (Level Three).
Oct 10, 2004 - Delphi tutorial introducing access to database files. (Level Three).
Oct 10, 2004 - Delphi tutorial: Typing Tutor. (Level 3).
Oct 10, 2004 - Delphi tutorial, A Component for Use and Re-use in other programs, part 2
(Level...
Oct 10, 2004 - Delphi tutorial, A Component for Use and Re-use in other programs, part 2
(Level...

http://search.freefind.com/find.html?id=46682545&w=0&p=0 (1 of 2) [1/28/2005 3:47:54 PM]


What's new
Oct 10, 2004 - Delphi tutorial, A component for use and reuse in other programs, part 1 (Level
3)...
Oct 10, 2004 - Delphi tutorial: Introduction to Graphics.
Oct 10, 2004 - Delphi tutorial: Creating an array of Edit Boxes.
Oct 10, 2004 - Delphi: The String Grid component
Oct 10, 2004 - Delphi: How to blank monitor
Oct 10, 2004 - Delphi: TScrollbar, GetTickCount, TabOrder, TabStop, Interlocking enables.
Oct 10, 2004 - Delphi: Some sourcecode to peruse.
Oct 10, 2004 - Delphi: How To: Make 'beep' or other sound.
Oct 10, 2004 - Delphi tutorial: TTimer component, Event Driven Environments.
Oct 10, 2004 - Delphi tutorial: Command Line Parameters, an alternative to .ini, registry.
Oct 10, 2004 - Delphi tutorial: Syntax Notation (Level 2).
Oct 10, 2004 - Delphi tutorial: Where To Put Things (Level 2).
Oct 10, 2004 - Delphi tutorial: Using an old project as the basis of a new one (Level 2).
Oct 10, 2004 - Delphi tutorial: File Handling
Oct 10, 2004 - Delphi tutorial: Menu, etc
Oct 10, 2004 - Delphi tutorial, Debugging.. and avoiding the need. (Level 1).
Oct 10, 2004 - Delphi tutorial, The Whole Picture (Level 1). Revised 19 Nov 00
Oct 10, 2004 - Delphi tutorial, Start Here (Level 1).
Oct 10, 2004 - MicroLan and 1-Wire and Delphi Programming
Oct 10, 2004 - Delphi: Data types with MicroLan
Oct 10, 2004 - To contact Tom Boyd / Sheepdog Software (TM)
Oct 10, 2004 - Delphi tutorial: Notes on editorial policy
Oct 10, 2004 - Delphi and Pascal Programming Tutorials Table of Contents
Oct 10, 2004 - Offers

Site Map Search: Search

Site search technology by FreeFind.com Webmasters: get your own site search engine

http://search.freefind.com/find.html?id=46682545&w=0&p=0 (2 of 2) [1/28/2005 3:47:54 PM]


Using a PC's parallel port for more than printers

HOME &GT &GT ELECTRONICS MAIN PAGE &GT &GT ELECTRONICS PROJECTS CONTENTS

Using a PC's parallel port for more than printers

This material is about the parallel port on MS-DOS / Windows computers. It sometimes spills over into things of
more general nature when talking about devices you might attach to the parallel port.

PLEASE NOTE: You CAN damage your computer if you make ill-advised
connections to it. Any use you make of anything you find here must be AT
YOUR OWN RISK

This page has information about......

How to send and receive data to/ from the parallel port.
How to defy Bill Gates and send/ receive data even on a Win9x, NT or XP machine.
Which pins (both back of computer and end of cable) have which signals.
Help on the software issues, with Basic, Pascal and Delphi addressed.
Help for the complete beginner wondering how even to connect an LED.
Help on the beginner's issues of 'what is an output'?
Beginner's help with the issues of load limits, pull ups, pull downs.
A little bit about interfacing to via USB and the serial (COM) port
..... AND a way to email me, for whatever I've missed!
Don't want to tie up your printer port? No excuse!! You can get a cheap card to provide a second parallel port!
Alternatively, for some projects needing input only consider using your joystick port... it can detect 4 switches and 4
resistances. (N.B.: Most joystick ports do not sense analogue voltages.) For how to program Delphi 2 and higher to
read joysticks visit this page of my Delphi Tutorials.

Using your PC isn't the only way to have a lot of fun with controlling and sensing external devices. Control Plus
sells a little computer ideally suited, and they offer a free simulator. At my Sheepdog Software (tm) site, I have done
some tutorials. I've tried to make them accessible for novices, but also useful to experts.

Don't let the warning above worry you too much... I want to stress that there is a lot of fun to be had with electronics
projects. Find yourself an 'antique' PC. If you can't rescue one from a dusty corner, you can buy one for almost
nothing. You can use the same monitor as you use on your main machine. If you wreck the antique, it hasn't cost
you much! (I got one, with monitor, off a sidewalk once!)
I have a third generation inexpensive 'protect the PC' circuit in development. You interpose it between your PC and
the home-made stuff you are attaching to the parallel port, and any mistakes in the home-made things are blocked
off from the computer by opto-isolators and relays. (Inputs to the computer are passed through an opto-isolator,
outputs are fed to the coils of relays. Properly set up, the worst thing you can do is wreck an opto-isolator or a
relay.... both relatively hard to do!) Email me if you are interested in that device. If you can design and etch your
own PCBs I can send you some notes. (Send me a snailmail address, as they are not available in machine readable

http://www.arunet.co.uk/tkboyd/ele1pp.htm (1 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

form.) If you are not making your own PCBs, I may still be able to help, but not so quickly and not for free.

If you are very new to the hardware side of computing, my Connect An LED In Words Of One Syllable may be of
interest.

Stop press!!
Cool new possibility: If you can write your own programs, I THINK (still have some work to do on this!!) you can
now connect multiple 8 bit input/ output ports to your PC using the Dallas Microlan, aka "1-wire". Look at the
DS2408 if you are impatient. Or, give my introduction to 1-Wire a try. Extra cool: The ports would interface to your
computer through your serial port, or your USB port!!

The bad news? You need to equip your PC with a pc-to-Microlan adapter (about $25). The data rates wouldn't be as
high as they would be via LPT1.

Quick guide... more thorough explanations appear


further down the page...

Software...
For a simple program to turn bits on or off just by clicking a button, go to my shareware site.
There are two free programs there... one for toggling bits, the other for using the computer as a
timer via the parallel port.

- - - - - - - -

To send 123 to the parallel port....

(There are notes below about obtaining Delphi 1 or 3, or higher)

Once upon a time, sending 123 to the parallel port (or reading from the input bits there) was a pain. The way to do it
depended on what Delphi you used and what OS the program had to run under. No longer, hurrah!

Some time ago, a kind reader sent me an email saying... "use inpout32.dll. It enables the sample programs in Jan
Axelson's book Parallel Port Complete".

It took me a while to get over my fear of DLLs, but am I glad I did! They are no big deal. Details are given in my
tutorial on using inpout32.dll. That is written for Delphi programmers, but C or VB (yuck) programmers will find
help there, too.

If you use inpout32.dll (freeware, dll and source code available from Logix4u), then one version of your program
will run on many different operating systems... Win 3x to XP at last count, including NT.

=============
If you are determined to send 123 to the parallel port the hard way..... ----

http://www.arunet.co.uk/tkboyd/ele1pp.htm (2 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

In Delphi 1 or Turbo Pascal:

port[888]:=123;
(The code above won't work in Delphi 2 or with Win 9x)

----
In Delphi 2 (and probably higher), for Win95 and 98 (but not NT), add the following procedure....

procedure PortOut(IOport:word; Value:byte); assembler;


asm
xchg ax,dx
out dx,al
end;
.... and then you can send 123 to the parallel port with

PortOut(888,123);
The code above won't work in Delphi 1 or with Win 3x, or NT, or 2000, or XP. Remember that there's a better
way... see using inpout32.dll, above.

----
A newsgroup post said that in QuickBasic you do the following

Out &h378,123
The &h378 is just another way of saying 888. The &H part says "what follows is written in hexadecimal (aka
"hex"). Hex 378 is the same as decimal (our "normal") 888. It's like the "difference" between "12", "twelve" and
"dozen".

----
For NT, if you don't want to use the better way, using inpout32.dll, explained above, you first need to install a port
driver. Here are a few URLs worth checking:

TVicHW32 http://www.entechtaiwan.com/tools.htm
DriverX http://www.tetradyne.com*)
Tinyport (NT only)
http://www.winsite.com/info/pc/winnt/programr/tinypo20.zip
(How to access the other lines of the parallel port is covered further down the page.)

Hardware

Imagine you are looking at the back of your PC, and that the parallel port socket is horizontal, with the long row of
socket on top. The numbers of the sockets at the ends of the rows are...

13 . . . . . . . . . . 1

25 . . . . . . 14

http://www.arunet.co.uk/tkboyd/ele1pp.htm (3 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

(See below for where things are to be found on the connector at the end of the cable normally plugged into a
printer.) The 'interesting' pins are:

Data bits 0-7: Pins 2 to 9, respectively. If you write to address 888 (decimal), you should see the outputs on those
pins change. (The address is different in some circumstances, but try 888. In Borland's Pascal: port[888]:=254 would
set all bits but the first one high.)

Pins 18-25: Signal ground. (I.e. for a VERY simple experiment, connect an LED to pin2, a 680ohm resistor to the
LED, and then the other end of the LED to pin 19. If it doesn't work... try turning the LED around!)

Inputs: If you read address 889, you can discover the state of 5 pins. They determine the state of bits 3-7 of 889.
bTmp:=port[889] is the 'raw' Pascal you need. Obviously, you do clever things with the result of that. The bits are
mapped and named as follows:
Bit Pin Name
3 15 Error
4 13 Select In
5 12 Paper Empty
6 10 Acknowledge
7 11 Busy
(A trap for the unwary... 'Busy' is inverted 'just inside' the computer. Thus if you apply a '1' to all of the pins, you'll
see 01111xxx when you read 889! Isn't computing fun?)

Before turning to more generally useful things, I might as well finish off the other pins....

Write to 890 to set the state of the following pins:


Bit Pin Name
0 1 Strobe
1 14 Auto Linefeed
2 16 Initialize
3 17 Select Out

The rest of this page is rough.... but ready.


The layout is a mess (sorry), and there's more editing to do (you're welcome) but there's a lot of good info and links
below and on the linked page, if you take the trouble to find them.

For many projects, you need a source of 5v (or 12v) for the electronics outside your PC. I saw the following in a
newsgroup. See my note at the end before attempting the test described.

"If you're getting the 5V from your PC, the ground from the PC will be fine. However, if you're trying to add 5V
from somewhere else, be just a little wary. The PCs logic ground (and thus that of your one-wire bus) is probably
tied to either line neutral or line ground. If you use a non-isolated switching power supply to get 5V from house
wiring, it's possible to make smoke under certain conditions. If you're not sure, hook a cheap 1K resistor between the
PCs ground and the ground of the power supply you intend to use (don't connect 5V yet for this test). If the resistor
doesn't immediately go poof, then hook a voltmeter across it and check on both DC and AC settings; you shouldn't

http://www.arunet.co.uk/tkboyd/ele1pp.htm (4 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

see more than a small fraction of a volt this way. If this test shows little or no voltage across the resistor, you're
probably all set. Not all bad to put a very low-wattage 10 ohm resistor in both the ground and 5V lines, though -
that's really cheap insurance, and most times the resistors will sacrifice themselves and protect the rest of the
circuitry if something's badly amiss.

"As always, experiment at your own risk. Safety glasses are a minimum precaution when you think there's a chance
of blowing up a resistor! Guard your eyesight carefully, and be prepared to turn off the power quickly if anything
untoward develops."

I'm not sure why the writer suggests the 1k resistor. I would be inclined just to put the leads of my voltmeter on the
two unconnected grounds, hoping to find no voltage (DC or AC!) between them. The 10 ohm idea puzzles me too..
why not just use a fuse?

In response to the previous paragraph, a test engineer in a Swedish firm kindly sent me the following....

"The first test with the 1k Ohm resistor tells you if there is a dangerous difference of voltage between the devices
(i.e. dangerous to the equipment) If the two electronic devices have floating grounds, not connected to anything near
earth potential, you will probably have a voltage between the devices that could be anything up to twice the top line
voltage. But, since the coupling to earth or whatever is weak, it won't usually generate substantial current. It's just
what leaks through capacitors and cables in the power supply.

"Using an old moving coil multi-meter with low resistance would probably tell you that there is no (dangerous)
voltage between the devices. A modern digital multi-meter, however, has a very high impedance so the voltage you
might see could alarm you. It's not necessarily a problem because it is likely that only a tiny current would flow. The
1k Ohm resistor (or 10k or even 50k or 100k...) would provide the load needed to tell about the danger.... You might
find the same "problem" if you measured the voltage between the metal frame-work of two lamps standing on your
desk! (In the US. In the UK most electrical equipment is grounded.)

"The second resistor, the 10 Ohm between the "grounds", is used by some people to minimize the problem with
migrating ground currents (editor's "clarification": Ground loops? The author was contributing in his second
language.... much more fluently than I could have in my second language!!) if the equipment have some kind of
earth, ground or other common connection. A slowly changing voltage of let's say 1/2 Volt or so in zero Ohms is... It
could damage a computer card if you were unlucky or at least jeopardize the signals within ICs on poorly designed
PCBs.

"For "normal" desk top work I don't think this 10 Ohms is needed. The resistance in the cables (if they are thin
enough) will do, but as you never know what "industrious" persons can came up with in their workshops...
Personally, if feeling uncertain, I would use opto couplers. Most parallel ports can drive them directly trough a
resistor without extra electronics."

All of the above relates only (I hope) to situations where your circuit is in two or more separately powered parts... as
will often be the case with parallel port interfacing. Unless you use opto-isolators (not a bad idea), you will have to
connect the grounds of the separately powered parts, even though the power to the parts comes from different
sources.

(An aside: The submission from Sweden put capital letters on Volt and Ohm. I started to "correct" them, but then
realized that the general rule is to use capitals where a unit of measurement derives from a person's name, e.g. Hertz,
Pascal. So why don't we usually capitalize "volt" and "ohm"? Boy, am I glad I didn't have to learn English as a
second language!) ===
Click this for Jan's good page similar to this one.

http://www.arunet.co.uk/tkboyd/ele1pp.htm (5 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

===
Much good information is available in the British magazine 'Everyday with Practical Electronics.' You can visit
them at www.epemag.wimborne.co.uk

Robert Penfold's 'Interface' column has frequently had projects interfacing all sorts of things to the parallel port, but
I don't think much of his material is in the website... yet. Agitate!

===
Someone asked: Why do we need to connect pull up/ down resistors or hex inverter buffers (open collector) to the
control pins of a port? What is open collector actually? What are the states of the open collector port?

Someone answered:

Inputs do NOT *HAVE* an inherent state, and need NO pull-up or pull-down! But the input voltage to them must
be definitely HI or LO. The open-collector outputs have internal pull-ups, and do NOT *NEED* external pull-ups,
unless the internal pull-up is not sufficient. Rarely true!! See my FTP Gateway's TUTS/totmpole.tut file for
explanations of how the three different kinds of outputs work. See the simplpt.faq and other *lpt.faq files for
information about the parallel port. The simplpt.faq is below, Steve

ftp://ftp.armory.com/pub/user/rstevew
The filenames are: *lpt.faq; ibmlpt.faq, tomlpt.faq, and krislpt.faq. each meets different skill levels and needs.

===
If you are very new to digital electronics, It may pay you to visit my tutorial on the subject of inputs and outputs.
Bookmark this page, then click here

===
If you put eight LEDs, one on each of pins 2-9, then you can get a pretty little light show very simply. The following
is pseudo-code... you should be able to convert to the language of your choice....

REPEAT
Datum=0 ;Don't use a byte-type variable. Integer will do.
REPEAT
SEND Datum to parallel port
ADD 1 TO Datum
(If using Delphi, put application.processmessages here)
WAIT A BIT
UNTIL Datum>255
UNTIL 4=5 (i.e., forever!)
===
Someone wrote me with a question about using the "strobe" output. I sent the following in reply; maybe it clears
something up for you....

The following is untested and may have silly mistakes, but should be a guide. Port 890 is read first, and then OR's or
AND'd with the values given so that only the "strobe" bit is set or cleared.

procedure SendStrobeHi;
var b1:byte;

http://www.arunet.co.uk/tkboyd/ele1pp.htm (6 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

begin
b1:=port[890];
port[890]:=b1 OR 1;
end;

procedure SendStrobeLo;
var b1:byte;
begin
b1:=port[890];
port[890]:=b1 AND 254;
end;
Although the name 'strobe' implies a pulse, the output from the parallel port (pin 1) should stay high after a call of
SendStrobeHi until you make a call of SendStrobeLo, after which it should stay low, etc. Try sending the pin high
and low with nothing but your voltmeter attached.... maybe the circuit you are trying to drive has flaws? (The strobe
output from the parallel port shouldn't be expected to drive much.)

===
Some readers have reported problems when trying to drive a laptop's LPT with port[888]. I too have had the
experience, though in my case, I did not explore the situation. I may just have had a situation where I was wanting
too much current from the output.

If any reader knows how to determine the memory address used in a DOS or Windows 3.1 machine for the LPT
port, if it isn't 888, I'd be glad to know. I'd even welcome information on addresses which might be right. (I'm
particularly interested in driving the pins of an IBM Model 755, aka 9545.)

===
The pinout at the printer's end of a printer cable is as follows...

Look into the end of the cable that is normally plugged into your printer. Turn it so that the long side of the
connector is on top.

'Pin' 1 will be the one at the upper left.


The first in the lower row is 'pin' 19.

I won't persist in putting the word 'pin' in quotes (to acknowledge the fact that the connections are not literally
pins}... assume them for the rest of this discussion of the printer end of a Centronics cable.

Pin 2 is an output, the LSB of the data byte.


The next pins (3,4,5...9) carry the rest of the byte, in ascending order.
Pins 20-27 carry the corresponding 'data returns', i.e. are signal grounds. In a perfect world, I think you are supposed
to connect to each of them, but I believe they are all connected inside the computer anyway, so you can probably use
just a few. (Using more than one takes care of any current limitation issues, and provides insurance against bad
connections in the system.)

I can provide details of where the other signals are if you need them.

===
Remember 'the' PC is not always made exactly the same way... and, especially with old machines, a bit may be
damaged or not implemented. Experiment! Be sure to test things as you go along, 'bottom up.'

http://www.arunet.co.uk/tkboyd/ele1pp.htm (7 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

The previous paragraph applies in particular to the issues of the power capabilities of the outputs, and the pull- up/
down needs of the inputs. I'm a novice on these issues myself... but I do have several machines doing useful things
for me. In general, I wouldn't be reluctant to try to drive the base of a transistor with an output. I try to design the
external circuits to be fail-safe... e.g. if the computer that controls my burglar alarm is off, or if it has booted into
MS-DOS but not my alarm software, the output of the parallel port in those conditions was taken as the starting
point for the circuits that ring the alarm's bell. My program moves the output away from the 'default' state to ring the
bell. (There are also less complex circuits also attached to the bell which can ring it if the computer is dead!)

I have driven LEDs directly from the parallel port in my machine.... but I wouldn't assume that every machine has
sufficiently strong outputs.

(For the barely-started: Do be careful not to connect more than 5v to any input, and NOT to connect 0 or 5v directly
to any output. There should be significant resistance between an output and either 0v or 5v, e.g. the resistor
mentioned in my simple experiment with the LED, above.)

I've had enormous fun with circuits driven off the parallel port. Getting started can be a little hard, but you'll soon be
under way.

===
If you are ensconced in the brave new world of Windows, you're not supposed (gasp, horror) to access ports directly.
There are good reasons for the rule... but there are also times to break it!

With the old Borland Turbo Pascal, making the pins of LPT1 all 5v was as simple as
port[888]:=255;

In Borland's superb Delphi, version 1, you could still do


port[888]:=255;

I'm told that was dropped in later versions of Delphi, BUT... fear not!...

Version 1 has been given away many times on cover discs of magazines like Personal Computer World. It is also
bundled with later versions of Delphi. It is a superb tool for creating Windows applications. Version 1 is for
Windows 3.1, BUT NB: programs written with version 1 WILL run under Windows 95 (to my personal knowledge,
including the program below), and I am confident that they would also run under 98. You would not have access to
long filenames. (Big deal!.. you can use the DOS alias names.) Version 3 has also appeared on cover discs.

Just to check that the parallel port pins could be controlled with a Delphi program, I wrote the following tiny
program. The form it relates to has only a button on it. When the program starts, the button is marked '255' and all of
the data lines are at 5v. Clicking the button toggles the system between that state and one in which the button is
marked '0' and all the data lines are at 0v. The core of the program's code is as follows:

procedure TForm1.FormCreate(Sender: TObject);


begin
(*initialize*)
button1.caption:='255';
port[888]:=255;
end;

procedure TForm1.Button1Click(Sender: TObject);


begin

http://www.arunet.co.uk/tkboyd/ele1pp.htm (8 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

if button1.caption='255' then begin


button1.caption:='0';
port[888]:=0;
(*Makes outputs 0v*)
end(*no ; here*)
else begin
button1.caption:='255';
port[888]:=255;
(*Makes outputs 5v*)
end;
end;
===
Here is a version which will compile in Delphi 2, for Windows 95 and higher. The form has a Timer on it. The
timer's interval property is set to 2000. The only other thing the form needs is a label called Label1. Below is
EVERYTHING you need from 'implementation' through to the final 'end.'

implementation

{$R *.DFM}
{$R+} {nothing to do with previous $R}

(*The Delphi 2 on-line help has an entry for Mem[:], but


the compiler does not seem to recognize it, not does it appear in the
Reference Library Guide. Various postings in usergroups
seem to say that Win95 will not let programs access physical memory.
There was also an entry for something called ExtEscape which looked
promising for sending something to the port, but I haven't explored
that yet, and it didn't appear in Reference Library Guide either.

Peter Below (TeamB) provided the following port access routines


in a newsgroup post. He said push and pop were not needed, that
they were in fact bad ideas. He pointed out that the function uses
the normal Delphi 2/3 register calling convention and thus will get
the first parameter (e.g. IOPort) in eax, the second in edx.

In addition, he said...
This will not work on NT; it works on Win9x only because the OS has a
generic port driver. For NT you need to install such a driver first.
Here are a few URLs worth checking:
TVicHW32 http://www.entechtaiwan.com/tools.htm
DriverX http://www.tetradyne.com*)
Tinyport (NT only)
http://www.winsite.com/info/pc/winnt/programr/tinypo20.zip

procedure PortOut(IOport:word; Value:byte); assembler;


asm
xchg ax,dx
out dx,al
end;

http://www.arunet.co.uk/tkboyd/ele1pp.htm (9 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

(*More, similar, routines from Peter Blow. They are not needed
in this simple demo program...

function PortIn(IOport:word):byte; assembler;


asm
mov dx,ax
in al,dx
end;

function PortInW(IOport:word):word; assembler;


asm
mov dx,ax
in ax,dx
end;

procedure PortOutW(IOport:word; Value:word); assembler;


asm
xchg ax,dx
out dx,ax
end;

End of material from Peter Blow*)

procedure TForm1.Timer1Timer(Sender: TObject);


begin
if bPoke<>0 then begin
Label1.caption:='0';
bPoke:=0;
PortOut(888,bPoke);
end(*no ; here*)
else begin
Label1.caption:='255';
bPoke:=255;
PortOut(888,bPoke);
end;(*else*)
end;

end.

===
More info on parallel port, serial, USB (Some great pages from another source.)

===
In a newsgroup, I saw: "the TDLPort IO 'wrapper' can be installed as a Delphi component. This allows IO under
Win95/98 and (using a different file) Win NT. I know the latter normally blocks attempts to Write to/Read from
specific addresses but the DLL (legally) get around the problem. I'm hoping that the Win95/98 version will do the
same rather than just re-duplicate inpout32. It comes with a nice manual and is FREE!

http://www.arunet.co.uk/tkboyd/ele1pp.htm (10 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

Even thought there was a lysdexic error in the above, Google found for me this, which leads to....

Name: TDLPortIO 1.3 Date: 12/7/99


Environment: Delphi 3.0, Delphi 4.0, C++ Builder 3.0, C++ Builder 4.0 Download
Type: Freeware with Source Size: 851 Kb
Description:
TDLPortIO is a wrapper for the free DriverLINX kernel mode driver (included).
It allows full port IO under Windows 95/98/NT.
Comes with a C++ Builder and Delphi components,
ActiveX control (for Visual BASIC) and DLL version.
Compatible with the shareware package TVicPort.

===
It is VERY ROUGH still, but I've started a collection of links and information about communicating via the serial
port. It is at... My Serial Port page
This isn't really the time or the place to tell you about the following, but until I can write it up properly....

If you are into making your own electronic devices, you might be interested in the USB modules from
www.ftdichip.com/FTEval.htm. For about $20, you can buy a little unit that plugs into a Win98 or higher machine
via USB. On the "outside world" side, it has 8 bidirectional digital input / outputs, and a few handshake lines. The
programming isn't trivial, but there is great material about accessing the device. Illustrations in Delphi are provided.
You either install a TComPort component (a freeware one, with Delphi source code is available from Dejan Crnila
and then access the 8 bits as if (to Win98) they were on a COM port, OR you use a DLL (supplied royalty free from
FTDI). It is not exactly a parallel port via USB, but that's roughly the idea.

And, also perhaps in the wrong place, but maybe you'll find fun:

To control 8 lights from the parallel port is extremely easy. If you want to control more, you are going to have to
design some external electronics with "latches". Three lines from the parallel port will go to something like a 74138
which selects one line of 8 outputs from the 74138 according to the pattern of ons and offs on the three inputs to the
74138. You will also use one line of the parallel port to say "latch now, data is valid", i.e., the signals you're seeing
are the signals I want you to notice. This "latch now" signal is how you avoid problems while the signals are
changing. The remaining 4 lines from the parallel port will be data lines. Thus, you will be able to change the state
of four lights at a time, but you will have 8 banks of four lights, so the circuit, potentially, could have 40 lights (or
other output devices) on it.

For Delphi programmers: Tutorial: A free DLL to access the printer port, and how to use it..

For Delphi 2 (and above) programmers: Tutorial: How To Access A Joystick.

Haven't found what you wanted? Click here to go to a further page consisting mainly of links to
other resources.

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this
doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my
freeware and shareware page, download something, and circulate it for me? At least (please) send an 'I liked the

http://www.arunet.co.uk/tkboyd/ele1pp.htm (11 of 12) [1/28/2005 3:47:59 PM]


Using a PC's parallel port for more than printers

parallel port use page, and I'm from (country / state)' email? (No... I don't do spam) Links on your page to this page
would also be appreciated!

Click here to visit editor's freeware, shareware page.

Don't forget to check out the programs for controlling the state of the parallel port at my
shareware site. There are two free programs there... one for toggling bits, the other for using the
computer as a timer via the parallel port.

If you want to email page's editor, Tom Boyd, please click here and read a short message. My eddress if given there.
Click here to go up to general 'electronic projects' page by editor of this page.
Why does this page have a script that loads a tiny graphic? I have my web traffic monitored for me by eXTReMe
tracker. They offer a free tracker. If you want to try it, check out eXTReMe's site

Some other activity may result from my "Link Exchange" banner ad. I signed up for this a long time ago, and
haven't got around to removing it. Other than that, what you get is what you see! I don't inflict cookies on you,
except via my Link Exchange links.

http://www.arunet.co.uk/tkboyd/ele1pp.htm (12 of 12) [1/28/2005 3:47:59 PM]


Delphi Central provider of Delphi programming tutorials

Delphi Central - Tutorials, Hints and Information


Welcome To Delphi Central
The purpose of this site is to share Delphi programming knowledge amongst the Delphi community by means of Delphi tutorials and articles.
The site is currently home to over 50 Delphi programming tutorials.
We have been given permission to republish some Delphi components by a company that one of us was a director for, these will be available
soon with full source.
We have now added the fourth and final part to the Delphi Tutorial called Programming a Memory Game. The complete source code is
available for download at the end of this final installment.
In the near future we will be adding information related to training in other programming languages, including but not limited to C++, C# and
SQL.
We hope you find our tutorials useful. If not then drop us an email and we will see what we can do.

Latest Delphi Programming Tutorials


Tutorials Added 2005-01-19
Added more Delphi Hints Tutorials Added 2004-12-30
Programming a Memory Game in Delphi - Final Part (4) - Coding the Algorithm
Implementing Shell Search Handler in Delphi
How to Show a Print Preview of a TRichEdit
How to get File Summary Info
Tutorials Updated 2004-11-28
Writing a URL Label component
Tutorials added 2004-11-21
Programming a Memory Game in Delphi - Part 3 - Draw the Grid
First Delphi .NET Tutorial - Hello World
Delphi Tutorial on how to use the AlphaBlend Function
How to write a Ping utility in Delphi using ICMP.dll
Tutorials added 2004-11-03
Programming a Memory Game in Delphi - Part 2 - Starting to Code
Added more Delphi Hints & Tips
How to Rotate a Bitmap using Borland Delphi
Drawing a Shaded Rectangle by using GradientFill
Detecting if an Application has Stopped Responding
Toggling the NUM, CAPS and SCROLL LOCK Keys
2004-10-26
Delphi Tutorial - Programming a Memory Game - Part 1
Finding a Node in a TreeView
Get Current User and Domain Names on Windows NT and 2000
2004-10-17
Delphi .NET Tutorial - Get IP Address
Delphi Tutorial - Getting a User List on NT
Delphi Tutorial - Setting File Summary Info
Shell_NotifyIcon Delphi Tutorial
Enjoy
The Delphi Central Team

http://www.delphi-central.com/ (1 of 3) [1/28/2005 3:48:27 PM]

Anda mungkin juga menyukai