HOME - - - - - - - TUTORIALS INDEX - - - - - - - - - - - - Other material for programmers
Delicious.Com  Bookmark this on Delicious     StumbleUpon.Com Recommend to StumbleUpon

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.

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, 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 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...
  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...
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 goes into a skill that I don't use nearly often enough. By using the "sender" parameter of things like the handler for an OnClick event, you can have one subroutine serve multiple components. Part Two shows you how to do this.


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




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

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


Valid HTML 4.01 Transitional Page WILL BE tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes. There were two "unknown attributes" in Google+ button code. Sigh.


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

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