Recent

Author Topic: OnDraw problem with TStringGrid  (Read 6482 times)

kalagan

  • Newbie
  • Posts: 3
OnDraw problem with TStringGrid
« on: October 05, 2011, 06:59:49 pm »
Hi all,
I have a little problem with my application under Win32 (Laz 0.9.30 + FPC 2.4.2).

I have a dynamic array of packed record. The structure is this:
Code: [Select]
  TRecord = packed record
              Description:ansistring;
              DT:tdatetime;
              Component:string;
            end;
  TDataRec= array of TRecord;
var
  datarec: TDataRec;
This array can be very big (about 1.000.000 of record). And I need to show its content in a TStringGrid.

My first attempt was to populate each cell with a loop:
Code: [Select]
StringGrid1.rowcount:=length(datarec)+1; //for header...
for c:=0 to high(datarec) do
begin
  StringGrid1.cells[0,c+1]:=datarec[c].description;
  ...
end;

But this approch has 2 problems:
1. it takes about 6-7 seconds to complete
2. the application eats about 600MB in ram

So, considering a user can display only few records at a time, I  tried to populate the grid only for records that are visible on the screen. To achive this I used OnDrawCell event.
Something like this:
Code: [Select]
procedure TForm1.StringGrid1DrawCell(Sender: TObject; aCol, aRow: Integer;
  aRect: TRect; aState: TGridDrawState);
var
  MyTextStyle:TTextStyle;
begin
  MyTextStyle := StringGrid1.Canvas.TextStyle;
  MyTextStyle.SingleLine := false;
  StringGrid1.Canvas.TextStyle := MyTextStyle;
  if arow>0 then //stringgrid1 has length(datarec)+1 as rowcount, and row 0 is header
    case acol of
        0: stringgrid1.Canvas.TextRect(aRect,aRect.Left+6,aRect.Top,formatdatetime('yyyy-mm-dd hh:nn:ss.zzz',DataRec[arow-1].DT));
        1: stringgrid1.Canvas.TextRect(aRect,aRect.Left+6,aRect.Top,DataRec[arow-1].Component);
        2: stringgrid1.Canvas.TextRect(aRect,aRect.Left+6,aRect.Top,DataRec[arow-1].Description,mytextstyle);
    end;
end;

In this way: the load time is few milliseconds and the ram used by stringgrid is about 20MB because I do not write on each cell but "draw" a cell with text. (Perhaps it is possble to optimize it with a lower number of rows, about 100, and using a TScrollbar to move to a different position).

But my problem is that after the grid is populated, the application eats 100% cpu and become irresponsive. The same happens if I write directly to cells with StringGrid1.cells[acol,arow]:=...
and also if I use OnPrepareCanvas event.

So I have 2 questions:
1. What is wrong in my code? Why I cannot "draw" text in OnDrawCell event?
2. Is this approach correct? Does anybody know a different method to load a large amount of data in a stringgrig, without actually populate every cell?

Thanks in advance.

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: OnDraw problem with TStringGrid
« Reply #1 on: October 05, 2011, 07:18:54 pm »
Quote
2. Is this approach correct? Does anybody know a different method to load a large amount of data in a stringgrig, without actually populate every cell?
You can have something like:

Code: [Select]
TMyData = packed record
  description: string;
  data: byte;
end;

var mydata: array of TMyData;
...
setlength(myData, NumOfMyRecords);
// Load data to the array...
Then on form you can have a TStringGrid with no scrollbars.
Scrolling can be handled with a separate TScrollBar.

In the onScroll event call your written UpdateStringGrid method which updates stringgrid with records from [ScrollBar.Position to ScrollBar.Position+stringgrid.RowCount-2], if row[0] is reserved for fixed title.

This way you don't need a custom onDraw, but you have to handle StringGrid's onResize event to accommodate changed visible rowcount.
« Last Edit: October 05, 2011, 07:20:38 pm by User137 »

jesusr

  • Sr. Member
  • ****
  • Posts: 499
Re: OnDraw problem with TStringGrid
« Reply #2 on: October 05, 2011, 08:39:49 pm »
So I have 2 questions:
1. What is wrong in my code? Why I cannot "draw" text in OnDrawCell event?
2. Is this approach correct? Does anybody know a different method to load a large amount of data in a stringgrig, without actually populate every cell?
Thanks in advance.

1. It's not all clear, you say you populate the grid, I understand "populate" as filling grid cell's with content, but the code in drawcell do not populate the grid, it only draw the text. Just drawing shouldn't be that slow. I think it's better if you could prepare a sample project and make it available someway.

2. If you already have the data, don't use a stringgrid, use a drawgrid which doesn't have cells, you have to use the drawcell event to show the data, just like shown in your drawcell handler. Or, make your data available through a dataset and use a dbgrid.


kalagan

  • Newbie
  • Posts: 3
Re: OnDraw problem with TStringGrid
« Reply #3 on: October 06, 2011, 12:26:47 pm »
First, thanks all for answers...

To jesusr: your answer (use a DrawGrid instead of a StringGrid) directed me to the right way, and now all works fine. Thanks!

 

TinyPortal © 2005-2018