2

I'm making a simple application in Delphi XE2 which uses specifically the "Carbon" style. There's a large String Grid which has thousands of rows. I have a process which loops through the records of this grid, does some work, and makes some changes in the grid. As the process loops, the row which is being currently processed gets highlighted (by setting TStringGrid.Row).

The problem is that when I apply the style to this grid, the scroll bar doesn't change position as the row is changed. The loop does properly highlight each row as it's being processed, but by the time it gets towards the end of the list, the scroll bar on the right is still all the way at the top.

How do I make the grid's scroll bar move along with it?

Here's a sample of how I'm looping:

procedure TForm1.Button1Click(Sender: TObject);
var
  X: Integer;
begin
  FStop:= False;
  for X:= 1 to Grid.RowCount - 1 do begin
    if FStop then Break; //Ability to stop loop
    Grid.Row:= X; //Highlight current row
    DoSomeLenghyWork;
    ChangeSomethingOnGrid;
    Application.ProcessMessages; //Keep program responding
  end;
end;

Everything works just fine when I'm not using any styles.

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • 1
    This sounds like a bug to me. `Invalidate` is the way to force a paint cycle. I think I'd be inclined to do the processing in the background and use a virtual control (e.g. list view in virtual mode) to update UI. Update the UI on a timer, e.g. every second. – David Heffernan Feb 11 '12 at 20:15
  • I am converting it to process each item in a thread anyway, and am putting messages for various events. I can have one `MSG_BEGIN`, `MSG_END`, `MSG_NEXT`, `MSG_ERROR` etc. – Jerry Dodge Feb 11 '12 at 20:26
  • You should have a thread to do the work and then run a timer in the main thread to get the UI updates. Use a virtual list view to display. Syncronisation with a lock is probably sufficient. – David Heffernan Feb 11 '12 at 20:27
  • VirtualTreeView would be far better (working as a virtual grid in this case) than TStringGrid. – Warren P Feb 14 '12 at 16:32

2 Answers2

2

This worked for me - it forces windows to repaint the border area of the StringGrid:

SetWindowPos(Grid.Handle, 0, 0, 0, Grid.Width, Grid.Height, SWP_DRAWFRAME);
Flexo
  • 87,323
  • 22
  • 191
  • 272
njd
  • 21
  • 1
2
  1. If invalidate and repaint don't do anything for you, try resizing the string grid:

    Grid.Width := Grid.Width - 1; Grid.Width := Grid.Width + 1;

  2. Try playing with the string grid options that hide and show the scrollbars. Hide them before you update and show them after. Perhaps that will force them to repaint.

  3. Try moving the scroll position and moving it back to the original position.

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • Thanks, will do when back in office. #1 won't work because the grid is aligned alClient (can't change width without changing its parent's width). Plus that seems like a last resort quick-fix :P Other ones are worth a go. – Jerry Dodge Feb 11 '12 at 19:40
  • I wound up temporarily hiding the scrollbar during the loop (#2). I'm sure there's a trick however to make this work right. – Jerry Dodge Feb 11 '12 at 21:05
  • You could turn off alClient (align=alNone and then alClient) but that will flicker for sure. So instead, leave align always alNone, and set the anchors instead. THat workaround is specifically useful for VCL grid scroll bugs. – Warren P Feb 12 '12 at 03:10