Tframeの値の引き渡しについて

解決


  2022-08-20 07:09:19  No: 150369

おはようございます。
Tframeの値の引き渡しについて詰まっています。

TForm.Createをおこない、そこにFrameを配置した場合に
そのフレームのイベントを着火させるには、どのようにすればよろしいでしょうか?

Createしない場合は

■フレームイベント
function sample():string
begin
result:='aaa';
end;

■フォーム1イベント
edit1.text:=Tframe.sample();

で出来ましたが、フォームを動的に生成し、そこに貼り付けたコントロールの
着火でつまずいております。

また、逆に上記のFrameからForm1に値を送るときに
■フレームイベント
procedure Tframe.Button1(Sender: TObject);
begin
form1.Edit1.Text:='www';
end;

このform1を決め打ちにせずに呼び出し元のフォーム名やstringで
与えることは出来ないでしょうか?

すいませんが解明いただけますと助かります。


  2022-08-21 09:11:13  No: 150371

form1.editの部分をグローバル変数にでもして、そこに必要なタイミングで処理したい先のフォーム名を入れれば良いのでは無いでしょうか。


  2022-08-21 09:13:47  No: 150372

それと、イベントはフレーム側であらかじめ作っておけば、普通に発火しませんか?


Mr.XRAY  2022-08-21 20:48:51  No: 150374

話しの内容がよく分からないのですが・・・,TFrame についてです.

TFrame は,複数のコンポーネントを配置して使用できるコンポーネントです.
したがって,一般的には,

> procedure Tframe.Button1(Sender: TObject);
> begin
> form1.Edit1.Text:='www';
> end;

のような使い方はしません 通常のコンポーネントと同じように使用します.
コンポーネント内部の値は,コンポーネントを使用する側で受け取ります

フォームに配置した TFrame の Button1 のイベントを作成します.
この時,TFrame に配置した Button1 に,クリックのイベントがあると,以下のようになります.

procedure TForm1.Frame21Button1Click(Sender: TObject);
begin
  Frame21.Button1Click(Sender); 
end; 

TFrame 側の値を取得したい場合は,TFrame 側でその値用の変数をプロパティとして実装します.

procedure TForm1.Frame21Button1Click(Sender: TObject);
begin
  Frame21.Button1Click(Sender); 
    
  // Frame21 という名前のコンポーネントの,TextValue という string 型のプロパティを取得する例
  Edit1.Text := Frame21.TextValue:
end;
 
     
# 発火とか着火という専門用語は,私には意味が分かりません.
# コントロールの着火って,どういう状態 ? 


Mr.XRAY  2022-08-21 22:41:57  No: 150375

> このform1を決め打ちにせずに呼び出し元のフォーム名やstringで
> 与えることは出来ないでしょうか?

これも意味が分からないのです.

フォーム名をどこに与えるのか ?
String で与える.どこに,この string は何 ?
そもそも string というのは型名なんですが・・・

こういうことなら,できます.

フォーム側の TFrame の Button1 のクリックイベント

procedure TForm1.Frame21Button1Click(Sender: TObject);
begin
  Frame21.Button1Click(Edit1);
end;

TFrame 側の Button1 クリックイベント

procedure TFrame2.Button1Click(Sender: TObject);
begin
  TEdit(Sender).Text := '日本語 ABC';
end;


take  2022-08-22 08:07:22  No: 150376

質問内容を分けると
1.フォームを動的に生成したときフォーム上のコントロールを知る方法?
2.フォームとフレーム間でメソッド受け取りとイベント受信がわからない

初歩的な勘違いと変な用語が多すぎですが
フレームはフォームを生成するときに生成するのが一般的ですので

フォーム生成時に

FFrame1 := TFrame1.Create(Self);
FFrame1.Parent := Self;
FFrame1.Algin := alClient;

こうやって作ってフレーム上のコントロールへは
FFrame.Edit1 := 'form -> frame';
のように処理します。
※これも専用メソッドを作って中継させた方が良いですが

反対にフレームからフォームへアクセスするには
フレーム内のイベントやメソッドで

TFrame1(Parent).Edit1 := 'frame -> form';

のようにすることができますが
フレーム内でイベントを作って、それをフォーム側で受け取って処理するのが良いでしょう


  2022-08-22 15:07:43  No: 150377

>それと、イベントはフレーム側であらかじめ作っておけば、普通に発火しませんか?

ありがとうございます。原因解明しました!!

TForm.Createする場合も最初にグローバルで対象のFrameを定義しておかないと
メソッドチェーンのように指定できないんですね。

生成時のフレームに対して行うと思っていたのが原因でした。

> // Frame21 という名前のコンポーネントの,TextValue という string 型のプロパティを取得する例

と言う事は

Tframe.edit1.text:='xxxx';のような感じ呼び出し元からは参照や代入は出来なく
frame側で1度グローバル変数に代入するイベントを通さなくて駄目な感じなんですね。
新規->フォームで作成したときと同様に参照代入できルものだと思っていました。

># 発火とか着火という専門用語は,私には意味が分かりません.# コントロールの着火って,どういう状態 ? 

Mr.XRAYさんはJAVASCRIP系の記事も書いているので両方とも精通しているのかと思いましたら、DELPHIベースだと変な用語に感じてしまうんですね。

WEB系だとイベントの発動のことを着火とか発火と一般的に言われているので
同じように認識できると思っていました。

https://qiita.com/airesaies/items/85faa8e18be5089e0e1a

>フォーム名をどこに与えるのか ?String で与える.どこに,この string は何 ?
そもそも string というのは型名なんですが・・・

findcomponentでname文字列を与えてコンポーネント型に変換できますよね?
それと同じように、フォーム名を文字列で与えてtform型として認識させたかったのです。

たぶん、findclassを利用すると思うので、文字列を与えてもclass名が無いと言われ実現できませんでした。

>こうやって作ってフレーム上のコントロールへはFFrame.Edit1 := 'form -> frame';
のように処理します。

Parent := Self;にすると新しいフォームを作っても呼び出し元に表示されてしまうのと
FFrame.Edit1 のFFrameがどこから出てきたのかが流儀の認識が不足で確認できませんでした。

>TFrame1(Parent).Edit1 := 'frame -> form';
のようにすることができますが、フレーム内でイベントを作って、それをフォーム側で受け取って処理するのが良いでしょう

TFrame1(Parent).Edit1 の指定の仕方に興味はありますが確認できずじまいでしたので、おすすめのフォーム側で受け取って処理する方法で行いますね。


take  2022-08-22 16:09:41  No: 150378

解決してなによりですが
FormとFrameの関係性のための設計に問題があるかもしれません
Frameは便利な反面使い方を誤ると かなり悩まされます。

Frameを利用してそれを呼び出すFormが動的生成ということであれば
グローバル変数は使用しないと思います。

新しいプロジェクトから作って説明すると
最初のFormがForm1、追加したFormがForm2、作ったフレームが Frame1 と設計されていたとして
Form2は動的生成するのであればプロジェクトの設定で自動生成から除外
グローバルとしてFrom2が残っていれば手動削除

Form1からForm2を生成

var
  aFrom2 : TForm2; // 常にForm1から参照したい場合はForm1のprivateにて定義
begin
  aForm2 := TForm2.Create(Self);
  aForm2.Parent := Self;
  aForm2.Show;

Form2でFrame1を使う

Form2のprivateに FFrame1を定義
Form2のOnCreateイベントで
  FFrame1 := TFrame1.Create(Self);
  FFrame1.Parent := Self;
  // 独自イベントを受け取る場合はイベントを割り当て
  FFrame1.Onxxxxx := Onxxxx;

Form2からFrame1にアクセスする場合は
  FFrame1.Edit.Text := 'Form2 -> Frame1';

1つの実体を持つFrame1をFrom2やForm3でもどうしても扱いたい場合は

Form1のOnCreateイベントでFrame1を生成しておいて

  aForm2 := TForm2.Create(Self);
  aForm2.Parent := Self;
  aFrom2.FramePublic := FFrame1;
  aForm2.Show;

生成しておいた実体を参照させることは出来そうですが事故が起きそうですね。

着火、発火は何を言いたいのか予想がついてはいましたがSEしか使わない用語のようですね
書籍には使われていませんでした。

不思議の国のSE用語
https://qiita.com/t_nakayama0714/items/478a8ed3a9ae143ad854


Mr.XRAY  2022-08-22 18:35:56  No: 150380

> 書籍には使われていませんでした。

書籍で使ってはいけません.それらの用語を解説する書籍であれば別ですが.😀
それらは,いわゆる「俗語」ですね.
少なくとも,掲示板等で,人様に何かを教わろうとする方が使用する用語ではないでしょう.


Mr.XRAY  2022-08-23 13:28:43  No: 150382

take さんが

> フレームはフォームを生成するときに生成するのが一般的ですので
>
> フォーム生成時に

> FFrame1 := TFrame1.Create(Self);

と書いているので気付いたのですが,私がレスした

> こういうことなら,できます.

で書いた,フレーム側で  TEdit(Sender) とするコードは,
フレームを実行時に生成する場合はは利用できません.
この時の Sender は,フレームの Button1 になってしまいます.
当然なのですが,念のため.
フレームを実行時に生成しない場合も,原則として,こんなことはすべきではありません.


  2022-08-24 17:23:16  No: 150383

だいぶ、イメージできてきました。
あとは参照時にアクセスエラーが出ていて試行錯誤しています。

Frame側

procedure Tframe1.Button1Click();
var
s:string;
begin
showmessage('xxx');//これはOK
showmessage(edit1.text);//edit1はFrame側のコントロール(アクセスエラー)
s:=edit1.text;//これもだめ
end;

Form1側でボタンを押しFrameのprocedureの内容を実行させたく下記のようにするとFlame側でボタンを押すと実行されるが下記のようにすると、xxxの方は表示されるがコントロール名の方はaccess vaiolationエラーになります。

Form1側

procedure TForm1.Button2Click(Sender: TObject);
begin
Tframe1.Button1Click();
end;

なので、Frame側でいったんほかのprocedure経由で実行させFrameでしょりしたようにみせかけてもエラーになり、今のところ、edit1の値を参照したり取得したければonchange時にglobal変数に代入し、それを参照するという感じでしか手段がみあたらない感じです。
(onchangeせずにForm1の指示でframe側のedit1の参照をかけたい)


HFUKUSHI  2022-08-24 19:06:11  No: 150384

断片的なコードを書いても意思疎通は難しいと思うんで、動作する最小限のコード(全体)を提示したほうがいいと思いますね。


take  2022-08-25 08:53:55  No: 150385

こういうことかな?Delphi起動せずに書いてるので一部省略

type TFrame1=class(TFrame)
  private
    procedure Button1Click(Sender : TObject);
  end;

これを

procedure TForm1.Button2Click(Sender: TObject);
begin
  TFrame1.Button1Click();
end;

で呼び出せないのは何故か?

1.クラスの定義(型)とクラスそのもの(変数)が理解出来ていない
2.コントロールのイベントはpivate宣言なので他クラスから呼ぶべきではない

(1)
Delphiのエディタでフレームを追加する操作を行って Nameプロパティに「Frame1」と設定して完成するのは
TFrame1という型が定義されただけで実体がどこにも存在していない

Form1でTFrame1としてデザインしたフレームを使用する場合は
Form1の上のuses宣言に TFrame1として保存したときのファイル名を書いてインクルード
Form1のprivate宣言に

FFrame1 : TFrame1;

としてデザインしたフレームを使いますよと宣言

Form1のイベントに生成と破棄OnCreate OnDestroyイベントを作って
OnCreate内で

FFrame1 := TFrame1.Create(Self);
FFrame1.Parent := Self;
FFrame1.Algin := alClient;

OnDestroy内で

FFram1.Free;

これでForm1が動いている間はFFrame1にTFrame1としてデザインされたフレームが反映されるので
FFram1を通じてコントロールにはアクセス出来る
ただしButton1Clickは呼べない

呼ぶにはというかその場合は
ボタンを押したときに処理するプログラムをpublicに定義してその中で処理されるように作って
Button1Clickでもその関数を呼ぶように作る

自分自身でフレームを生成して自動で配置する方法を想像して書きましたが
手動でフレームを置いた場合はどういう動きになるのか忘れました

一番最初の書き込みに

>■フォーム1イベント
>edit1.text:=Tframe.sample();

となっていますが、これを見ると型と値の区別が出来ていないような・・・


  2022-08-25 22:24:15  No: 150387

>これを見ると型と値の区別が出来ていないような・・・

frame側で
stringの返値を出すfunctionなんですが

そこで
result:='xxx';だと意図したようにForm1に表示されますが
result:=edit.text のようにコントロール名を入れるとアクセスエラーになります。

返値に限らず、そこでshowmessage(edit.text)でもなるので疑問でしたが
findcomponentsで目的を果たすことが出来たので、作りかかけのをまとめてから、HFUKUSHI さんの言うように最小ソースを作って補足しますね。


ぽ・イ  2022-08-26 12:37:38  No: 150390

> ■フォーム1イベント
> edit1.text:=Tframe.sample();
動的にフォームを生成しているのだから、以下のようにフレームの生成箇所もあるはず
FFrame1 := TFrame1.Create(Self);

この FFrame1 を使ってsampleメソッドを利用すれば、問題ない。

例は悪いかもしれないが、TFrame1は「金型」、FFrame1は「金型を利用してできた生成物(実体)」。
これくらいの違いがあるので、金型に対し、生成物(実体)の情報よこせと命令しても、できるはずがない。


  2022-08-26 20:20:33  No: 150395

ぽ・イ さん。原因が解明しました。
(FFrame1をキーにすればいいということで確証が得られたので、そこを中心に調べたところ)
//-----------------------------
procedure Tframe1.Button1Click();
var
s:string;
begin
s:="xxx";//これはいい
s:=edit1.text;//これもだめ
end;
// -------------

Form1で呼び出したときは、Frame側のTFがForm1になっていて、実質s:=form1.edit1.text 


  2022-08-26 20:23:32  No: 150396

ぽ・イ さん。原因が解明しました。
(FFrame1をキーにすればいいということで確証が得られたので、そこを中心に調べたところ)
//-----------------------------
procedure Tframe1.Button1Click();
var
s:string;
begin
s:="xxx";//これはいい
s:=edit1.text;//これもだめ
end;
// -------------

Form1で呼び出したときは、Frame側のTFがForm1で処理され、実質s:=form1.edit1.text の参照になっておりFrame側のコントロール認識されづに例外
Frameで呼び出したときは、Frame側のTFがFFrame1で処理され、実質s:=FFrame1.edit1.text で処理されるので例外にならないと言う感じでした。


AAAAA  2022-08-27 07:00:26  No: 150397

基本
**** FORM ****

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Frame21: TFrame2;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
    Frame21.Edit1 := Edit1;
end;

end.

**** FRAME ****

unit Unit2;

interface

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

type
  TFrame2 = class(TFrame)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    FEdit: TEdit;
  public
    //Edit: TEdit; (※) property でなくこちらでもOK
  published
    property Edit: TEdit read FEdit write FEdit;
  end;

implementation

{$R *.dfm}

procedure TFrame2.Button1Click(Sender: TObject);
begin
    if Assigned(Edit) = True then
    begin
      showmessage(Edit.Text);
    end;

end;

end.


Mr.XRAY  2022-09-01 22:21:43  No: 150419

TFrame についての記事を書きました.
質問者が意図する内容とは関係ないと思いますが,
検索でこのスレッドに来た方の参考になればと思います.

[ TFrame ( フレーム ) の使用 ]
http://mrxray.on.coocan.jp/Delphi/Others/TFrame.htm


Mr.XRAY  2022-09-06 07:54:43  No: 150427

リンクを貼ったページに以下の記事を追加しました

追加した記事は,質問者の書き込みを,
私なりに解読した結果を踏まえての内容にしたつもりです.
当然ですが,元の,実際のコードが分かりませんので推測です.

[ 06_関数と手続きとメソッドとイベント ]
http://mrxray.on.coocan.jp/Delphi/Others/TFrame.htm#06

# 掲載記事は随時更新する可能性があります.


Mr.XRAY  2022-09-08 06:42:52  No: 150431

> s:=edit1.text;//これもだめ

等というのがありますが,これらは,今回追加した記事では対象外です.
フレームも通常のコンポーネントと同じようにクラスです.
普通にインスタンスを生成して,普通に使用さえすれば何も問題ありません.,
クラスとしてのフレームの実行時生成については,take さんがレスしています.

※ フレームが他のコンポーネントと違うのは,設計時にフォームに配置する手順です.

# 質問者の文章からでは,何が,どこが「普通」ではないかを解読することは不可能です.
# 私はエスパーではありません..


Mr.XRAY  2022-09-08 14:40:09  No: 150432

> # 質問者の文章からでは,何が,どこが「普通」ではないかを解読することは不可能です.
> # 私はエスパーではありません.

おそらく,解読に成功しました.
エニグマの解読に匹敵する快挙かも知れません (笑)

こういうことです.

(1) フレームをフォームに配置,または実行時に生成
(2) フレームを利用する側のフォームに,以下のユニットグローバル変数を宣言
   TFrame : TTestFramee; (TTestFrame は今回のテスト用フレームのクラス名)

質問者の書き込みに

>edit1.text:=Tframe.sample();  
s:=edit1.text;//これもだめ

というのがあります.
1 行目は,最初の書き込みの時現れています.
この時の TFrame はおそらくフレームのユニット名ではないかと思われます.

2 行目の「これもだめ」は,フォーム側からこのコードを実行した場合です.
実際にフォームに配置しているのは,TestFrame1 ですが,TFrame を使用して実行します.
この TFrame はインスタンスが生成されていません.
したがって,例外が発生するというわけです.

ただし,この解読には 1 つ条件があります.それは,

procedure Tframe1.Button1Click();

が間違っているという条件です.
つまり,オン書きのため,引数を忘れているという条件です.  

興味ある方,というより閑な方向きかも ?
テストに使用したプロジェクトです ( EXE 付き ).
http://mrxray.on.coocan.jp/Delphi/zip/TFrameSample_not_make_sense.zip

# レスされた方々,お疲れ様でした.


Mr.XRAY  2022-09-08 15:46:17  No: 150433

悪意のある・・・とかいう表示がでたので,ファイル名を短くしてみました.
http://mrxray.on.coocan.jp/Delphi/zip/TFrameSample.zip


Mr.XRAY  2022-09-11 13:27:23  No: 150435

> おそらく,解読に成功しました. ( 以下,略 ) 

読み返してみたら,文章が変ですね.
説明していない変数なども使用していて.スミマセン.

解読内容は,ダウンロードしたプロジェクトのソースとコメントで理解して頂ければと思います.
コメントを修正して,Delphi 6 で作成したプロジェクトも追加しました.


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加