Recent

Author Topic: [SOLVED] TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream  (Read 1662 times)

Vodnik

  • Full Member
  • ***
  • Posts: 212
I'm trying to hide a column of TStringGrid.
If TStringGrid is created at design time, there is no problem:
Code: Pascal  [Select][+][-]
  1. StringGrid1.Columns[2].Visible:=False;
But when grid content is loaded at runtime:
Code: Pascal  [Select][+][-]
  1. StringGrid1.LoadFromCSVStream(SS,',',true,0,true);
the same string causes "out of bounds" error.
Well, grid is displayed fine, but StringGrid1.Columns.Count is 0.
Test project is attached. What I'm doing wrong?
 
« Last Edit: December 03, 2023, 10:46:21 pm by Vodnik »

wp

  • Hero Member
  • *****
  • Posts: 12476
Re: TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #1 on: December 03, 2023, 10:23:26 pm »
The Lazarus StringGrid can work with columns, unlike Delphi, and your code seems to do that because you access the column with index 2. However, this is not the default mode - normally TStringGrid has no column classes, and you must explicitely add Columns to activate this mode.

When you load data from a csv file into an empty grid it basically is not clear whether columns should be created or not. The grid does a simple check to make a decision: If there is at least one column it will read the files into a "column-aware" grid, otherwise into a normal grid.

So, all you have to do is to create one column before calling LoadCSVFile. Then this method will create the other columns automatically:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. var SS: TStringStream;
  3.      I: Integer;
  4. begin
  5.   SS:=TStringStream.Create;
  6.   SS.LoadFromFile('StringGrid.csv');
  7.   with TStringGrid.Create(Form1) do begin
  8.     Parent:=Form1;
  9.     ...
  10.     Columns.Add;              // <--- ADDED
  11.     LoadFromCSVStream(SS,',',true,0,true);
  12.     ...
  13.   end;
  14.   SS.Free;
  15. end;

Vodnik

  • Full Member
  • ***
  • Posts: 212
Re: TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #2 on: December 03, 2023, 10:45:52 pm »
Thank you for the explanation, @wp!
This is a non-evident trick for me.

wp

  • Hero Member
  • *****
  • Posts: 12476
Re: TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #3 on: December 03, 2023, 11:37:00 pm »
Thank you for the explanation, @wp!
This is a non-evident trick for me.
I did not know it either. Let me show you how I found out: I added a custom option "-gw3" (without quotes) to "Additions and overrides" in the project options which allows me to debug into LCL and third-party units. With the debugger, I stepped into LoadFromCSVStream, and saw in the nested function NewRecord a call to Columns.Add which confirms that LoadFromCSVStream, in fact, is able to add columns. But there is an "if Columns.Enabled" before that. A Ctrl-Click on this "Enabled" leads to the TGridColumns property Enabled. It does not have a setter function and thus cannot be activated immediately. But the property getter function "GetEnabled" (another Ctrl+Click) tells that Enabled is true when another property, VisibleCount, is true. And the getter of VisibleCount simple returns the Count of the Columns collection. Then it was clear: Add a column to make Columns.Count <> 0.

Added a note to the grids wiki page: https://wiki.freepascal.org/Grids_Reference_Page#procedure_LoadFromCSVFile.28AFileName:_string.3B_ADelimiter:Char.3D.27.2C.27.3B_WithHeader:boolean.3Dtrue.29.3B

dsiders

  • Hero Member
  • *****
  • Posts: 1291
Re: TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #4 on: December 03, 2023, 11:44:11 pm »
Thank you for the explanation, @wp!
This is a non-evident trick for me.
I did not know it either. Let me show you how I found out: I added a custom option "-gw3" (without quotes) to "Additions and overrides" in the project options which allows me to debug into LCL and third-party units. With the debugger, I stepped into LoadFromCSVStream, and saw in the nested function NewRecord a call to Columns.Add which confirms that LoadFromCSVStream, in fact, is able to add columns. But there is an "if Columns.Enabled" before that. A Ctrl-Click on this "Enabled" leads to the TGridColumns property Enabled. It does not have a setter function and thus cannot be activated immediately. But the property getter function "GetEnabled" (another Ctrl+Click) tells that Enabled is true when another property, VisibleCount, is true. And the getter of VisibleCount simple returns the Count of the Columns collection. Then it was clear: Add a column to make Columns.Count <> 0.

Added a note to the grids wiki page: https://wiki.freepascal.org/Grids_Reference_Page#procedure_LoadFromCSVFile.28AFileName:_string.3B_ADelimiter:Char.3D.27.2C.27.3B_WithHeader:boolean.3Dtrue.29.3B

It is documented at https://lazarus-ccr.sourceforge.io/docs/lcl/grids/tcustomstringgrid.loadfromcsvstream.html, but I'm always open to ways topics can be improved.
Preview the next Lazarus documentation release at: https://dsiders.gitlab.io/lazdocsnext

wp

  • Hero Member
  • *****
  • Posts: 12476
Re: TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #5 on: December 04, 2023, 12:34:35 am »
Thank you for the explanation, @wp!
This is a non-evident trick for me.
I did not know it either. Let me show you how I found out: I added a custom option "-gw3" (without quotes) to "Additions and overrides" in the project options which allows me to debug into LCL and third-party units. With the debugger, I stepped into LoadFromCSVStream, and saw in the nested function NewRecord a call to Columns.Add which confirms that LoadFromCSVStream, in fact, is able to add columns. But there is an "if Columns.Enabled" before that. A Ctrl-Click on this "Enabled" leads to the TGridColumns property Enabled. It does not have a setter function and thus cannot be activated immediately. But the property getter function "GetEnabled" (another Ctrl+Click) tells that Enabled is true when another property, VisibleCount, is true. And the getter of VisibleCount simple returns the Count of the Columns collection. Then it was clear: Add a column to make Columns.Count <> 0.

Added a note to the grids wiki page: https://wiki.freepascal.org/Grids_Reference_Page#procedure_LoadFromCSVFile.28AFileName:_string.3B_ADelimiter:Char.3D.27.2C.27.3B_WithHeader:boolean.3Dtrue.29.3B

It is documented at https://lazarus-ccr.sourceforge.io/docs/lcl/grids/tcustomstringgrid.loadfromcsvstream.html, but I'm always open to ways topics can be improved.

You're right. Users (including myself) should read documentation first... It is always surprising to see how much the official documentation has improved recently.

However, the statement "if Columns is enabled" is not very clear. Yes, the link into TGridColumns finally explain that this is true when "VisibleCount contains a value greater than 0", but requires some clicking and also leaves questions: What is "VisibleCount"? What when all columns have been scrolled out of the grid's window? In the code, VisibleCount simply is Count. So, I'd propose the replace that "VisibleCount" by "Count", or "VisibleCount (=Count)".

As for "if Columns is enabled" I'd also propose to modify this to "if Columns is enabled (i.e. Columns.Count <> 0)"

dsiders

  • Hero Member
  • *****
  • Posts: 1291
Re: TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #6 on: December 04, 2023, 02:43:12 am »
Thank you for the explanation, @wp!
This is a non-evident trick for me.
I did not know it either. Let me show you how I found out: I added a custom option "-gw3" (without quotes) to "Additions and overrides" in the project options which allows me to debug into LCL and third-party units. With the debugger, I stepped into LoadFromCSVStream, and saw in the nested function NewRecord a call to Columns.Add which confirms that LoadFromCSVStream, in fact, is able to add columns. But there is an "if Columns.Enabled" before that. A Ctrl-Click on this "Enabled" leads to the TGridColumns property Enabled. It does not have a setter function and thus cannot be activated immediately. But the property getter function "GetEnabled" (another Ctrl+Click) tells that Enabled is true when another property, VisibleCount, is true. And the getter of VisibleCount simple returns the Count of the Columns collection. Then it was clear: Add a column to make Columns.Count <> 0.

Added a note to the grids wiki page: https://wiki.freepascal.org/Grids_Reference_Page#procedure_LoadFromCSVFile.28AFileName:_string.3B_ADelimiter:Char.3D.27.2C.27.3B_WithHeader:boolean.3Dtrue.29.3B

It is documented at https://lazarus-ccr.sourceforge.io/docs/lcl/grids/tcustomstringgrid.loadfromcsvstream.html, but I'm always open to ways topics can be improved.

You're right. Users (including myself) should read documentation first... It is always surprising to see how much the official documentation has improved recently.

However, the statement "if Columns is enabled" is not very clear. Yes, the link into TGridColumns finally explain that this is true when "VisibleCount contains a value greater than 0", but requires some clicking and also leaves questions: What is "VisibleCount"? What when all columns have been scrolled out of the grid's window? In the code, VisibleCount simply is Count. So, I'd propose the replace that "VisibleCount" by "Count", or "VisibleCount (=Count)".

As for "if Columns is enabled" I'd also propose to modify this to "if Columns is enabled (i.e. Columns.Count <> 0)"

Good suggestions. I'll apply them in my next update.
Preview the next Lazarus documentation release at: https://dsiders.gitlab.io/lazdocsnext

dsiders

  • Hero Member
  • *****
  • Posts: 1291
Re: TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #7 on: December 04, 2023, 08:10:03 am »
Good suggestions. I'll apply them in my next update.

Updated in commit cc813766cc if you would like to review.
https://gitlab.com/freepascal.org/lazarus/lazarus/-/commit/a9a62d33f8aed5a55e5174558ccda98ffd0c78bc
Preview the next Lazarus documentation release at: https://dsiders.gitlab.io/lazdocsnext

Vodnik

  • Full Member
  • ***
  • Posts: 212
Re: [SOLVED] TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #8 on: December 04, 2023, 08:50:06 am »
Thank you for this discussion, @wp and @dsiders!
When one is designing a trivial application using high-level LCL components, he may not expect deep debugging into component source code. I always try first to find something documented before investigating the source code, which is not easy for me. I saw document mentioned by @dsiders, but didn't catch the real meaning of Columns enabled. Now it's more clear, thanks. A bit confusing for me was that there is procedure DeleteCol(), which works with normal grids, too. So I can delete column, but can't hide it. If normal grids are prefered, maybe there is some (easy) way to hide/show column without enabling Columns?

wp

  • Hero Member
  • *****
  • Posts: 12476
Re: [SOLVED] TStringGrid.Columns.Count=0 after TStringGrid.LoadFromCSVStream
« Reply #9 on: December 04, 2023, 11:03:07 am »
You could set the ColWidths of that particular column to zero. Keyboard navigation will jump over columns with zero width.

 

TinyPortal © 2005-2018