1

在设计时从这个布局开始。(它包含几个 TLayout、TGridPanelLayout、TText 元素作为示例)

在此处输入图像描述

在运行时,我使用 ObjectBinaryToText 将完整的对象结构保存到文件中

在此处输入图像描述

但是当使用 ObjectTextToBinary 从文件中加载文件时,我得到了这个结果

在此处输入图像描述

为什么子控件没有采用与以前保存的完全相同的布局?文件结构似乎没问题,并且包含使用 IDE 保存表单时描述的所有子控件

这是一段演示问题的代码。

考绩档案

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  system.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, 
  FMX.Dialogs, FMX.Objects, FMX.Layouts, FMX.Controls.Presentation, 
  FMX.StdCtrls;

type
  TForm1 = class(TForm)
    RecTop: TRectangle;
    ButtonSave: TButton;
    ButtonClear: TButton;
    ButtonLoad: TButton;
    Layout1: TLayout;
    GridPanelLayout1: TGridPanelLayout;
    Text1: TText;
    Text2: TText;
    Text3: TText;
    Text4: TText;
    procedure ButtonSaveClick(Sender: TObject);
    procedure ButtonClearClick(Sender: TObject);
    procedure ButtonLoadClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    AppPath: string;
    AppDatFile: String;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
{$R *.fmx}

uses
  System.IOUtils;

procedure TForm1.ButtonSaveClick(Sender: TObject);
var
  FileStream : TFileStream;
  MemStream : TMemoryStream;
begin
  FileStream := TFileStream.Create(AppDatFile, fmCreate);
  try
    MemStream := TMemoryStream.Create;
    MemStream.WriteComponent(Layout1);
    MemStream.Position := 0;
    ObjectBinaryToText(MemStream, FileStream);
  finally
    MemStream.Free;
    FileStream.Free;
  end;
end;

procedure TForm1.ButtonClearClick(Sender: TObject);
var
  i: Integer;
begin
  for i := pred(Layout1.ChildrenCount) downto 0 do
    Layout1.Children[i].Free;
end;

procedure TForm1.ButtonLoadClick(Sender: TObject);
var
  FileStream : TFileStream;
  MemStream : TMemoryStream;
begin
  if FileExists(AppDatFile) then
  begin
    FileStream := TFileStream.Create(AppDatFile, fmOpenRead);
    try
      MemStream := TMemoryStream.Create;
      ObjectTextToBinary(FileStream, MemStream);
      MemStream.Position := 0;
      MemStream.ReadComponent(Layout1);
      Layout1.Align:= TAlignLayout.Client;
    finally
      MemStream.Free;
      FileStream.Free;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  AppPath:= TPath.GetLibraryPath;
  AppDatFile:= TPath.Combine(AppPath, 'SaveLoadLayout.dat');
end;

end

FMX 文件

  object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 480
  ClientWidth = 640
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  OnCreate = FormCreate
  DesignerMasterStyle = 0
  object RecTop: TRectangle
    Align = Top
    Size.Width = 640.000000000000000000
    Size.Height = 41.000000000000000000
    Size.PlatformDefault = False
  end
  object ButtonSave: TButton
    Position.X = 8.000000000000000000
    Position.Y = 8.000000000000000000
    TabOrder = 3
    Text = 'Save'
    OnClick = ButtonSaveClick
  end
  object ButtonClear: TButton
    Position.X = 96.000000000000000000
    Position.Y = 8.000000000000000000
    TabOrder = 2
    Text = 'Clear'
    OnClick = ButtonClearClick
  end
  object ButtonLoad: TButton
    Position.X = 184.000000000000000000
    Position.Y = 8.000000000000000000
    TabOrder = 1
    Text = 'Load'
    OnClick = ButtonLoadClick
  end
  object Layout1: TLayout
    Align = Client
    Size.Width = 640.000000000000000000
    Size.Height = 439.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 4
    object GridPanelLayout1: TGridPanelLayout
      Align = Client
      Size.Width = 640.000000000000000000
      Size.Height = 439.000000000000000000
      Size.PlatformDefault = False
      TabOrder = 0
      ColumnCollection = <
        item
          Value = 50.000000000000000000
        end
        item
          Value = 50.000000000000000000
        end>
      ControlCollection = <
        item
          Column = 0
          Control = Text1
          Row = 0
        end
        item
          Column = 1
          Control = Text2
          Row = 0
        end
        item
          Column = 0
          Control = Text3
          Row = 1
        end
        item
          Column = 1
          Control = Text4
          Row = 1
        end>
      RowCollection = <
        item
          Value = 50.000000000000000000
        end
        item
          Value = 50.000000000000000000
        end>
      object Text1: TText
        Align = Client
        Size.Width = 320.000000000000000000
        Size.Height = 219.500000000000000000
        Size.PlatformDefault = False
        Text = 'Text1'
      end
      object Text2: TText
        Align = Client
        Size.Width = 320.000000000000000000
        Size.Height = 219.500000000000000000
        Size.PlatformDefault = False
        Text = 'Text2'
      end
      object Text3: TText
        Align = Client
        Size.Width = 320.000000000000000000
        Size.Height = 219.500000000000000000
        Size.PlatformDefault = False
        Text = 'Text3'
      end
      object Text4: TText
        Align = Client
        Size.Width = 320.000000000000000000
        Size.Height = 219.500000000000000000
        Size.PlatformDefault = False
        Text = 'Text4'
      end
    end
  end
end
4

1 回答 1

2

正如我在评论中所说,问题在于 WriteComponent 错误地使用以下格式写入项目:

Control = Form1.Text1

这不正确,应该是

Control = Text1

该行为可能是由于使用其他组件序列化一个组件,它们的所有者被一起保存。

解决方法是更正 WriteComponent 写入的内容。使用简单 ReplaceString 的简单实现如下所示:

procedure TForm1.ButtonSaveClick(Sender: TObject);
var
    StringStream : TStringStream;
    MemStream    : TMemoryStream;
    Buf          : String;
begin
    MemStream    := nil;
    StringStream := TStringStream.Create;
    try
        MemStream := TMemoryStream.Create;
        MemStream.WriteComponent(Layout1);
        MemStream.Position := 0;
        ObjectBinaryToText(MemStream, StringStream); 
        Buf := StringReplace(StringStream.DataString,
                             '    Control = ' + Self.Name + '.',
                             '    Control = ', [rfReplaceAll]);
        TFile.WriteAllText(AppDatFile, Buf);
    finally
        MemStream.Free;
        StringStream.Free;
    end;
end;

请注意,此解决方法实现适用于您的示例,但可能会造成混淆,因为搜索和替换不使用真正的解析器,并且可以替换具有相同形式的其他内容(例如字符串属性)。

于 2020-11-24T17:06:24.407 回答