bLastFilled:byte;...just after...
public { Public declarations }... and you must add...
bLastFilled:=5;...just after "sgLeft.cells[0,5]:='no';sgRight.cells[0,5]:='fromage';"
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; 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.
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.
grTmp:=sgLeft.selection; liSGRLeft:=grTmp.Top;... gets a hold of which row is selected in the left hand string grid.
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....
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.
if boPair(liSGRLeft,liSGRRight) then begintests 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.
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.
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.
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.
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!!!
|
Page WILL BE tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org
....... P a g e . . . E n d s .....