HDPI TDBAdvGrid StringToColumnStates and ColumnStatesToString

There appears to be a HDPI problem with saving/restoring column states for TDBAdvGrid when using them on a frame. Here is a screen shot showing the problem I am having. I have a main form which dynamically creates frames on tabsheets containing a TDBAdvGrid and allows you to close them afterwards. I save and restore the column widths in an ini file. The screen shot shows the values saved and retrieved from the ini file when I create the frame and destroy it. I have not changed anything other than loading the data. I'll investigate it further on my side as perhaps it's a problem loading the data rather than these two functions but that is where I am seeing the problem so I wanted to run it by you in case you have any insight that might help.

What Delphi version do you use?
What is the DPI situation? DPI at time of saving? DPI at time of loading?

Delphi 11 Update 3 patch 1
Resolution is shown in the screenshot font scale 500% display resolution 7680 x 3240

I have updated my Delphi with the latest VCL UI pack 13.0.1.0

I suspect it is something I am doing wrong. I have a grid on a form that I am saving/restoring in a similar way and that works fine but I seem to remember their are issues with frames and HDPI. Please don't waste any time on it for now, I just thought it might have been a known issue with frames. I have to park this job for a bit anyway and it will be a week at least before I am back on it. Many thanks.

Ok, thanks for informing. Let us know if further investigation is needed.

Hi Bruno,
ColPersistDemo_2023-09-26.zip (26.9 KB)

Please find attached a demo application that shows the problem with frames and HDPI. I am running this on a Parallels VM. Display settings; Scale 500%, resolution 7680 x 3240. When I save/restore column states form a form it's fine but on a frame it multiplies it by 2 each time. Here is an extract from the log of the test app.

[26/09/2023 10:02:26][Value: Windows 11 (Version 22H2, OS Build 22621.2283, 64-bit Edition)][Type: string]
[26/09/2023 10:02:31][Trace][Value: ReadString( STATES,FORM ) = 10#40,128,128,128,128,128,128,128,128,128#0,1,9,2,3,4,5,6,7,8#1,0,1,1,1,1,1,1,1,1][Type: string][Type: string][Type: string]
[26/09/2023 10:02:37][Trace][Value: WriteString( STATES,FORM,10#40,128,128,128,128,128,128,128,128,128#0,1,9,2,3,4,5,6,7,8#1,0,1,1,1,1,1,1,1,1 )][Type: string][Type: string][Type: string]
[26/09/2023 10:02:40][Trace][Value: ReadString( STATES,FRAME ) = 10#40,128,128,128,128,128,128,128,128,128#0,1,9,2,3,4,5,6,7,8#1,0,1,1,1,1,1,1,1,1][Type: string][Type: string][Type: string]
[26/09/2023 10:02:42][Trace][Value: WriteString( STATES,FRAME,10#80,256,256,256,256,256,256,256,256,128#0,1,9,2,3,4,5,6,7,8#1,0,1,1,1,1,1,1,1,1 )][Type: string][Type: string][Type: string]

We have seen this issue. Sadly it seems tied to an underlying VCL problem.
(We expect you will see the same problem with getting and setting the column widths of a TStringGrid when used on a frame).
It is due to a different sequence of creating the frame and calling ChangeScale in this create process. We have not yet found a reliable workaround.
This might also change in a future Delphi version, so at this point, it is unsure what to do about this issue.

Thanks Bruno, that's helpful. After what you said I overridded the ScaleForPPI procedure and put the code to restore the column states in there and it appears to work. I only have one monitor now, so can't test what happens if you drag it on to another screen but I suspect it will just reset to what's saved in the ini file which again wouldn't be a problem. What do you think to this approach, do you think it is a reasonable workaround?

procedure TFrameDemo.RestoreColumnStates;
var
  inif: TINIFile;
  colstates: string;
  i: Integer;
  col: TDBGridColumnItem;
begin
  for i := 0 to ADOTable1.FieldCount - 1 do
  begin
    CheckListBox1.Items.Add( ADOTable1.Fields[ i ].FieldName );
    CheckListBox1.Checked[ i ] := true;
  end;

  DBAdvGrid1.SetColumnOrder;
  DBAdvGrid1.Options := DBAdvGrid1.Options + [ goColSizing, goColMoving ];

  inif      := TINIFile.Create( cSettingsIniPath );
  colstates := inif.ReadString( cSection, cIdentFrame, '' );
  TMSLogger.TraceFormat( 'ReadString( {%s},{%s} ) = {%s}', [ cSection, cIdentFrame, colstates ] );
  inif.Free;

  if colstates <> '' then
      DBAdvGrid1.StringToColumnStates( colstates );

  for i := 0 to ADOTable1.FieldCount - 1 do
  begin
    col := DBAdvGrid1.ColumnByFieldName[ CheckListBox1.Items[ i ] ];
    if DBAdvGrid1.IsHiddenColumn( col.Index ) then
        CheckListBox1.Checked[ i ] := false;
  end;
end;

procedure TFrameDemo.ScaleForPPI( NewPPI: Integer );
begin
  inherited;
  RestoreColumnStates;
end;
1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

This is a good solution as this makes the timing of the scaling the same between using a subform or using a frame.