Author Topic: Using TStringgrid for showing data  (Read 677 times)


  • Hero Member
  • *****
  • Posts: 1112
Using TStringgrid for showing data
« on: April 14, 2020, 12:51:09 pm »
From my topic of listview, I'm trying to use TStringgrid.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.formcreate;
  2. begin
  3.   Createcolumns(fDataset)
  4. end;
  6. procedure Tform1.Createcolumns(aDs : TDataset);
  7. var index  : integer;
  8. begin
  9.   sgrid.ColCount := fdataset.FieldDefs.Count + 1;
  10.   for index := 0 to aDs.FieldDefs.Count - 1 do
  11.     sgrid.Columns[index].Title.Caption := aDs.FieldDefs[index].DisplayName;
  12. end;
This code should create a few columns in stringgrid and change the title.
But no columns are created (showmessages shows 0) and a error occured:
Project project1 raised exception class 'EListError' with message:
List index (0) out of bounds
[Break] [Continue]
But when the form is activated, the actual called columns are on screen.

Nice. This is working and fits also the width of a cell:
Code: Pascal  [Select][+][-]
  1. procedure Tform1.Creatcolumns(aDs : TDataset);
  2. var index, index2  : integer;
  3.     Column   : TGridColumn;
  4.     Value    : string;
  5. begin
  6.   for index := 0 to aDs.FieldDefs.Count - 1 do
  7.   begin
  8.     Value := '';
  9.     Column := TGridColumn.Create(SGrid.Columns);
  10.     Column.Title.Caption := aDs.FieldDefs[index].DisplayName;
  11.     if aDs.FieldDefs[index].DataType = ftstring then
  12.     begin
  13.       for index2 := 1 to aDs.FieldDefs[index].Size do
  14.         Value := Value + 'D';
  15.       Column.Width := sgrid.canvas.TextWidth(Value);
  16.     end;
  17.   end;
  18.   sgrid.ColWidths[0] := 15;
  19. end;
The last line of code changes the width of the fixes column. The fixed column is not a part of TGridcolumns.

The easiest way to fill the cells is using procedure InsertRowWithValues(index, array of string).
This procedure doesn't look if a fixed row is displayed, so the first cell of the index row is used.
That's not correct. To get a workaound you have create a first empty array parameter:
Code: Pascal  [Select][+][-]
  1. procedure Tform1.FillGrid(aDs : TDataset);
  2. var Game : TGame;
  3.     index : integer;
  4. begin
  5.   index := 1;
  6.   for Game in fGames do
  7.   begin
  8.     sgrid.InsertRowWithValues(index,['',game.Name,game.TypeofGame,game.NumberofPlayers,game.Duration.ToString]);
  9.     index := index + 1;
  10.   end;
  11. end;
If you use InsertRowWithValues with index = 0 and sequentially fill the rows a new fixed row will be created.
I think it's a bug.

Using Alternatecolor gives every even row another color. That's nice.

The only thing I can't get right is the selection bar of a cell when option dgRowselected is false. THe selectbar is like
a dit read retangle. Is it posible to get it filled like DBGrid?
« Last Edit: April 14, 2020, 12:53:23 pm by mangakissa »
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1


  • Full Member
  • ***
  • Posts: 189
Re: Using TStringgrid for showing data
« Reply #1 on: April 14, 2020, 01:28:15 pm »
Use Grid.Columns.Add

"Additionally, when using custom columns, the grids do not allow direct modification of grids.colcount; adding or removing columns should be done using the columns property. The explanation is that there is an inconsistency on gradually removing custom columns using ColCount, when ColCount reaches FixedCols, the grid has no more custom columns. If we now increase ColCount, the new column will not be a custom column but a normal column."

Started with OmegaSoft Pascal on OS-9/68k , now Lazarus 2.0.8 / FPC 3.0.4 on Windows 7


  • Hero Member
  • *****
  • Posts: 8096
Re: Using TStringgrid for showing data
« Reply #2 on: April 14, 2020, 01:43:56 pm »
I rarely use Columns in a StringGrid because the introduce some ugly indexing issue: The column indexes in StringGrid.Cells[col, row] refer to the top/left corner of the grid, but the index of the Columns collection refers to the first column after the fixed column.

Without Columns the number if columns is defined by setting the ColCount property. The width of a column is defined by changing ColWidths[col], the title by setting Cells[col, 0]. All cells are left-aligned by default, but you can override the OnPrepareCanvas to change alignment immediately before drawing.

With Columns you must "add" each column to the Columns collection which automaticall creates the column - see wiki Having Columns you can change the column width, title and text alignment by setting the corresponding properties of each column.

You mix both approaches.

I never use InsertRowWithValues to fill a row - in fact, I am only very dimly aware that is exists. I think it is only useful when the total count of rows is not known a priori. I simply set the RowCount from the datasets.RecordCount and then write the cell text into the Cells property.

For getting a filled selection rectangle you must set the option goDrawFocusSelected. Another option that I frequently set is goThumbtracking which makes the grid immediately follow the scrollbar. And I always prefer MouseWheelOption mwGrid over the default because the mouse wheel scrolls the grid, not the active cell this way which appears to me much more user-friendly.

I am attaching a modified version of your code without using columns - just to show you. Of course, using columns is not wrong.
« Last Edit: April 14, 2020, 01:47:28 pm by wp »
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...


  • Hero Member
  • *****
  • Posts: 1112
Re: Using TStringgrid for showing data
« Reply #3 on: April 14, 2020, 02:40:09 pm »
thank you fred and wp
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1


TinyPortal © 2005-2018