Jump to content
dormky

Augmenting RowCount resets scroll position

Recommended Posts

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 by dormky

Share this post


Link to post

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 by dormky

Share this post


Link to post

A pair of .BeginUpdate; and .EndUpdate; commands won't help?

Share this post


Link to post

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 by Pat Foley
add increase count example

Share this post


Link to post

@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

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

 

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×