Jump to content
Gustav Schubert

loading example data into fmx TStringGrid

Recommended Posts

FMX: What is the recommended way to load example data into TStringGrid?

I have this, but it no longer works:
 

unit FrmMain;

interface

uses
  System.SysUtils,
  System.Types,
  System.UITypes,
  System.Classes,
  FMX.Types,
  FMX.Controls,
  FMX.Forms,
  Data.Bind.EngExt,
  FMX.Bind.DBEngExt,
  FMX.Bind.Editors,
  Data.Bind.Components,
  Data.Bind.DBScope,
  Data.Bind.DBLinks,
  Fmx.Bind.DBLinks,
  FMX.Layouts,
  FMX.Grid,
  Data.DB,
  Datasnap.DBClient,
  FMX.Edit,
  System.Bindings.Outputs,
  FMX.StdCtrls,
  System.Rtti,
  FMX.Grid.Style,
  FMX.Controls.Presentation,
  FMX.ScrollBox;

type
  TFormMain = class(TForm)
    StringGrid: TStringGrid;
    TestBtn: TButton;
    procedure FormCreate(Sender: TObject);
    procedure TestBtnClick(Sender: TObject);
  private
    ClientDataSet: TClientDataSet;
    DataSource: TDataSource;
    BindScope: TBindScopeDB;
    BindingsList: TBindingsList;

    gl: TBindDBGridLink;
    Counter: Integer;
  end;

var
  FormMain: TFormMain;

implementation

{$R *.fmx}

procedure TFormMain.FormCreate(Sender: TObject);
var
  dn: string;
  fn: string;
  pn: string;
  ML: TStringList;
begin
  TestBtn.Enabled := False;

  ReportMemoryLeaksOnShutdown := True;

  dn := 'C:\Users\Public\Documents\Embarcadero\Studio\37.0\Samples\Data\';
  fn := 'country.xml';
  pn := dn + fn;

  if FileExists(pn) then
  begin
    ClientDataSet := TClientDataSet.Create(self);
    BindingsList := TBindingsList.Create(self);

    ML := TStringList.Create;
    ML.LoadFromFile(pn);
    ClientDataSet.Active := False;
    ClientDataSet.XMLData := ML.Text;
    ClientDataSet.Active := True;
    ML.Free;

    DataSource := TDataSource.Create(self);
    DataSource.AutoEdit := False;
    DataSource.DataSet := ClientDataSet;

    BindScope := TBindScopeDB.Create(self);
    BindScope.DataSet := ClientDataSet;
    BindScope.DataSource := DataSource;

    TestBtn.Enabled := True;
  end;
end;

procedure TFormMain.TestBtnClick(Sender: TObject);
begin
  if (gl <> nil)  then
    gl.Active := False;

  gl.Free;

  gl := TBindDBGridLink.Create(BindingsList);
  gl.AutoBufferCount := False;
  gl.Category := 'DB Links';
  gl.DataSource := BindScope;
  gl.GridControl := StringGrid; // <-- Exception in D13

// in D12.3: ok
// in D13: Crash because Position = nil in TControl.GetBoundRect

{
function TControl.GetBoundsRect: TRectF;
begin
//  if Position = nil then
//    result := TRectF.Create(0, 0, 0, 0)
//  else
    Result := TRectF.Create(Position.X, Position.Y, Position.X + Width, Position.Y + Height);
end;
}

  gl.Active := True;

  Inc(Counter);
  Caption := IntToStr(Counter);
end;

end.

 

Share this post


Link to post
2 minutes ago, Gustav Schubert said:

<-- Exception in D13

What is the exception? Please run it in the debugger and show the callstack at that point. 

Share this post


Link to post
12 minutes ago, Dave Nottage said:

What is the exception?

FMX.Controls.TControl.GetBoundsRect
FMX.ScrollBox.TScrollContent.IsVisibleChild($CB85650)
FMX.Controls.TControl.RecalcUpdateRect
FMX.Controls.TControl.InternalSizeChanged
FMX.Controls.TControl.HandleSizeChanged
FMX.Controls.TControl.SizeChanged(???)
FMX.Controls.TControl.RecalcSize
FMX.ScrollBox.Style.TStyledCustomScrollBox.RealignContent
FMX.Grid.Style.TStyledGrid.MMInvalidateContentSize(???)
FMX.Presentation.Messages.TMessageSender.SendMessage(???)
FMX.Grid.TGridModel.InvalidateContentSize
FMX.Grid.TGridModel.RemoveColumn(???)
FMX.Grid.TCustomGrid.ContentBeforeRemoveObject(???)
FMX.ScrollBox.TScrollContent.DoRemoveObject($CB85650)
FMX.Types.TFmxObject.RemoveObject(???)
FMX.Types.TFmxObject.Destroy
FMX.Controls.TControl.Destroy
FMX.Grid.TColumn.Destroy
System.TObject.Free
Fmx.Bind.DBLinks.TBindDBStringGridColumnCreator.ClearColumns
Data.Bind.DBLinks.TBaseBindDBGridLink.ClearColumns(TBindDBStringGridColumnCreator($CB95270) as IBindDBGridLinkControlManager)
Fmx.Bind.DBLinks.TCustomBindDBGridLink.ClearColumns(TBindDBStringGridColumnCreator($CB95270) as IBindDBGridLinkControlManager)
Fmx.Bind.DBLinks.TCustomBindDBGridLink.ClearGeneratedExpressions(???)
Fmx.Bind.DBLinks.TCustomBindDBGridLink.UpdateColumns
Data.Bind.DBLinks.TInternalBindGridLink.ApplyComponents
Data.Bind.Components.TActivatedContainedBindComponent.UpdateControlChanged
Data.Bind.Components.TCommonBindComponent.SetControlComponent($62A29B0)
Fmx.Bind.DBLinks.TBaseBindDBGridControlLink.SetControl(???)
FrmMain.TFormMain.TestBtnClick($4EC7280)
FMX.Controls.TControl.Click
FMX.StdCtrls.TCustomButton.Click
FMX.Controls.TControl.MouseClick(???,???,45,14)
FMX.Forms.TCommonCustomForm.MouseUp(mbLeft,[ssLeft],141,38,???)
FMX.Platform.Win.WndProc(460274,514,0,2490509)
FMX.Platform.Win.TPlatformWin.HandleMessage
FMX.Forms.TApplication.HandleMessage
FMX.Platform.Win.TPlatformWin.Run
FMX.Forms.TApplication.Run
SG02.SG02

I get access violation, Position is nil in TControl.GetBoundsRect.

Share this post


Link to post

I had a similar bug but I couldn't reproduce it anymore. Looks like RemoveColumn triggers some calls that act too late, when Position etc are already destroyed (use-after-nil).  I did submit a QC issue but never was activated as I couldn't add reproduceable steps.

Share this post


Link to post

I now have a workaround: Need to unload the Presentation before attempting the critical assignment.

 

procedure TFormMain.TestBtnClick(Sender: TObject);
begin
  StringGrid.UnloadPresentation; // to avoid problems later

  if (gl <> nil)  then
    gl.Active := False;

  gl.Free;

  gl := TBindDBGridLink.Create(BindingsList);
  gl.AutoBufferCount := False;
  gl.Category := 'DB Links';
  gl.DataSource := BindScope;
  gl.GridControl := StringGrid; // <-- critical line

  gl.Active := True;

  StringGrid.LoadPresentation; // now it is safe to have a presentation

  Inc(Counter);
  Caption := IntToStr(Counter);
end;

Depending on who the Owner is of these databinding components, Form or Application, it may be necessary to do the same (unloading the presentation of the string grid) when the application closes down. I needed to do this in FormClose, FormDestroy would be tool late.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×