Damon 0 Posted March 17, 2022 Making me crazy. I build grid at runtime based on a db record with col and row counts. I display and populate strings with data for cells from detail table data. When the grid is shown (pagecontrol tab is active) i want to programatically select the row that matches some data (id for a record) i know what col and row this is but when i try to set col and row it says out of bounds which is a lie. I thought it maybe because of fixed row and col, but if i set col-1 and row-1 the result is the same. 😞 What am I missing? This is to build the grid: procedure Tmain.buildrackClick(Sender: TObject); var i, k, c, r, j, box, rb, cb : Integer; begin //showmessage('draw grid'); stringgrid1.ColCount := ddata.rackclientdataset.fieldbyname('c').asinteger+1; stringgrid1.RowCount := ddata.rackclientdataset.fieldbyname('r').asinteger+1; setgridrow := 0; setgridcol := 0; j := 0; box := 0; K := 0; with StringGrid1 do for J:= 0 to RowCount - 1 do for I := 0 to ColCount - 1 do begin K := K + 1; if (i = 0) or (j = 0) then begin rb := 0; end else begin box := box + 1; ddata.tubclientdataset.locate('Rackid;Tubid',vararrayof([listbox1.items[listbox1.ItemIndex],box]),[]); if ddata.tubclientdataset.fieldbyname('id').asstring = '' then Cells[I,J] := 'Bin '+IntToStr(box) else begin Cells[I,J] := 'Bin '+IntToStr(box)+' '+ddata.tubclientdataset.fieldbyname('id').asstring; if (dbedit17.text = listbox1.items[listbox1.ItemIndex]) and (dbedit18.text = inttostr(box)) then begin setgridrow :=J; setgridcol:=I; //showmessage('cell is row '+inttostr(j)+' col '+inttostr(i)); end; end; end; end; with StringGrid1 do for r := 1 to RowCount - 1 do begin Cells[0,r] := 'Row '+inttostr(r); end; with StringGrid1 do for c := 1 to ColCount - 1 do begin Cells[c,0] := 'Column '+inttostr(c); end; stringgrid1.defaultcolwidth := trunc((stringgrid1.Width-56)/stringgrid1.colcount); stringgrid1.defaultrowheight := trunc((stringgrid1.height-45)/stringgrid1.rowcount); stringgrid1.ColWidths[0] := 56; end; Then this is to select the cell and it will not work! Fails when trying to set col value. Can see valid grid cell on screen at time. Doesn't make sense. Vars have correct data. if (setgridcol <> 0) and (setgridrow <> 0) then begin //stringgrid1.refresh; showmessage(inttostr(setgridcol)+' is col '+inttostr(setgridrow)+' is row - try to set cell selected.'); //stringgrid1.SetFocus; showmessage('grid focused'); stringgrid1.col := setgridcol; showmessage('col set'); stringgrid1.row := setgridrow; showmessage('row set'); end; Share this post Link to post
Ivan Yuzafatau 0 Posted March 17, 2022 Firstly, please make your code readable.. I recommend looking at the following article: Object Pascal Style Guide Share this post Link to post
Remy Lebeau 1396 Posted March 17, 2022 2 hours ago, Damon said: I thought it maybe because of fixed row and col, but if i set col-1 and row-1 the result is the same. 😞 Try something more like this: procedure Tmain.buildrackClick(Sender: TObject); var c, r, box : Integer; RackId : string; begin //ShowMessage('draw grid'); setgridrow := -1; setgridcol := -1; box := 0; RackId := ListBox1.Items[ListBox1.ItemIndex]; with StringGrid1 do begin ColCount := 1{FixedCols} + ddata.RackClientDataSet.FieldByName('c').AsInteger; RowCount := 1{FixedRows} + ddata.RackClientDataSet.FieldByName('r').AsInteger; for c := 1{FixedCols} to ColCount - 1 do begin Cells[c, 0{FixedRows-1}] := 'Column ' + IntToStr(c); end; for r := 1{FixedRows} to RowCount - 1 do begin Cells[0{FixedCols-1}, r] := 'Row ' + IntToStr(r); for c := 1{FixedCols} to ColCount - 1 do begin Inc(box); if ddata.TubClientDataSet.Locate('Rackid;Tubid', VarArrayOf([RackId, box]), []) and (ddata.TubClientDataSet.FieldByName('id').AsString <> '') then begin Cells[c, r] := 'Bin ' + IntToStr(box) + ' ' + ddata.TubClientDataSet.FieldByName('id').AsString; if (DBEdit17.Text = RackId) and (DBEdit18.Text = IntToStr(box)) then begin setgridrow := r; setgridcol := c; //ShowMessage('cell is row ' + IntToStr(r) + ' col ' + IntToStr(c)); end; end else begin Cells[c, r] := 'Bin ' + IntToStr(box); end; end; end; DefaultColWidth := Trunc((Width-56)/ColCount); DefaultRowHeight := Trunc((Height-45)/RowCount); ColWidths[0] := 56; end; end; ... if (setgridcol <> -1) and (setgridrow <> -1) then begin //StringGrid1.Refresh; ShowMessage(IntToStr(setgridcol) + ' is col ' + IntToStr(setgridrow) + ' is row - try to set cell selected.'); //StringGrid1.SetFocus; ShowMessage('grid focused'); StringGrid1.Col := setgridcol; ShowMessage('col set'); StringGrid1.Row := setgridrow; ShowMessage('row set'); end; Share this post Link to post
Damon 0 Posted March 25, 2022 Remy, thank you. Your code is much cleaner than mine. Result is the same however. Grid index out of bounds when attempting to assign the col and row to make the desired cell selected (and thus highlighted in the draw routine). I'm confused as the variables show what seem to be valid numbers. For example, a grid with 1 fixed row and 1 fixed col, with 9 string rows and 1 string col - the variables setgridcol is 1 and setgrid row is 2 should (i would think) select the 2nd cell in the grid. Row, 2, Column 1 in my attached image. But it throws the error. Thank you for you assistance, Damon StringGrid1.Col := setgridcol; ShowMessage('col set'); StringGrid1.Row := setgridrow; ShowMessage('row set'); Share this post Link to post
Vandrovnik 214 Posted March 25, 2022 Can you prepare a small demo project and put it here for download? Share this post Link to post
David Heffernan 2345 Posted March 25, 2022 Do you understand what the error message tells you? You are using an index i outside the range 0 to Count-1. You can use your debugger to find out which indexing operation is out if bounds. Debugging by looking at code can be quite hard. Delphi has a powerful debugger for such moments. 1 Share this post Link to post
Remy Lebeau 1396 Posted March 26, 2022 4 hours ago, Damon said: Result is the same however. Then it has to be a bug in the Grid, as it should be working given what you have described. I would suggest turning on "Use Debug DCUs" in the Project Options, and then step into the Grid's source code with the debugger to see exactly what is actually failing, and where it is occurring. On a separate note, have you tried the Grid's Selection property yet? var r: TGridRect; r.Left := setgridcol; r.Top := setgridrow; r.Right := setgridcol; r.Bottom := setgridrow; StringGrid1.Selection := r; 3 hours ago, David Heffernan said: Do you understand what the error message tells you? You are using an index i outside the range 0 to Count-1. But, given the screenshot and the values provided, it should not be out of bounds. That is the issue. Share this post Link to post
David Heffernan 2345 Posted March 26, 2022 7 hours ago, Remy Lebeau said: But, given the screenshot and the values provided, it should not be out of bounds. That is the issue. Perhaps the bug is in some other code in the user's program. One of the recurring themes with questions like this is that the asker often doesn't know how to use, or even realise the value, of the debugger. Re-writing the code for them doesn't help them learn that. Share this post Link to post
Damon 0 Posted March 26, 2022 7 hours ago, David Heffernan said: Perhaps the bug is in some other code in the user's program. One of the recurring themes with questions like this is that the asker often doesn't know how to use, or even realise the value, of the debugger. Re-writing the code for them doesn't help them learn that. David, you are in fact correct. I am terrible at using the debugger even though i have been using delphi since 2.0. However, my code, albeit quite messy compared to Remy's worked fine and produced exactly the same results. That piece of code was written by me some 20 years ago for a project i am porting up from D5 and the BDE to D10.x and an SQL backend. I honestly don't even remember why the variables i decided to use were so cryptic, but they must have made sense to me at the time. There is no other bug causing it. I have traced every step to the error in my code, but i do take to heart your advice about debugging and my poor knowledge of the use of it. Share this post Link to post
Damon 0 Posted March 26, 2022 15 hours ago, Remy Lebeau said: Then it has to be a bug in the Grid, as it should be working given what you have described. I would suggest turning on "Use Debug DCUs" in the Project Options, and then step into the Grid's source code with the debugger to see exactly what is actually failing, and where it is occurring. On a separate note, have you tried the Grid's Selection property yet? var r: TGridRect; r.Left := setgridcol; r.Top := setgridrow; r.Right := setgridcol; r.Bottom := setgridrow; StringGrid1.Selection := r; But, given the screenshot and the values provided, it should not be out of bounds. That is the issue. Remy, this works. All i did was comment out the .col and .row assignment and put in this code. It selects the cell and completes the ondrawcell correctly to color the selected cell. I guess the other methods just does not work as intended. ? Share this post Link to post
Pat Foley 51 Posted March 27, 2022 Couple of things that might help with the port is Quote ColCount := 1{FixedCols} + ddata.RackClientDataSet.FieldByName('c').AsInteger; RowCount := 1{FixedRows} + ddata.RackClientDataSet.FieldByName('r').AsInteger; That coding would yield where the cursor or record pointer is if a flat file? Renaming Field Name 'c' to align to what stored in it. Then Colcount would renamed to align to whats begin returned. I suspect its layout number. There is a columns count or fields count plus records count for each table. I think that older codebase should considered in final trim. Any improvements don't touch vintage code. If you're using 10.x program the improvements to suit that vintage. Over time d5 vintage code is not used very much. Good luck comes from months of careful planning and testing of enlightened repairs or good maintenance. Making a procedure in the DataModule that populates the VCL Control passed to it that can used any form that uses DMxx; the DMxx would only need VCL.grids added to the uses clause not needing the form calling it adding to uses clause. DM Public procedure getDataforSG(aCDS, aCDS2: TClientDataSet; rangeLeft, rangeRight, rangeTop, rangeBottom: Integer; aFieldName: string; //... aSG: TStringGRid); ... implementation procedure TDM.getDataforSG(aCDS, aCDS2: TClientDataSet; rangeLeft, rangeRight, rangeTop, rangeBottom: Integer; aFieldName: string; aSG: TStringGRid); var I,J: integer; RackID: Integer; TubIDcol: Integer;//Variant; csvfieldNames: string; fishName: string; begin aSG.Rows[0].CommaText := 'row'+ aFieldName; if rangeRight > CDS.FieldCount then rangeRight := CDS.FieldCount; if rangeBottom > CDS.RecordCount then rangeBottom:= CDS.recordCount; aSG.ColCount := rangeRight-rangeLeft; aSG.RowCount := -rangeBottom-rangeTop; //To find what c is about //pass in aFieldName := 'c'; for I := rangeTop to rangeBottom do begin aCDS.RecNo := I; fishName := ACDS.FieldByName(aFieldName).AsString; ASG.Rows[I].CommaText := aFieldName + ',' + fishName; end; //build SL header for I := rangeLeft to rangeRight do begin csvfieldNames := csvfieldNames + CDS.Fields[I].Name + ',' end; ASG.Rows[0].CommaText := ('Row,' + csvfieldNames); //Put your tubCDS code here Insert into form procedure Tmain.buildrackClick(Sender: TObject); const MagicNumberUp = 1; MagicNumberDown = -1;// would need inserted to adjust SG row offset var c, r, box : Integer; RackId : string; begin //ShowMessage('draw grid'); //setgridrow := -1; //setgridcol := -1; //box := 0; //RackId := ListBox1.Items[ListBox1.ItemIndex]; RackId := 'c'; getDataforSG(ffdata,tubdata,0 +MagicNumberUp,50000,0+MagicNumberUp,50000,RackID,StringGrid1); //(** comment rest out for now **) Share this post Link to post