dormky 2 Posted October 4, 2023 (edited) I have a StringGrid where results get added every second. However, doing StringGrid.RowCount := StringGrid.RowCount + 1; Sets the scroll position back to the top. How do I prevent this ? It leads to horrendous jank in the UI because I need to set the scroll back to the bottom afterwards, leading to the scrollbar (and grid) jumping up and down every second. I'm on Delphi 10.3. Thanks ! Edited October 4, 2023 by dormky Share this post Link to post
dormky 2 Posted October 4, 2023 (edited) So this code yields the best result, but requires that the last row keeps getting selected. The problem is that SetRowCount calls ChangeSize, which for some godforsaken makes sure that the anchor (ie, the top left) position is the same as the currently selected row. This means that on the next draw, your grid will "snap" to that currently selected row. This is obviously a completely idiotic implementation, but alas these are the joys of proprietary software. For the code I'm talking about, see Vcl.Grids's TCustomGrid.ChangeSize. Changing the size of something should never change its internal state(especially in such a massive way), but I guess programming standards were somewhat different in the days when this was written. Nice to see we're evolving at least 🙂 StringGrid.RowCount := StringGrid.RowCount + 1; StringGrid.TopRow := StringGrid.RowCount - StringGrid.VisibleRowCount; StringGrid.Row := StringGrid.RowCount - 1; Embarcadero issue number : RSP-42421 Edited October 4, 2023 by dormky Share this post Link to post
Stano 143 Posted October 4, 2023 A pair of .BeginUpdate; and .EndUpdate; commands won't help? Share this post Link to post
Pat Foley 51 Posted October 4, 2023 (edited) Why are you changing the rowcount it's done for you when you add a row? Here's an example of updating/overwriting all the cell's each UI update in case old information became stale! The SG column count is the Magic number 16 or the number of double fields in "atom". When the atom count is increased the SG Row count is bumped if needed. There's a Conway's game of life in the /samples that may yield better results. procedure TForm1.updateSG; var ii, R, C: integer; fPointer: Pdouble; //was^ not P begin for ii := 0 to Atoms.Count - 1 do begin C := 2 + ii mod 16; R := 3 + ii div 16; fPointer := Pdouble(Atoms.Objects[ii]); Screen2.StringGrid1.Cells[C, R] := format('%2.1f',[FPointer^]); end; Here's more modern example in a customized generic class (TList<PApp>) that has a SG assigned to it. Here the SG in a form some where gets its rowcount touched when needed. In the UI clicking on SG causes that row's app to surface even on a different desktop. procedure TptrApps.updateSG(inTool: ptrApp; inRow: Integer); begin if sgGrid.RowCount < inRow then sgGrid.RowCount := inRow + 1; var i := InRow; sgGrid.Cells[0, i] := inTool.Name;//sFirstTime; sgGrid.Cells[1, i] := inTool.Title; sgGrid.Cells[2, i] := inTool.ClassName; sgGrid.Cells[3, i] := inTool.Used.ToString; ///sgGrid.Cells[4, i] := inTool.sTime; sgGrid.Cells[5, i] := inTool.sVersion; end; Edited October 4, 2023 by Pat Foley add increase count example Share this post Link to post
dormky 2 Posted October 6, 2023 @Stano Yes, but that would just hide the underlying problem 😕. Still, always a good idea to use BeginUpdate & EndUpdate to make UI changes 🙂 @Pat Foley I've never seen an AddRow or equivalent function for StringGrid in Vcl. Plus, "doing it for me" wouldn't actually stop the problem from occuring. Share this post Link to post
Pat Foley 51 Posted October 6, 2023 So, in short you could use Toprow first visible row. The example adds an event to allow a progress bar to move with the grid as rows are used. The example sets the rowcount at 3600 then "adds" commatext. But I will admit I was thinking about a stringlist. procedure SGAdjustView(Sender: TObject; const AIndex: Integer; PB: TProgressBar); begin if Sender is TStringGrid and (AIndex > 4) then with (Sender as TStringGrid) do begin TopRow := AIndex - 4; end; PB.Position := AIndex; end; procedure TbaseMainForm.AddrowClick(Sender: TObject); begin var LIndex := 0; var pastTick := GetTickCount64; SG.Rows[0].CommaText:= ('RowCount,Index,Time'); SG.RowCount := 60 * 60;//seconds in minutes per hour ProgressBar1.Max := SG.RowCount; while LIndex < (120 * 30) do begin Inc(LIndex); SG.rows[Lindex].CommaText :=(SG.RowCount.ToString +',' + LIndex.ToString +',' + (GetTickCount64 - pastTick).ToString); SGAdjustView(SG, Lindex, ProgressBar1); // moves the view each by calling event outside begin..end end; end; Share this post Link to post