喫茶XRAYトップページ

[スレッド全体
]

[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;


[11169] Re4:Memo99は親ウィンドウを持っていません返信 削除
2017/4/30 (日) 14:15:10 taki
▼ Mr.XRAYさん
> takiさんのおかげて,またまた記事の修正をばしました.
>
> [130][04_コンポーネントをテキスト形式で保存]
> http://mrxray.on.coocan.jp/Delphi/plSamples/130_SaveComponent.htm#04
>
> なんですが,Parent の設定をコンポの読み出しいの後だったのを
> コンポーネントを生成した直後に設定するようにしました.
> これで TMemo の Lines プロパティにテキストがあっても読み込めます.
>
> taki さん,サンクスです (^^


実は、
http://mrxray.on.coocan.jp/Delphi/plSamples/130_SaveComponent.htm#03
「TMemoryStream を使用したコンポーネントの保存と読み出しの例」より
Panel1をMemo99に置き換えて試してみた時に、

  LMemo  := TMemo.Create(Self);
  LMemo.Parent := Self;          // <-- ここを追加
  LStream := TMemoryStream.Create;
  try
    //ファイルからメモリストーリームに読み込む
    LStream.LoadFromFile('AAA.dat');
    //メモリストリームからクラスのインスタンスを取得
    LStream.ReadComponent(LMemo);
    …
だとエラーが出ない事に気が付いたのですが、

LStream.ReadComponent(LMemo);と

function StringToComponentProc(Value: string): TComponent;内では
Result:= BinStream.ReadComponent(nil);が使われているので
その違いを調べていました。

「Instanceがnil(Delphi)またはNULL(C ++)の場合、ReadComponentは
ストリーム内の型情報に基づいてコンポーネントを作成し、
新しく構築されたコンポーネントを返します。」Google翻訳

なので、Createした直後にParentを設定できないので
function StringToComponentProc(Value: string): TComponent;は
もったいないけど使えないな〜と思っています。

それと、IDEの「デバッガを使わずに実行」すると
「Memo99.Lines.Stringsの読み取り中のエラー…」が表示されるんですね。
ずっとデバッガからの実行だったので、「Memo99は親ウィンドウを持っていません」
のエラー表示しか得られていませんでした。

勉強になりました。


[11170] Re5:Memo99は親ウィンドウを持っていません返信 削除
2017/4/30 (日) 14:52:40 Mr.XRAY
> function StringToComponentProc(Value: string): TComponent;は
> もったいないけど使えないな〜と思っています。


う〜む.必ずしもそうとは言えないかも.
 
> それと、IDEの「デバッガを使わずに実行」すると

こういうのって,図が掲載されていると,自分との違いに気づくんですよね.
だから,図,画像っていうのは多くを語ってくれんです.
その大切な画像を間違ってサーバーから削除してしまつたやつがいるんですよ.
そういうのって何と言うか知っています ?

バカって言うんです.そうです.私がそのバカです.ハイ.

昔,山の個人山行で,テントの中で先輩に言われたことがあります.
「お前さ,もしかしてバカ ?」


[11171] Re6:Memo99は親ウィンドウを持っていません返信 削除
2017/5/2 (火) 10:46:12 taki
▼ Mr.XRAYさん
> > function StringToComponentProc(Value: string): TComponent;は
> > もったいないけど使えないな〜と思っています。
>
> う〜む.必ずしもそうとは言えないかも.


function StringToComponentProc(Value: string): TComponent;で使われている
Result:= BinStream.ReadComponent(nil);
は、メソッド内でコンポーネントがCreateされている事と、
TComponentはParentプロパティが設定できません。

問題はMemoのLinesの設定が存在することでエラーになるので、
Memo99を「空」の状態で文字列に保存することを考えました。

その結果、Memoコンポーネントはエラーなく生成できました。

以下がコードです。

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, Vcl.ExtCtrls;

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;

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);
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;

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;
  Memo99.Clear;   // <- これを追加 中身を空に

end;

initialization

  RegisterClass(TMemo);

end.

要するに、現状のコンポーネント(だけ)の保存&生成ですよ。
中身は後でセットしてね。と言う事ですか…。

しつこくてすみません。


[11172] Re7:Memo99は親ウィンドウを持っていません返信 削除
2017/5/2 (火) 11:05:33 taki
マスターすみません。

記事を読み直していたら

> Lines プロパティ,つまり TMemo に描画する文字列は描画するコントロール,
> つまり,TMemo がないと描画,表示できません.
>
>        Result:= BinStream.ReadComponent(nil);
>
> の段階では TMemo の親が決まっていませんから,そのエラーとなるのでは
>  ないかと思います.
> Lines プロパティの値が空であればエラーは発生しないですね.
> TListBox 等も同じです.


と、指摘が既にありました。
> Lines プロパティの値が空であればエラーは発生しないですね.
を見逃していました。m(_ _)m




[11173] Re8:Memo99は親ウィンドウを持っていません返信 削除
2017/5/2 (火) 17:55:31 Mr.XRAY
>しつこくてすみません

しつこさ,くどさが大切です.と私は思っています.

> > Lines プロパティの値が空であればエラーは発生しないですね.
> を見逃していました。m(_ _)m


こういうことの繰り返しです.人生は.
私がいい手本です.
ん ? よくはないか... ハハハッ


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