喫茶XRAYトップページ

[スレッド全体
]

[11164] Memo99は親ウィンドウを持っていません返信 削除
2017/4/29 (土) 20:53:50 taki
コンポーネントを文字列化し、文字列からコンポーネントを生成しているのですが、
TMemoの文字列からコンポーネントを生成する過程で
「Memo99は親ウィンドウを持っていません」というエラーが発生します。
TEdit、TLabelはエラーは出ません。
それぞれコメントアウトしたり外したりして試しました。

Windows7 Pro+DelphiXE4 Starter Update 1
Windows10 Pro+Delphi10.2 Starter
同じ内容のエラーがMemoだけに出ます。

以下が試したコードです。
大元は
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Classes_TStream_ReadComponent.html


unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Grids;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  published

  end;

var
  Form1: TForm1;
  Memo99  : TMemo;
  Edit99  : TEdit;
  Label99 : TLabel;


implementation

{$R *.dfm}

function ComponentToStringProc(Component: TComponent): string;
var
  BinStream:TMemoryStream;
  StrStream: TStringStream;
  s: string;
begin
  BinStream := TMemoryStream.Create;
  try
    StrStream := TStringStream.Create(s);
    try
      BinStream.WriteComponent(Component);
      BinStream.Seek(0, soFromBeginning);
      ObjectBinaryToText(BinStream, StrStream);
      StrStream.Seek(0, soFromBeginning);
      Result:= StrStream.DataString;
    finally
      StrStream.Free;
    end;
  finally
    BinStream.Free
  end;
end;

function StringToComponentProc(Value: string): TComponent;
var
  StrStream:TStringStream;
  BinStream: TMemoryStream;
begin
  StrStream := TStringStream.Create(Value);
  try
    BinStream := TMemoryStream.Create;
    try
      ObjectTextToBinary(StrStream, BinStream);
      BinStream.Seek(0, soFromBeginning);
      Result:= BinStream.ReadComponent(nil);
    finally
      BinStream.Free;
    end;
  finally
    StrStream.Free;
  end;
end;

// コンポーネントを文字列化
procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Text := ComponentToStringProc(Memo99);
//  Memo1.Text := ComponentToStringProc(Edit99);
//  Memo1.Text := ComponentToStringProc(Label99);
end;

// 文字列からコンポーネントを生成
procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(Memo99) then Memo99.Free;
  Memo99 := (StringToComponentProc(Memo1.Text) as TMemo);  // <- ここでエラー
  Memo99.Parent := Form1;
  Memo99.Left := 200;
  Memo99.Visible := true;
//
{
  if Assigned(Edit99) then Edit99.Free;
  Edit99 := (StringToComponentProc(Memo1.Text) as TEdit);  // <- 大丈夫
  Edit99.Parent := Form1;
  Edit99.Left := 200;
  Edit99.Visible := true;
}
//
{
  if Assigned(Label99) then Label99.Free;
  Label99 := (StringToComponentProc(Memo1.Text) as TLabel);  // <- 大丈夫
  Label99.Parent := Form1;
  Label99.Left := 200;
  Label99.Visible := true;
  }
end;

// 動的にコンポーネントを生成
procedure TForm1.Button3Click(Sender: TObject);
begin

  Memo99 := TMemo.Create(Self);
  Memo99.Parent := Self;
  Memo99.Name := 'Memo99';
  Memo99.Top := 100;
  Memo99.Left := 100;
  Memo99.Width := 200;
  Memo99.Height := 20;
//
{
  Edit99 := TEdit.Create(Self);
  Edit99.Parent := Self;
  Edit99.Name := 'Edit99';
  Edit99.Top := 100;
  Edit99.Left := 100;
  Edit99.Width := 200;
  Edit99.Height := 20;
}
//
{
  Label99 := TLabel.Create(Self);
  Label99.Parent := Self;
  Label99.Name := 'Label99';
  Label99.Top := 100;
  Label99.Left := 100;
  Label99.Width := 200;
  Label99.Height := 20;
}
end;


initialization

  RegisterClass(TEdit);
  RegisterClass(TMemo);
  RegisterClass(TLabel);

end.

エラーの原因が全く分かりません。
同じような文字列ができているのですが、Memoだけがダメです。


[11165] Re:Memo99は親ウィンドウを持っていません返信 削除
2017/4/30 (日) 10:31:00 Mr.XRAY
▼ takiさん

> 「Memo99は親ウィンドウを持っていません」というエラーが発生します。
> TEdit、TLabelはエラーは出ません。


Lines プロパティ,つまり TMemo に描画する文字列は描画するコントロール,
つまり,TMemo がないと描画,表示できません.

        Result:= BinStream.ReadComponent(nil);

の段階では TMemo の親が決まっていませんから,そのエラーとなるのでは
ないかと思います.
Lines プロパティの値が空であればエラーは発生しないですね.
TListBox 等も同じです.
TEdit 等とは描画の仕組みが違うためと思われます.
回避策としては,TWriter, TReader の実装が必要かと.

>大元は

以下のが新しいやつですね.
コードは全く同じようですが (^^;
http://docwiki.embarcadero.com/CodeExamples/Berlin/en/ComponentToString_(Delphi)

参考
[TReader.ReadRootComponent]
http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.Classes.TReader.ReadRootComponent


[Button3], [Button1], [Button2] の順番でクリック

[11166] Re2:Memo99は親ウィンドウを持っていません返信 削除
2017/4/30 (日) 12:13:29 taki
▼ Mr.XRAYさん
> ▼ takiさん
>
> > 「Memo99は親ウィンドウを持っていません」というエラーが発生します。
> > TEdit、TLabelはエラーは出ません。
>
> Lines プロパティ,つまり TMemo に描画する文字列は描画するコントロール,
> つまり,TMemo がないと描画,表示できません.
>
>         Result:= BinStream.ReadComponent(nil);
>
> の段階では TMemo の親が決まっていませんから,そのエラーとなるのでは
> ないかと思います.
> Lines プロパティの値が空であればエラーは発生しないですね.
> TListBox 等も同じです.
> TEdit 等とは描画の仕組みが違うためと思われます.
> 回避策としては,TWriter, TReader の実装が必要かと.


ありがとうございます。
マスターのアドバイスを手掛かりにもう少し試してみます。


[11167] Re3:Memo99は親ウィンドウを持っていません返信 削除
2017/4/30 (日) 13:40:07 Mr.XRAY
takiさんのおかげて,またまた記事の修正をばしました.

[130][04_コンポーネントをテキスト形式で保存]
http://mrxray.on.coocan.jp/Delphi/plSamples/130_SaveComponent.htm#04

なんですが,Parent の設定をコンポの読み出しいの後だったのを
コンポーネントを生成した直後に設定するようにしました.
これで TMemo の Lines プロパティにテキストがあっても読み込めます.

taki さん,サンクスです (^^


[11168] Re4:Memo99は親ウィンドウを持っていません返信 削除
2017/4/30 (日) 14:12:06 Mr.XRAY
> [130][04_コンポーネントをテキスト形式で保存]
> http://mrxray.on.coocan.jp/Delphi/plSamples/130_SaveComponent.htm#04


では,コンポーネントの読み出しが以下のようになっています.

  LStream.ReadComponent(LPanel);

これを,今回の taki さんのコードにすると以下になります.
この場合,読み出すコンポーネントを予め Create しておく必要はありませんが,
RegisterClass で TPanel を登録しておく必要があります.
このこと以外に実質的な違いはありません.

  LPanel :=  LStream.ReadComponent(nil) as TPanel;


[▼次のスレッド]
INCM/CMT
Cyclamen v3.82