Index out of range with .StringToColumnStates

I have a TAdvStringGrid bound to a database table that I'm trying to preserve user changes to column widths. When I use the column state functions I'm getting a "List index out of bounds (1)" error message. This occurs even if I try to re-apply the exact string returned by the .ColumnStatesToString function:
  SettingsTBL.Open;
  SettingsTBL.Filtered:=false;
  SettingsTBL.Filter:='[Setting] = '+quotedstr('subjtests_columnsettings');
  SettingsTBL.Filtered:=true;
  if(SettingsTBL.RecordCount>0)
  then begin
       SettingsTBL.Append;
       SettingsTBL.FieldByName('Setting').AsString:='subjtests_columnsettings';
  end;
  ColumnSettingsStr:=subjecttests_grid.ColumnStatesToString;
  SettingsTBL.FieldByName('Value').AsString:=ColumnSettingsStr;
  SettingsTBL.Close;
  subjecttests_grid.StringToColumnStates(ColumnSettingsStr);
<- This is where error occurs
The string looks like this: 15#37,64,64,64,64,64,64,64,64,64,64,64,64,64,122#0#1,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Have also tried to use ColumnSize, which appears to save the widths in an ini file when program closes but does not restore widths.

Any suggestions or comments would be appreciated!

At the moment your grid has the default column settings, do you first call grid.SetColumnOrder before than using the StringToColumnStates , ColumnStatesToString functionality?

SetColumnOrder sets the reference default column order/visibility.

Hi guys.  I am getting this exact same error.  Everything works to the first time, but the second time (when the user performs a different search and I rerun my query and repopulate the grid) it fails.  Same code; second pass.  I have tried to add .Clear() and .ResetColumnSortOrder().  The exception is thrown during .ResetColumnSortOrder().


Here is my code, which fails on .StringToColumnStates if I remove the .Clear() and .ResetColumnOrder(), but as-is, fails on .ResetColumnOrder():


	// save user column positions and widths
	if (recomFollowupQuery->Active) {
		ReportHeaderForm->followupGridCols = followupResultsGrid->ColumnStatesToString();
	}


	recomFollowupQuery->Active = false;
	followupResultsGrid->Clear();
	followupResultsGrid->ResetColumnOrder();


	followupResultsGrid->RemoveAllColumns();


	recomFollowupQuery->SQL->SetText(sql.w_str());
	recomFollowupQuery->ParamByName("DECLINEDBEFORE")->AsDate = ReportHeaderForm->declinedBefore->DateTime;
	recomFollowupQuery->ParamByName("DECLINEDAFTER")->AsDate = ReportHeaderForm->declinedAfter->DateTime;


	recomFollowupQuery->Active = true;


	followupResultsGrid->SetColumnOrder();


	// restore user column positions and widths
	if (ReportHeaderForm->followupGridCols.Length()) followupResultsGrid->StringToColumnStates(ReportHeaderForm->followupGridCols);


I've had this index out of bounds error many times in the past year using TDBAdvGrid.  Can we catch this in the grid code and throw better errors... Something like: "Your column restore string contains 50 rows but the grid only contains 0.  Try loading the grid first."  I also get this if we ship a product rev. X to a client, which stores strings from the TDBAdvGrid and then product rev. X+1 adds a new query column.  Very strange results.  It would be nice if TDBAdvGrid overrode the AdvStringsGrid and saved DatabaseFieldNames in the save string instead of column numbers, or some other nice solution to this problem.  Anyway, thanks for a great product and for always great support.

Hey guys.  I have found a solution/workaround for my code, at least.  Wanted to post so it might give others a fix or might give you an idea what might need fixing in the grid code.


If I add:

	followupResultsGridd->FilterActive = false;

Immediately after the .Clear() call, and remove the .ResetColumnOrder() and .RemoveAllColumns() calls, I don't get the exception.

ResetColumnOrder() causes a grid that is not in default order (i.e. at the time SetColumnOrder() was called), to reorganize its columns to bring it back to default order. Here, you set your dataset inactive, so columns & data are removed from the grid, so calling ResetColumnOrder() doesn't make sense anymore.
So, did you try with just removing the call to ResetColumnOrder()?

I retried using .SetColumnOrder before saving and before retrieving the column string. Did not properly restore but saw hint - columns are being marked as hidden that are not. I manually edited string saved in database (setting all 0 to 1) and that appears to allow column resizing to work.

Not sure what caused the incorrect hidden marked columns. If a problem persists, can you please provide detailed steps with which we can reproduce this issue here so we can investigate?

Hi Bruno,


I only added ResetColumnOrder() to try to fix the problem.  It wasn't there to begin with.  The problem always manifests itself for me in this scenario:

TAdvDBGrid connected to a TDataSet connected to a TQuery
grid PageMode: false

// Try to Run the Report
Set TQuery Active to false
call grid Clear()
call grid RemoveAllColumns()
set TQuery SQL
set TQuery to Active to true
call grid SetColumnOrder()
call grid StringToColumnStates()
Add Filters to grid.

Everything works fine to this point.  Columns are restored from previous save.  Life is grand.

The Index out of bounds error comes when you try to do either:

1) jump to the // Try to Run  the Report, comment above.  This happens for us when the user changes their search criteria and we need to re-perform the query to the database.  This fails with the Index out of bounds error on StringToColumnStates.

What fixes the issue for me is to add:

a call to grid FilterActive = false;

None of our other TAdvDBGrid instances exhibit this problem, but they are not using filters on the grid.

2) Another way to get this error is to re-run the report and change the SQL to include an additional column to the query and attempt to call StringToColumnStates with a buffer saved from a grid populated with data from SQL without that additional column.

Nothing I know fixes this.  This might seem stupid to do...  But we run into this problem all the time because we save the ColumnStatesToString to the registry and reload on next run of our software.  Fine.  But, when we release a new version of our software which includes an additional column in our result set, all of our users get this error because the grid now includes an additional column and the saved string from the previous version isn't compatible.

Hope this help narrow down the issue and also give you a use case worthy to consider a fix.  Thank you for your support and a great product!

Troy




When you start a new query, will that query return the same set of fields as the query with which ColumnStatesToString() was called? For ColumnStatesToString() and StringToColumnStates() to work, it is of course necessary it concerns the same nr. of columns that is being added to the grid.

Back to the original post - I was able to get a workaround for the hidden columns by having the program get the column string then change the string after the last '#' to all 1s. When I do that I'm able to restore column settings between runs.

Yes Bruno, in case 1.


Case 2 is the problem you've described: restoring columns from a string obtained from a query with less columns.  Please read our use case in case 2 to understand why we run into this.

Regarding case 1, the query returns the same number of columns when re-run and still gives the error.

Please isolate and provide some sample source app with which we can reproduce this issue here. This is the most efficient way to have a detailed & complete view on what you do in the app and either suggest how to handle it correct or find a fix (when needed)

Troy
Have you looked at the string that ColumnStateToString returns? Do you see 0s in the terminal third as I indicated in my post? If so try replacing the 0s with 1s and see if the index error disappears.

You might also be able to modify the string to deal with the new query issue, removing or inserting elements in each of the three sections to match new number of columns. Assume there's some similarity that between the columns in the two queries even if number of column changes.
Neil