4
votes

I googled and found a lot of advice, but it all seemed several years old and none of it helped.

I have a string grid with 8 columns and once I get more than a few hundred rows it is taking over 2 seconds to populate (I compared using GetTickCount).

I tried StringGrid.Perform(WM_SETREDRAW, 0, 0) (and 0, 1 at the end). I tried setting Visible := False while updating. Both to no use.

There is no BeginUpdate() method.

Any advice? Delphi XE2 starter. I would be willing to use a FOSS 3rd party VCL string grid if it is tried & tested.


[Update] using TDrawGrid ... "A TDrawGrid doesn't have a property "Cells", like its brother TStringGrid. Your code has to calculate where to display the data and next it must draw a representation of the data on the "Canvas" of the grid."

That sounds like a lot of work to me :-(

Using VirtualTreeView - sounds ok if it is fast enough. I just won't have any child nodes. (update++ I just read this on the homepage "Virtual Treeview is extremely fast. Adding one million nodes takes only 700 milliseconds"). No problems on speed, then. But it woudl nice to just use a string grid. Escpecially one where the user can click & sort.

Alternatively, the stringgrid is only 20 rows high. Maybe I could just handle scrolbar clicks and clear & repopulate those 20 rows when the user scrols?

[Furtehr update] I changed from TStringGrid to TListView which codes have Beginupdate()), but that made a negligible difference. Ops, I forgot "viortual mode" - brb.

Btw, the data are read-only, just for disply.

Surely this is a very common probem?

3
The best performance will be achieved by changing your TStringGrid into a virtual grid, e.g. a TDrawGrid in virtual mode, which will retrieve the cells content via an Event from a separated data list. It will be much faster than this IMHO. I use TDrawGrid with thousands of rows with instant access, e.g. for our log viewer - For instance, a 280 MB log file is opened in less than one second on my laptop. Under Seven, it takes more time to display the "Open file" dialog window than reading and indexing the 280 MB content.Arnaud Bouchez
Instead of TDrawGrid you may learn VirtualTreeView. It's not just a tree view as it sounds to be ;-)TLama
Every control using virtual mode will give you a better performance than TStringGrid. It's not possible to compare TDrawGrid with VirtualTreeView just because they looks different, but both will be more efficient than TStringGrid, that's for sure. I've suggested you VirtualTreeView from my personal preference and because you can do much, much more things than with TDrawGrid. But if you really need just an old looking grid with very basic functionality, TDrawGrid might be sufficient for you.TLama
@Mawg, could you tell us for what purpose are you using TStringGrid in this case - is it for displaying or editing data? If you only need to display data, then even TListView should give you more than sufficient performance gains, and if you use it in "virtual mode" you will gain even more. However, I have to agree with @TLama about VirtualTreeView - it is simply the best component out there. I've stopped using TStringGrid a long time ago and I've never looked back.LightBulb
In response to your edit: putting the data in a memory client dataset and showing it by a DBGrid - which 'loads' only the visible rows - might also better perform.NGLN

3 Answers

2
votes

Adding to others suggesting a virtual string grid I'd like to plug TdzVirtualStringGrid which builds on a TDrawGrid and adds events to return the strings to display. I am using it for very "large" grids and it works fine.

Download it here.

(You need more files from the same repository, this is just the main component source code.)

EDIT: By "more files from the same repository" I mean, that this component uses other units from the dzlib library, so you should probably check out the whole shebang and either add it to your program's search path (there is a lot more useful stuff in there, because I add to it whenever I come across something that needs a more generalized solution) or just extract those units which the component depends on. dzlib is licensed under MPL.

5
votes

Add rows from bottom to top, and/or set RowCount afterwards. I just did a little test adding 90.000 rows, gaining ca. 25% in speed.

Though, this takes 1,5 seconds at most. Since you are talking about just a few hundred rows, I am sure populating the grid is not the burden here. Instead the time needed to retrieve and/or convert the data seems to be.

5
votes

There is no BeginUpdate() method.

TStringGrid does have BeginUpdates: you need to access it via either the Rows[] or Cols[] arrays of TStrings, though for adding new data, using the Cols[] array makes most sense:

for i := 0 to Grid.ColCount - 1 do
begin
  Grid.Cols[i].BeginUpdate;
  try
    //Add row data
    for j := 1 to Grid.RowCount - 1 do
      Grid.Cols[i][j] := ...;
  finally  
    Grid.Cols[i].EndUpdate;
  end;
end;

I'm sure I've used this before with an increase in speed noted.