ユニット分割について

解決


もん  2022-01-28 15:03:38  No: 149980  IP: [192.*.*.*]

おばんさまです。
先日はありがとうございました。

別ユニットについて、あの後いろいろ試してみているんですが
別ユニットでフォームと画像の動的生成を行った場合、同一の場合は機能していたんですが、
別ユニットにするとonclickイベントがエラーになってしまい定義ができない状態になってしまいました。

多分、onclickの親が何?というような話だと思うのですが
アドバイスいただけますと助かります。

Main
-----------------------------------
implementation
uses sample_module;

procedure TForm1.Button1Click(Sender: TObject);
begin
go(sender,self);
end;
-----------------------------------

sample_module.pas
-----------------------------------
unit sample_module;

interface
uses Dialogs,forms,ExtCtrls,Graphics;

procedure go(sender:tobject;form:tform);
procedure aaa(Sender: TObject);

implementation

procedure aaa(Sender: TObject);
begin
showmessage('xxx');
end;
procedure go(sender:tobject;form:tform);
var
ti:timage;
tf: TForm;
begin
tf:= TForm.Create(nil);
tf.Caption := 'overlay';
tf.FormStyle:=fsStayOnTop;
tf.width:=200;
tf.Height:=200;
tf.Show;

ti:=TImage.Create(nil);
ti.Parent:=TForm(tf);
ti.Transparent := True;
ti.Canvas.Ellipse(0,0,100,100);
ti.OnClick :=aaa();
end;

end.
-----------------------------------


編集 削除
KONNOYA  2022-01-29 00:15:53  No: 149981  IP: [192.*.*.*]

関数とメソッドは異なる物でして、
エラーが発生するのは、メソッドを設定して下さいという所に
関数を設定しようとしているからなんだろうと思います。
なので、
var
  Method : TMethod;
begin 
  ・・・
  Method.Code := @aaa;
  Method.Data := Sender;
  Self.OnClick := TNotifyEvent( Method );
end;
と、このように書けばどうでしょうか?

編集 削除
KONNOYA  2022-01-29 01:10:01  No: 149982  IP: [192.*.*.*]

Self.OnClick := TNotifyEvent( Method );
ではなく、
ti.OnClick := TNotifyEvent( Method );
でした。失礼しました。

編集 削除
HFUKUSHI  2022-01-29 01:23:31  No: 149984  IP: [192.*.*.*]

OnClickイベントなどのイベントハンドラは概念的にはいわゆる関数ポインタですが、単純なポインタではなく、インスタンスとメソッドの2つのポインタの組み合わせで、公式ではメソッドポインタと呼んでいます(単純な関数ポインタを公式では手続きポインタと呼んでいます)
https://docwiki.embarcadero.com/RADStudio/ja/%E6%89%8B%E7%B6%9A%E3%81%8D%E5%9E%8B#.E3.83.A1.E3.82.BD.E3.83.83.E3.83.89_.E3.83.9D.E3.82.A4.E3.83.B3.E3.82.BF

type
  TFoo = class(...)
    procedure Bar(...);
  end;

proedure Baz(...);

Barへのポインタは
type
  procedure (...) of object;  // of objectがあるのでメソッドポインタ
ですが、Bazへのポインタは
type
  procedure (...);  // of objectがないので手続きポインタ
と、パラメータが同一でも"型が違う"ということになります。
# BarにはSelf(TFooのインスタンス)が存在しているからですね。

解決策はKONNOYAさんが書いているようにTMethodレコード型経由でインスタンスとメソッドの2つのポインタを組み合わせたうえでOnClickに代入する、ということになります。

ところで質問するときは
> エラーになってしまい
ではなく、コンパイルエラーなのか実行時エラーなのか、どの行で発生しているのか、またエラーメッセージはどのようなものなのかを(メッセージは書き写すのではなくコピペで)書いたほうが適切な回答が得られます(エスパー不要になるので)。

またユニット分割の目的は何でしょう?そのへんも考えながらいろいろ試すといいと思います。

編集 削除
KONNOYA  2022-01-29 04:29:16  No: 149985  IP: [192.*.*.*]

> HFUKUSHI様

私も勉強になりました。
公式で呼称されている文言を使用した方が混乱も少なくなりますね。
ありがとうございます。

> もん様

サブユニットを作成して、その中で関数を作り、動的にフォームを生成していますが、
サブフォームを作成するのなら、Delphiのメニューでフォームの新規作成を行ってサブフォームを作る方が良いと思います。
フォームの新規作成を行えば、自動的に新しいユニット ( ファイル ) も作成されるので、
今回の様に関数として記述するのではなく、その新しいフォームのメソッドとして記述する様にすれば、
TMethodレコード経由で設定…等と小細工しなくても良くなります。

更に生成・解放等のコードも必要無くなり、プロパティ設定はオブジェクトインスペクタ上で行えるので、
コードの記述が少なくなる上に、IDEで直感的な操作でフォームをデザインできる様になります。

私の経験則ですが、動的にコンポーネントを作成する場面は、作成するコンポーネントの数が設計時に分からない時で、
5個生成するのか10個生成するのか、パラメータによって変動する時に使用した方が良いと思います。

編集 削除
Mr.XRAY  2022-01-30 02:04:44  No: 149986  IP: [192.*.*.*]

> サブフォームを作成するのなら   ( 以下,略)

私も,提示されたコードをみて,メインフォームから別のフォームを表示したいのかな ?
と思いました.
しかし,質問のタイトルに「ユニット分割」とあります.
こればかりは本人でないと不明ですね.
本当にユニットの分割方法の検討なのか ?
そのためのテストコードなのか ?
ユニットの分割ではなく,本当はフォームを表示するユニットが必要なのか ? 

編集 削除
Mr.XRAY  2022-01-30 02:12:19  No: 149987  IP: [192.*.*.*]

投稿してから読み直してみたら,
考えてみると,ユニットの分割方法というのもよく意味が分かりませんね.

編集 削除
もん  2022-01-30 17:50:28  No: 149988  IP: [192.*.*.*]

KONNOYA 様ありがとうございます。

>このように書けばどうでしょうか?

できましたぁー♪
TMethod 初めて知りました。この後、検索して知識を深めたいと思います。

>サブフォームを作成するのなら、Delphiのメニューでフォームの新規作成を行ってサブフォームを作る方が良いと思います。 

そのやり方で今まで行っていたのですが、その方法だと別アプリで利用の際に都度作り直しになってしまうので生成処理を別PASに記述し使い回しで動的生成を行おうと思いました。

>5個生成するのか10個生成するのか、パラメータによって変動する時に使用した方が良いと思います。

質問用に短縮しましたが利用時には引数で条件を与え、表示時はhandle指定で最初に破棄をしてから常時新規でフォーム生成を行う感じを想定しております。

>HFUKUSHI様
>またユニット分割の目的は何でしょう?

前回はありがとうございました。
同一処理の別アプリ作成時の使い回しを目的としております。


>Mr.XRAYさま。

ありがとうございます。
いつもコッソリサイトを活用させていただいております(^-^)

>提示されたコードをみて,メインフォームから別のフォームを表示したいのかな ?
と思いました. 

ずばり、その通りなんですが、ツール作成時に修正用の処理をオーバレイフォームで多用するのですが、いつも同じ処理のUNITをIDEから新規フォームで作成した場合、1つに多数含めると非表示処理が必要になる&別の物を作るたびに打ち直しになるとう手間がかかるのでフォーム関係の表示とか位置調整とかを関数化し、.PASのインクルードで使い回したく思った次第です。

たぶん、DLLでするような物だと思いますが、DLLにしてしまうと作成時に手間がかかりそうなのでユニットに関数群をひっぱり処理をまとめようと思った次第です。

>ユニットの分割ではなく,本当はフォームを表示するユニットが必要なのか ? 
>ユニットの分割方法というのもよく意味が分かりませんね.

いつも利用する各処理を部品化し.pasのインクルードでの使い回しを目的としています。
自分はWEB制作利用の方が多いので関数の外部ファイル化と言う方がしっくりくるんですが前回、ユニットの分割と言う方がdelphiでは一般的だと習ったので使ってみました。

https://www.petitmonte.com/bbs/answers?question_id=29920

編集 削除
もん  2022-01-30 19:45:20  No: 149989  IP: [192.*.*.*]

KONNOYA様。

clickは上手くいきましたが、mousedownやmousemoveで行う場合は
下記のようにしてみたところ
Incompatible types: 'TShiftState' and 'Enumeration'
というエラーになっしまいました。

この場合は、どのような感じで回避できますでしょうか?
度々すいませんがよろしくお願いいたします。

Method.Code := @me(sender,mbLeft,ssLeft,10,10);
Method.Data := Sender;
comp_curvy.OnMouseDown := TNotifyEvent( Method );

編集 削除
Mr.XRAY  2022-01-31 00:13:14  No: 149990  IP: [192.*.*.*]

OnClick や OnMouseMove コントロールのイベントです.
だから TMethod を使用しているわけです.

イベントには型があります.
TControl.OnMouseMove のイベントの型は TMouseMoveEvent です.
TControl.OnClick のイベントの型は TTNotifyEvent てず.

TNotifyEvent( Method )

というのは,メモリ上のデータを,この型のデータとして操作することを意味します.
別の型ではメモリ上のデータが持つ意味が異なります.
OnClick と OnMouseMove とでは引数が違います.
ということは,メモリ上のデータが違うということです.
このことを,一般的に型キャストと言っています.

https://docwiki.embarcadero.com/Libraries/Sydney/ja/Vcl.Controls.TMouseMoveEvent


編集 削除
KONNOYA  2022-01-31 04:04:12  No: 149991  IP: [192.*.*.*]

>>サブフォームを作成するのなら、Delphiのメニューでフォームの新規作成を行ってサブフォームを作る方が良いと思います。 

>そのやり方で今まで行っていたのですが、その方法だと別アプリで利用の際に都度作り直しになってしまうので生成処理を別PASに記述し使い回しで動的生成を行おうと思いました。

ここがちょっと良く分からなかったのですが、
フォーム ( ユニット ) の使いまわしはできますよ?
メソッドを切り替えるのも簡単です。

関数をメソッドに動的に割り当てるのは通常のやり方ではないと思いますが、
どの様な特殊な事情があるのでしょう?

編集 削除
take  2022-01-31 04:17:33  No: 149992  IP: [192.*.*.*]

もしかしてサブフォームと呼ばれる子フォームを複数呼んでいて
その子フォームの表示内容はフォームごとに異なるけど
関数群を各フォームごとに記述するのではなく共通のどこかで定義出来ないか?
って話なのかなぁ

1.単なる関数だったら別ユニットファイルに定義してインクルードするだけ
2.データも所持するならクラス化
3.共通するフォームの要素にアクセスしたいなら共通フレームを作ってフォームから呼ぶ

編集 削除
もん  2022-01-31 05:21:08  No: 149993  IP: [192.*.*.*]

>Mr.XRAY 様
>TControl.OnClick のイベントの型は TTNotifyEvent てず.

お返事ありがとうございます。
そこがダメだったんですね。

普通にフォームに記述する場合は下記で動くので
image1.onMouseDown(Self,mbLeft,[ssLeft],10,10);

下記のように変更してみましたが下記のエラーが表示されてしまいます。
Incompatible types: 'TShiftState' and 'TMouseButton
---------------------------------------------
Method.Code := @me(sender,mbLeft,[ssLeft],10,10);
Method.Data := Sender;
ti.OnMouseMove :=  TMouseMoveEvent( Method );


procedure me(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
  begin
  showmessage('xxx');
  end;
---------------------------------------------

>KONNOYA様
>どの様な特殊な事情があるのでしょう?

仕事で指示されているわけでは無いので特殊な事情というのは無いんですが

例えばrichedit等だとcontextmenuがデフォで無いので、押した返り値だけ取得できれば良いので、定型のガワだけ用意しておき、色々なフォームやアプリを作った際にも、項目名を投げるだけでて内容を変更しクリックで返り値をえたり、stringgridでユニークなindexを生成するなど同じ処理を行う事が多いので、その部分を1つのファイルを引っ張ることにより使い回して部品化したく思いました。

>take様。
>関数群を各フォームごとに記述するのではなく共通のどこかで定義出来ないか?って話なのかなぁ

それです!!
なので①を進めている感じになると思います。

編集 削除
take  2022-01-31 07:54:22  No: 149994  IP: [192.*.*.*]

>利用時には引数で条件を与え、表示時はhandle指定で最初に破棄をしてから常時新規でフォーム生成を行う感じを想定しております。

ここだけ読むと親フォームがあって、そこから子フォームを呼ぶけど、
子フォームには種類があって親フォームからの操作でどの子フォームが呼ばれるのかが決まる
でもフォームは1つでいいので表示してあるフォームがあれば破棄してから表示する
のですが、そこは質問の本質ではないのかな?

>項目名を投げるだけでて内容を変更しクリックで返り値をえたり、stringgridでユニークなindexを生成

各パーツ(コンポーネント)は複数配置するけどその設定初期値や値のやり方が面倒ってことなら

1.フレームを使用してフレームにコンポーネントを配置する
 フレームにはそのコンポーネントを使いやすくするプロパティやメソッドを用意する
 フォームの方には作ったフレームを1つまたは複数配置してフレームを通じて値をやりとりする。
2.コンポーネントを自分なりに使いやすく拡張する
 RichEditが使いづらいのならTRichEditを継承したコンポーネントを作成
 そのコンポーネントをフォームに動的に配置する

それか値に関してもっと難しい技術を要望しているのかな?
RTTI実行時型情報を使って親フォームから子フォームの
「コンポーネント名」「プロパティ名」「値」を読み書きするって話なら
それで論文が書けるぐらいの情報量になってしまいますし(個人的には作りましたが)

編集 削除
もん  2022-01-31 09:41:14  No: 149995  IP: [192.*.*.*]

>take様
>そこは質問の本質ではないのかな?

そこは問題ない状態になっており、フレームというのが何をする物か理解できていないので調べて見みました。

https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwid3rieztv1AhUWIIgKHQxXA38QFnoECAIQAQ&url=https%3A%2F%2Fwww.migaro.co.jp%2Fcontents%2Fsupport%2Ftechnical_report_search%2Fno08%2Ftech%2F08_01_01.pdf&usg=AOvVaw2PXW2rNb5ja1Wip6RPfN4M

ここで言っている、①の部分が本質になると思います。
-----------------------------
処理を共通化する方法には  大きく以下の4つの方法がある。

①共通関数ユニットによる処理の共通化
②コンポーネントによる部品の共通化
③継承によるクラスの共通化
④フレームによる画面一部の共通化
-----------------------------

例えば、画面にクロスバーをオーバーレイさせ座標を取得するプログラムを作るとします。

その処理は、画像アプリを作るのならCropに使いますし
別の色取得アプリを作るとしても同じ処理になり
マウスの座標でAuto-hideさせるにも利用したりと同じ処理を共通で使えると思います。

なので外部のPASでフォームやオーバーレイを定義すると
mousemoveで座標を得る感じになるとおもいますが、そのイベントを定義できない状態で、mousemoveイベントを共通関数群のあるPASで得たいと言うのが本質になります。

なので、コンポーネントを拡張したいのではなく共通につかう処理を1つのPASでまかないたい感じになります。

たとえばsendkeyをカスタム出来るアプリを作る場合は、あの何十個もあるくみあわせをアプリを作るたびに表記していくのでは無く、関数化しPASのインクルードで引数指定で利用できると便利になると思います。

>「コンポーネント名」「プロパティ名」「値」を読み書きするって話なら
それで論文が書けるぐらいの情報量になってしまいます

設定初期値や値のやり方の面倒さや各種情報の取得は、openTOOLSAPIの利用やプロパティーの取得はソースから正規表現で抜くという形で過去に妥協&挫折しました。

理由としては、画面に貼り付ける or usesしないと取得できないと判断したためで、
必要なときにプロパティーを調べるのには向いていなく、たぶん、usesしたソースとして保存を行い、それをコマンドラインコンパイルで個別にusesし表示させる感じになるのではと思っています。

なので、下記のような物を利用する場合、StdCtrlsがusesされていないとエラーになるとおもいますがusesされていない場合はエラーとして認識されないようにしusesされている場合にのみ関数を利用できるようにしたいと言う課題が残っているくらいになります。

tm := Form.FindComponent('memo1') as TMemo;

編集 削除
Mr.XRAY  2022-01-31 15:14:53  No: 149996  IP: [192.*.*.*]

> そこがダメだったんですね。

そこはそこですが,引数が複数あるということです.
提示されたコードでは当然動作しません.残念ながらコードに対する理解が必要です.


> mousemoveイベントを共通関数群のあるPASで得たいと言うのが本質になります。


そういう場合はクラスメソッドを使用するのが確実で便利です.
クラスのイベントは文字通りクラスのメンバです
以下はその例です.
  


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

type
  // このクラスのコードを別ユニットにすれば他のプロジェクトからも利用可能
  // 必要性の有無は別として・・・ 
  TMyCommClass = class(TObject)
  
  private
    FTargetCtrl : TControl;
    FDispCtrl    : TControl;
    procedure SetTargetCtrl(const Value: TControl);
  protected
   procedure OnMouseDownEvent(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  public
    property TargetCtrl: TControl read FTargetCtrl write SetTargetCtrl;
    property DispCtrl: TControl read FDispCtrl write FDispCtrl;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

var
  FMyCommClass : TMyCommClass;

  procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyCommClass := TMyCommClass.Create;
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FMyCommClass);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FMyCommClass.TargetCtrl := Form1;
  FMyCommClass.DispCtrl := Panel1;
end;

{ TMyCommClass }

type
  TMyControl = class(TCustomControl);

procedure TMyCommClass.OnMouseDownEvent(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if FDispCtrl <> nil then begin
    TMyControl(FDispCtrl).Caption := TMyControl(Sender).Name;
    TMyControl(FDispCtrl).ParentBackground := False;
    TMyControl(FDispCtrl).Color := clGreen;
  end;
end;

procedure TMyCommClass.SetTargetCtrl(const Value: TControl);
begin
  FTargetCtrl := Value;
  if FTargetCtrl <> nil then begin
    TMyControl(FTargetCtrl).OnMouseDown := OnMouseDownEvent;
  end;
end;

end.

編集 削除
もん  2022-01-31 17:33:17  No: 149997  IP: [192.*.*.*]

Mr.XRAY 様ありがとうございます。

早速入力してみたんですが、その並びで入力したところ

Varのところで Undeclared identifier: 'TMyCommClass' が出てしまったので上の方にtype TMyCommClass = class(TObject);を移してみたところ
今度はUndeclared identifier: 'OnMouseDownEvent' になってしまいました。

{ TMyCommClass }と区切ってあることから察するに、そこに記述が必要という意味では無く
別の使い方を意味している可能性があると思うのですが、// このクラスのコードを別ユニットにすれば他のプロジェクトからも利用可能との事なので
そこを意味するのかなとおもい分離したく思いましたが、この場合のどのように分離し記述を行えばいいかが想像できない感じです。

すいませんが、そこら辺をご指導いただけませんでしょうか。 

編集 削除
Mr.XRAY  2022-01-31 22:24:53  No: 149998  IP: [192.*.*.*]

新規にプロジェクトを作成して,
Unit1 のコードを以下にしてコンパイルします.
EXE を起動したら,Button1 をクリックしてから From1 上でマウスダウンします.
Form1 にはマウスダウンのコードはありませんが,マウスダウンのイベントが発生します.
そして,Form1 上に配置した TPanel の色が変わります.

イベントを発生させるコードはクラス型として定義しているので,
このクラスのインスタンスを別に生成すれば,別のコントロールのイベントの捕捉も可能です.
  
    
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.ExtCtrls;

type
  // このクラスのコードを別ユニットにすれば他のプロジェクトからも利用可能
  // 必要性の有無は別として・・・  
  TMyCommClass = class(TObject)
  private
    FTargetCtrl : TControl;
    FDispCtrl : TControl;
    procedure SetTargetCtrl(const Value: TControl);
  protected
   procedure OnMouseDownEvent(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  public
    property TargetCtrl: TControl read FTargetCtrl write SetTargetCtrl;
    property DispCtrl: TControl read FDispCtrl write FDispCtrl;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

var
  FMyCommClass : TMyCommClass;   
    
procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyCommClass := TMyCommClass.Create;
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FMyCommClass);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // TargetCtrl はマウスのイベントを受け取るコントロール
  FMyCommClass.TargetCtrl := Form1;
  // 動作確認表示用
  FMyCommClass.DispCtrl := Panel1;
end;

{ TMyCommClass }

type
  TMyControl = class(TCustomControl);

procedure TMyCommClass.OnMouseDownEvent(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  LColor : TColor;
begin
  if FDispCtrl <> nil then begin
    TMyControl(FDispCtrl).Caption := TMyControl(Sender).Name;
    TMyControl(FDispCtrl).ParentBackground := False;

   LColor := RGB(Random(255), Random(255), Random(255));
    TMyControl(FDispCtrl).Color := LColor;
  end;
end;

procedure TMyCommClass.SetTargetCtrl(const Value: TControl);
begin
  FTargetCtrl := Value;
  if FTargetCtrl <> nil then begin
    TMyControl(FTargetCtrl).OnMouseDown := OnMouseDownEvent;
  end;
end;

end.

編集 削除
Mr.XRAY  2022-01-31 23:09:13  No: 149999  IP: [192.*.*.*]

別ユニットにする例です.

    
unit HogeHoge;

interface

uses
  Winapi.Windows, System.Classes, Vcl.Graphics, Vcl.Controls;

type
  TMyCommClass = class(TObject)
  private
    FTargetCtrl : TControl;
    FDispCtrl : TControl;
    procedure SetTargetCtrl(const Value: TControl);
  protected
   procedure OnMouseDownEvent(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  public
    property TargetCtrl: TControl read FTargetCtrl write SetTargetCtrl;
    property DispCtrl: TControl read FDispCtrl write FDispCtrl;
  end;

implementation

{ TMyCommClass }

type
  TMyControl = class(TCustomControl);

procedure TMyCommClass.OnMouseDownEvent(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  LColor : TColor;
begin
  if FDispCtrl <> nil then begin
    TMyControl(FDispCtrl).Caption := TMyControl(Sender).Name;
    TMyControl(FDispCtrl).ParentBackground := False;

    LColor := RGB(Random(255), Random(255), Random(255));
    TMyControl(FDispCtrl).Color := LColor;
  end;
end;

procedure TMyCommClass.SetTargetCtrl(const Value: TControl);
begin
  FTargetCtrl := Value;
  if FTargetCtrl <> nil then begin
    TMyControl(FTargetCtrl).OnMouseDown := OnMouseDownEvent;
  end;
end;

end.
    
              
上のユニットを使用する側のコード例です.
フォーム上でマウスダウンすると TPanel の色が変わります.
Button1 上でマウスダウンするとフォームの色が変わります.

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  HogeHoge;

{$R *.DFM}

var
  FMyCommClass1 : TMyCommClass;
  FMyCommClass2 : TMyCommClass;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyCommClass1 := TMyCommClass.Create;
  FMyCommClass2 := TMyCommClass.Create;

  FMyCommClass1.TargetCtrl := Form1;
  FMyCommClass1.DispCtrl := Panel1;

  FMyCommClass2.TargetCtrl := Button1;
  FMyCommClass2.DispCtrl := Form1;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FMyCommClass1);
  FreeAndNil(FMyCommClass2);
end;

end.

編集 削除
take  2022-02-01 02:12:16  No: 150000  IP: [192.*.*.*]

>同一処理の別アプリ作成時の使い回しを目的としております。

作ったFormは他のプロジェクトでも呼び出せるけど違うのかな?
フォームに配置したパーツを流用したいなら前にも紹介したフレームになりますが

>、StdCtrlsがusesされていないとエラーになるとおもいますが
>usesされていない場合はエラーとして認識されないようにし
>usesされている場合にのみ関数を利用できるようにしたいと言う課題が残っているくらいになります。

さらっととんでもないことを書いているように見えるのですが・・・
条件コンパイルと、動的関数呼び出しを考えているのかな?

なんとなくですが、実はもっと簡単なやり方があるけど
仕様を先に決めて考えを固定しているせいで、設計が困難になってる
というもので無ければ良いのですが

前の質問で
>tm:=  TMemo(frm1.FindComponent('memo1'));
って書いてるけどJAVAあたりから来てるのかな?
※Delphiではあまりしない書き方なので

やりたいことをもっと簡潔に書いて頂ければ、もっと良い方法が見つかるかも

編集 削除
Mr.XRAY  2022-02-02 11:08:05  No: 150010  IP: [192.*.*.*]

質問された方が提示したコードに TImage の操作がありましたのでやってみました.
プロパティの設定で例外が発生しました.
TForm.OnCreate の段階では TImage は完全に生成されていないようです.
で,修正したコードです.

ユニットのコードです.
  
    
unit HogeHogeTImage;

interface

uses
  Winapi.Windows, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.ExtCtrls;

type
  TMyCommTImageClass = class(TComponent)
  private
    FTargetCtrl : TImage;
    procedure SetTargetCtrl(const Value: TImage);
  protected
   procedure OnMouseDownEvent(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  public
    property TargetCtrl: TImage read FTargetCtrl write SetTargetCtrl;
  end;

implementation

{ TMyCommClass }

procedure TMyCommTImageClass.OnMouseDownEvent(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  LColor : TColor;
begin
  LColor := RGB(Random(255), Random(255), Random(255));
  FTargetCtrl.Canvas.Brush.Color := LColor;
  FTargetCtrl.Canvas.FillRect(FTargetCtrl.Canvas.ClipRect);
end;

procedure TMyCommTImageClass.SetTargetCtrl(const Value: TImage);
begin
  FTargetCtrl := Value;
  if FTargetCtrl <> nil then begin
    FTargetCtrl.OnMouseDown := OnMouseDownEvent;
  end;
end;

end.
  
    
 ユニットを使用する側のコードです.
   

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  HogeHogeTImage;

{$R *.DFM}

var
  FMyCommClass1 : TMyCommTImageClass;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if FMyCommClass1 = nil then begin
    FMyCommClass1 := TMyCommTImageClass.Create(Self);
  end;
  FMyCommClass1.TargetCtrl := Image1;
end;

end.

編集 削除
Mr.XRAY  2022-02-02 11:10:41  No: 150011  IP: [192.*.*.*]

フォームのユニットと,それを使用する側のプロジェクトのサンプルも作成してみました.
ダウンロードして,ブロックを解除してから解凍してください.
説明は全てコード内にコメントとして書いておきました.

http://mrxray.on.coocan.jp/Delphi/zip/HogeForm.zip

編集 削除
Mr.XRAY  2022-02-02 13:04:29  No: 150012  IP: [192.*.*.*]

> フォームのユニットと,それを使用する側のプロジェクトのサンプルも作成してみました.
http://mrxray.on.coocan.jp/Delphi/zip/HogeForm.zip

中身は普通のフォームのユニットです.特別な処理はありません.
質問者の意図を十分理解しているわけではありません.
解読できたらまた追加します.

編集 削除
Mr.XRAY  2022-02-02 22:17:44  No: 150013  IP: [192.*.*.*]

ゴメンなさい.

> TForm.OnCreate の段階では TImage は完全に生成されていないようです.

ということは以下ですね.
これで TForm.Create でクラスのインスタンスを生成しても問題ありません.
失礼しました.アップした ZIP 書庫内のファイルも修正しました. 

procedure TMyCommTImageClass.SetTargetCtrl(const Value: TImage);
begin
  if csLoading in ComponentState then Exit;   // これを追加

  FTargetCtrl := Value;
  if FTargetCtrl <> nil then begin
    FTargetCtrl.OnMouseDown := OnMouseDownEvent;
  end;
end;

としておけば,ユニットを利用する側は以下で OK です.

uses
  HogeHogeTImage;

{$R *.DFM}

var
  FMyCommClass1 : TMyCommTImageClass;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyCommClass1 := TMyCommTImageClass.Create(Self);
  FMyCommClass1.TargetCtrl := Image1;
end;

編集 削除
もん  2022-02-07 20:28:03  No: 150026  IP: [192.*.*.*]

Mr.XRAY 様。サンプルありがとうございます。
解読してみているんですが、classと言う物になじみが無いので難航中です(>_<)

>質問者の意図を十分理解しているわけではありません. 

意図としましては、メインフォームの指示で外部PASにて動的にフォームを生成し
そのフォームのイベントを外部PAS内でキャッチしたい感じです。

メインフォーム
----------------------------------------
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
Form1: TForm1;

implementation
uses sample_module;

{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
go(sender,self);
end;
end.
----------------------------------------

sample_module.pas
----------------------------------------
unit sample_module;

interface
uses Dialogs,forms,ExtCtrls,Graphics,Controls,Classes;

procedure go(sender:tobject;form:tform);

implementation

procedure OnMouseDownEvent(********);
begin

end;

procedure OnMouseMoveEvent(********);
begin

end;

procedure go(sender:tobject;form:tform);
var
ti:timage;
tf: TForm;
begin
tf:= TForm.Create(nil);
tf.Caption := 'overlay1';
tf.FormStyle:=fsStayOnTop;
tf.width:=200;
tf.Height:=200;
tf.Show;

ti:=TImage.Create(nil);
ti.Parent:=TForm(tf);
ti.Transparent := True;
ti.Canvas.Ellipse(0,0,100,100);
//ti.OnMouseDown := OnMouseDownEvent;
//ti.OnMouseMove := OnMouseMoveEvent;
end;

end.
----------------------------------------

>take様ありがとうございます。
>作ったFormは他のプロジェクトでも呼び出せるけど違うのかな? 
>条件コンパイルと、動的関数呼び出しを考えているのかな?

決まったフォームを呼び出したいという感じでは無く
動的に中身の違うフォームを引数に応じて作成したい感じです。

なので、中身にサードパーティーのコントロールを利用する関数を利用していた場合は
使う使わないに限らずにusesが必要になると思います。

イメージだと、コンポーネント一覧を表示しプロパティーをtypeinfoで表示しようとするとusesしていないコンポーネントの情報は表示されませんよね。なので全コンポーネントをusesするのも現実的では無いと思います。なので、一覧から選んだときのみ動的にusesさせるためには、ソースをテキストで持ちコマンドラインでusesと一覧する物を動的に生成し、データーとして出力し、その返り値を得るのではと考えた次第です。

編集 削除
Mr.XRAY  2022-02-08 03:14:50  No: 150028  IP: [192.*.*.*]

> 決まったフォームを呼び出したいという感じでは無く
> 動的に中身の違うフォームを引数に応じて作成したい感じです。

そういう場合は,以下のように全て自前でコントロールを生成することになります.
これは,貴方が既に書かれている

> 共通につかう処理を1つのPASでまかないたい感じになります。

という趣旨のものとは言えなくなりますし,ユニットの分割とも言えませんね.

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    procedure OnBtnClickEvent(Sender: TObject);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  LForm    : TForm;
  LButton1 : TButton;
  LButton2 : TButton;
begin
  LForm := TForm.Create(Self);

   LForm.Position := poDesigned;
   LForm.Width := 300;
   LForm.Height := 200;
   LForm.Left := Self.Left + Self.Width;
   LForm.Top := Self.Top - Self.Height;

   LButton1 := TButton.Create(LForm);
   LButton1.Parent := LForm;
   LButton1.Left := 20;
   LButton1.Top  := 20;
   LButton1.Caption := 'Button1';
   LButton1.OnClick := OnBtnClickEvent;

   LForm.Show;
end;

procedure TForm1.OnBtnClickEvent(Sender: TObject);
begin
  ShowMessage('Clicked !!');
end;

end.

> 動的にusesさせるためには

実行時に uses 部を編集することはできません.
プログラムのコードをコンパイルすると EXE ができます.
その EXE はマシン語と呼ばれるコードになります.
その時,Uses 部のユニットのコードを参照してマシン語を生成します.
つまり,たとえできたとしても意味がありません.
uses 部に必要なユニットがないと,コンパイル時に [xxx.dcu が見つかりません] のエラーが発生します.
このエラーは実行時でなく,コンパイル時に発生します
つまり,実行時にユニットを参照するのではありません..
マシン語は EXE を生成した時のプログラムのコードではありません.

そもそも

> 決まったフォームを呼び出したいという感じでは無く
> 動的に中身の違うフォームを引数に応じて作成したい感じです。

なのであれば,uses 部に必要なユニットは,
上のコードで示すように呼び出し側 (フォームを生成する側) の設定になります.

編集 削除
Mr.XRAY  2022-02-08 07:53:53  No: 150031  IP: [192.*.*.*]

> 決まったフォームを呼び出したいという感じでは無く
> 動的に中身の違うフォームを引数に応じて作成したい感じです。

> 外部PASにて動的にフォームを生成し
> そのフォームのイベントを外部PAS内でキャッチしたい感じです。

フォームに,実行時にコードでコントロールを生成して配置して使用する場合,
それらのコントロールのイベントの処理コードは,呼び出し側のユニットに書くことになります.
フォームを新規に作成する場合も当然そうなります.
フォームにはどんなコントロールが配置されるのか,
どんなイベントが必要なのか分からないので.そうなります.
それが分かるのなら,それらのコントロール類を配置したフォームを利用すればいいのてずから.

編集 削除
Mr.XRAY  2022-02-08 13:24:38  No: 150033  IP: [192.*.*.*]

> そのフォームのイベントを外部PAS内でキャッチしたい感じです。

「そのフォームのイベント」
を「フォームに配置したコントロールのイベント」と解釈しています.
文字通り「フォームのイベント」でしたらメッセージ処理で捕捉できます.

編集 削除
もん  2022-02-08 16:21:46  No: 150034  IP: [192.*.*.*]

>つまり,たとえできたとしても意味がありません.
>uses 部に必要なユニットがないと,コンパイル時に [xxx.dcu が見つかりません] のエラーが発生します.

そうですよね。なので、ソースをテキストで持ち、必要なときにusesを加えたソースを投げ
コマンドラインでコンパイルし、その実行で結果をoutputoしメインで取得するしか無いのかな。と思った感じになります。

ただ、IDEで補完が行われているのでもしかしたら、OTAあたりで取得できるのかなとも思った次第ですが、そちらは、こういうことがあったという程度の話で本題とは外れてしまいお手数かけるわけには行きませんので放置していただいても大丈夫です(>_<)そこの部分とtregexprがOTAでuses出来ないのだけが疑問点でした。

>それらのコントロールのイベントの処理コードは,呼び出し側のユニットに書くことになります. 
>文字通り「フォームのイベント」でしたらメッセージ処理で捕捉できます. 

そこが出来ると思っていたので理解が進まなかったんですね。

前回のTTNotifyEventで、OnClickは補足できたので、なら、moveやdownも
TMouseMoveEvent の型の処理で同じように外部側で解決できると思ってしまいました。

呼び元でメッセージ処理については理解できていますので大丈夫感じになります。

あれ?読み直してみたら、外部のpasでフォーム精製時に一緒にApplicationEventsを動的生成して、それを処理すれば出来る気がしてきました。それは試していなかったので今から試してみます。メインフォームではダブルクリック取得時等にApplicationEventsを使いますが、そこの発想はありませんでした。

編集 削除
take  2022-02-08 22:55:31  No: 150035  IP: [192.*.*.*]

>必要なときにusesを加えたソースを投げ
>コマンドラインでコンパイルし、その実行で結果をoutputoしメインで取得するしか無いのかな。

Delphiはスクリプト言語ではないので そういう使い方は想定されていません。
どうしても自分でソースを生成、管理したものを実行時に使いたいというのであれば
スクリプト言語形式のDelphiを使うしかありません。

大昔にProject-PPAというDelphiで使えるDelphi仕様のスクリプトがありましたが今使うべきではないでしょう

単なるクラスの設計とイベントの継承などで実現可能なことを わざわざ難しくしてません?
質問に答える方も混乱します。

1回 ちゃんと完成させてから、そのソースを再利用可能にするために改良していけば
再利用できるようになるでしょう。

編集 削除
もん  2022-02-09 02:33:37  No: 150039  IP: [192.*.*.*]

>Delphiはスクリプト言語ではないので そういう使い方は想定されていません。 

たしかMr.XRAY様のページで解説してあった気がしていたきがしまして・・・。
思い出しては、そこも踏まえ色々な手法がないか探ってみたりしていたしだいです。
(と言ってもMr.XRAY様とDEKO様と白地にオレンジ色の文字ページをグルグルになってしまいますが(>_<)。今はURLを無くしてしまい白地オレンジのページは不明なんですが、やってることが面白い&マッチしているので検索するとちょくちょくいくかんじになってますが。)

>単なるクラスの設計とイベントの継承などで実現可能なことを わざわざ難しくしてません? 

イメージ的にコンポーネントパレットのプロパティーを外部アプリで取得するには、ちゃんと完成=全部uses もしくは全コントロールの貼り付け
なイメージをしているので、手段的にブラウザーでソースをテキストで持ち投げるように、テキストでソースを持ち必要なときに投げてコンパイルなイメージになっています。






編集 削除
take  2022-02-09 04:03:12  No: 150040  IP: [192.*.*.*]

>手段的にブラウザーでソースをテキストで持ち投げるように、
>テキストでソースを持ち必要なときに投げてコンパイルなイメージになっています。

ここにきて これが今までで一番わかりやすい質問内容なのですが・・・

Delphiでプログラムソースファイル pasを管理していている。
ListBoxにソースファイルがリスト表示されていて
選択してボタンを押すと、そのDelphiソースファイルが実行され
返り値の表示や、ソース内のプロパティからメインプログラムのフォームも触りたい。

こうですか?

それならやっぱり他のスクリプト言語か、Delphi Project-PPAでやる内容ですよ

編集 削除
KONNOYA  2022-02-09 08:22:53  No: 150041  IP: [192.*.*.*]

ずっと読んでいましたが、なんだかよく分からなくなってきました(汗

最初に申し上げましたが、関数とメソッドは異なる物です。
通常はクラスを作成し、クラス自体を部品と捉え、流用したりします。
Mr.XRAY様が提示したコードが一般的な手法だと思います。


通常はこんな場面に遭遇しませんが、
もしかして下記の様な事を求めていらっしゃいます?
コンパイラ指令のincludeを使用してユニット(ファイル)を分割するコードを貼り付けます。


【 メインフォームのユニット:Unit1.pas 】

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TMainForm = class( TForm )
    Button1 : TButton;
    procedure Button1Click( Sender: TObject );
    // プロトタイプ宣言のインクルード
    {$INCLUDE SubType.pas}
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}
// コードのインクルード
{$INCLUDE SubCode.pas}

procedure TMainForm.Button1Click( Sender: TObject );

begin
  Go( Sender, Self );
end;

end.


【 プロトタイプ宣言のユニット:SubType.pas 】

procedure Go( Sender: TObject; Form: TForm );
procedure Click( Sender: TObject );
procedure MouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer );


【 コードのユニット:SubCode.pas 】

procedure TMainForm.Go( Sender: TObject; Form: TForm );

var
  TF : TForm;
  TI : TImage;

begin
  // フォーム
  TF := TForm.Create( nil );
  TF.Parent := nil;
  TF.Caption := 'overlay';
  TF.FormStyle := fsStayOnTop;
  TF.Position := poScreenCenter;
  TF.Width := 300;
  TF.Height := 200;
  TF.Show;

  // イメージ
  TI := TImage.Create( nil );
  TI.Parent := TForm( TF );
  TI.Transparent := True;
  TI.Canvas.Ellipse( 0, 0, 100, 100 );

  TI.OnClick := Click;
  TI.OnMouseMove := MouseMove;
end;

procedure TMainForm.Click( Sender: TObject );

begin
  ShowMessage( 'Click!' );
end;

procedure TMainForm.MouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer );

begin
  TForm( TImage( Sender ).Parent ).Caption := 'Move!';
end;

※ プロジェクトマネージャには、SubType.pasとSubCode.pasを含めない様にして下さい。
   アプリケーションのプロジェクトディレクトリにファイルを置くだけです。

もし、外していたらすみません。

編集 削除
もん  2022-02-09 21:02:31  No: 150043  IP: [192.*.*.*]

>take 様

>選択してボタンを押すと、そのDelphiソースファイルが実行され
>返り値の表示や、ソース内のプロパティからメインプログラムのフォームも触りたい。
>こうですか?

概ねそのような感じですが目的としてはコンポーネントのプロパティーを必要なときに外部アプリで取得をしたい。でも、そのためにはusesしなければ取得できない。が、必要あるなしにかかわらずusesしなくてはいけない、ので、選択してボタンを押すと、usesしたDelphiソースを生成し、それをコンパイル実行でusesされた物を作りプロパティーをtext書き出しと考えました。メインフォームを操作できるかどうかは必要ない感じになり、理想は外部アプリでコントロール名だけでプロパティーを参照できることを求めている感じになります。

なので、Mr.XRAY様のページでみたであろうコマンドラインコンパイルというのがソーステキストのPASを与えて実行ファイルを作れるという認識で捉えているので、そのような物で無かった場合は、まったく自分の勘違い想定な感じです(実際には実行まではたどり着け無いでおわらせてしまったので・・・。あっ。ですがMr.XRAY様に解説してほしいと言っているわけではないので触れなくても大丈夫です。次に試したときにもう少し自身で突き進められるとおもうので)

>KONNOYA様。 

>最初に申し上げましたが、関数とメソッドは異なる物です。 

メソッドはコントロール等に用意されている物で、関数は自作する物と言う認識しか無いのですが・・・そこの認識が違うととどのような問題に接触するかが把握できていない感です。

>もしかして下記の様な事を求めていらっしゃいます? 

すっごく近くなりました!!
それのSubType.pas がSubCode.pasに含まれている物を求めています。

上記のような状態になっており、引数で呼び出し元等が変わっても
動作する物を求めています。

今回のはMr.XRAY様の言うようにメインフォームにマウスイベントを記述しなくてはいけない。そぼ用にしたければ表示上別ファイルに出来るという感じで認識しましたが

求めている理想の物は
KONNOYA 様に最初に教えていただいた Self.OnClick := TNotifyEvent( Method ); 
のようにフォームの動的生成と同じ外部ファイルにイベント処理ももちつつSelf.Onmousedownや Onmousemoveを似たような感じで処理できるのを求めている感じです。


それと前回のmessageで取得する方法も同じ理由で動的生成しても使い方がわからない
感じで無理な気がしてきました。

------------------------------
unit sample_module;

interface
uses windows,Dialogs,forms,ExtCtrls,Graphics,Controls,Classes,SysUtils,AppEvnts,messages, StdCtrls;

procedure go(sender:tobject;form:tform);
procedure ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);

implementation

procedure ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var
Message: TMessage;
Pt: TPoint;
begin
showmessage(inttostr(Msg.pt.X));
end;

procedure go(sender:tobject;form:tform);
var
ti:timage;
tf: TForm;
ta:TApplicationEvents;
begin
tf:= TForm.Create(nil);
tf.Caption := 'overlay1';
tf.FormStyle:=fsStayOnTop;
tf.width:=200;
tf.Height:=200;
tf.Show;

ta:=TApplicationEvents.Create(nil);
//ta.Parent:=TForm(tf); //使えない
ta.OnMessage:= ApplicationEvents1Message;//ここもKONNOYA様の言う関数とプロパティーは違うという理由で参照不可
end;
------------------------------

編集 削除
take  2022-02-09 23:34:51  No: 150044  IP: [192.*.*.*]

説明されればされるほど 内容を理解出来なくなっているのは自分だけでしょうか・・・

「コマンドラインコンパイル」とか「外部ファイルが・・」を全部無視して

「別ユニット」、「クラスの動的生成」、「OnClickイベントがエラー」
この辺からの勝手な推測ですが
動的生成とイベント割り当てとか理解されていないとかかな?

新規フォームにボタン2つ パネル1つ置いた状態で
Button1クリックイベントの方と、ButtonClientClickメソッドを追加しました。

単純なコードながら動的生成とイベント割り当てのサンプルです。
これを実行して どうしてこういう動作になるのか理解出来ますか?

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    procedure ButtonClientClick(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  tf: TForm1;
begin
  tf := TForm1.Create(Self);
  tf.Parent := Panel1;
  tf.Align := alClient;
  tf.Button2.OnClick := ButtonClientClick;
  tf.Show;
end;

procedure TForm1.ButtonClientClick(Sender: TObject);
begin
  Caption := 'Click';
end;

end.

編集 削除
もん  2022-02-10 01:06:26  No: 150045  IP: [192.*.*.*]

>これを実行して どうしてこういう動作になるのか理解出来ますか?

それをメインフォームで行う場合はわかるんですが

procedure TForm1.Button1Click(Sender: TObject); 
procedure TForm1.ButtonClientClick(Sender: TObject); 
を外部においたときはKONNOYA様に教わった

ti.OnClick := TNotifyEvent( Method ); 

で出来るようになりました。

これと同じようにti.Onmousemoveやti.Onmousedownを行いたい状態で

このイベントはメインフォームに記述しなくてはダメ&TControl.OnMouseMove のイベントの型は TMouseMoveEvent
と言う事で、 OnClickでTNotifyEventだと外部PASで処理できるのにTMouseMoveEventだと同じように出来ないのはなぜ?
と言う感じになっており、出来ない場合は

  ti.Onmousemove := ***** や   ti.Onmousedown := ***** の形
もしくは、外部pasで動的生成したフォームで同じ外部pas内でOnmousemoveやOnmousedownを取得する方法が無いのか
と言う部分で、現状は、メインフォームにOnmousemoveやOnmousedownイベントを記述しなければ出来ません。と言う感じになっております。

編集 削除
take  2022-02-10 01:42:58  No: 150046  IP: [192.*.*.*]

Form2を作ってボタン1つパネル1つ置いて Unit5.pas として保存
Form1の方はForm2を保存した Unit5.pas をインクルード

メインの方のボタンクリックイベントで
TForm2を動的生成してイベント割り当て

>TMouseMoveEventだと同じように出来ないのはなぜ?

イベントの種類がButtonClickとMouseMoveで異なるからです。
誰かが説明していたような・・・
とにかくMouseMoveをメインで拾うソースも置いておきます。

Form2のソース
//--------------------------------------------------------------------------------
unit Unit5;

interface

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

type
  TForm2 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

end.

//--------------------------------------------------------------------------------
// メインフォームのソース
//--------------------------------------------------------------------------------
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls,Unit5;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    procedure ButtonClientClick(Sender: TObject);
    procedure PanelClientMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  tf: TForm2;
begin
  tf := TForm2.Create(Self);
  tf.Parent := Panel1;
  tf.Align := alClient;
  tf.Button1.OnClick := ButtonClientClick;
  tf.Panel1.OnMouseMove := PanelClientMouseMove;
  tf.Show;
end;

procedure TForm1.ButtonClientClick(Sender: TObject);
begin
  Caption := 'Click';
end;

procedure TForm1.PanelClientMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  Caption := 'Mouse Move';
end;

編集 削除
もん  2022-02-10 02:05:36  No: 150047  IP: [192.*.*.*]

>イベントの種類がButtonClickとMouseMoveで異なるからです。

異なるのは引数を見て判断できるのですが、異なるときは、その異なった物を利用するためには
どのようにするのか?と言う部分がわからない感じになっています。
form1からform1のイベントを発生させることは出来ますが外部ファイルから動的生成させたフォームで同じファイルにあるイベントを起こす部分に
どのようにアクセスをかければ良いかが出来ない状態になっております。

>とにかくMouseMoveをメインで拾うソースも置いておきます。

これも同じようにメインフォームで生成しメインフォームでイベントを起こすのは理解できるんですが
生成自体を外部ファイルで行い、その外部ファイルにイベントを記述し、そこを呼ぶにはどうすれば出来るのか。と言う部分が謎になっております。

編集 削除
take  2022-02-10 02:25:33  No: 150048  IP: [192.*.*.*]

「外部ファイル」と呼んでいるものを「別ユニット」「外部ライブラリ」と思って回答
そして
>その外部ファイルにイベントを記述し、そこを呼ぶにはどうすれば出来るのか

普通に呼べますよね?


Form2のソース
//--------------------------------------------------------------------------------
unit Unit5;

interface

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

type
  TForm2 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
  Caption := 'Click';
end;

end.

//--------------------------------------------------------------------------------
// メインフォームのソース
//--------------------------------------------------------------------------------
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls,Unit5;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  tf: TForm2;
begin
  tf := TForm2.Create(Self);
  tf.Parent := Panel1;
  tf.Align := alClient;
  tf.Show;
  tf.Button1Click(Self);
end;

編集 削除
もん  2022-02-10 03:07:35  No: 150049  IP: [192.*.*.*]

フォームはIDEで作る場合は出来るんですが下記のような感じの場合に指定の仕方がわからない感じになります。

メインフォーム
-----------------------------------------------
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
Form1: TForm1;

implementation
uses sample_module;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
go(sender,self);
end;
end.
-----------------------------------------------

sample_module.pas
-----------------------------------------------
unit sample_module;

interface
uses windows,Dialogs,forms,ExtCtrls,Graphics,Controls,Classes,SysUtils,messages, StdCtrls;

procedure go(sender:tobject;form:tform);
procedure MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);

implementation

procedure MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
begin
showmessage('xxx');
end;

procedure go(sender:tobject;form:tform);
var
ti:timage;
tf: TForm;
ta:TApplicationEvents;
begin
tf:= TForm.Create(nil);
tf.Caption := 'overlay1';
tf.FormStyle:=fsStayOnTop;
tf.width:=200;
tf.Height:=200;
tf.OnMouseMove:= MouseMove;
//tf.OnMouseMove:= MouseMove(form,[ssleft],10,10);
tf.Show;

end;

end.
-----------------------------------------------

編集 削除
Mr.XRAY  2022-02-10 03:16:27  No: 150050  IP: [192.*.*.*]

サンプルを以下に UP しました.
フォームの Button1 クリックで設定していますが,ユニット側でも設定できます.
適当に利用してください.

 http://mrxray.on.coocan.jp/Delphi/zip/BetuUnit_OnMouseMove.zip

 
 ※ 前に UP した ZIP 書庫は以下に移動しました.
  http://mrxray.on.coocan.jp/Delphi/zip/123_ReusingForm.zip

編集 削除
Mr.XRAY  2022-02-10 03:31:42  No: 150051  IP: [192.*.*.*]

クラスはダメ.コードを提示しもユニットに分割できない.
これは厳しいものがあります.少し絶望的です.

しかし,何事も挑戦することはいいことです.
オリンピックの競技で金メダルをとれるのは一人だけです.
しかし,挑戦して頑張らなければ金メダルはとれません.
頑張ってください.
応援をするつもりはありませんが.😅

編集 削除
もん  2022-02-10 03:51:26  No: 150052  IP: [192.*.*.*]

ズバリ!!それです!!


---------------------------------------
unit sample_module;

interface
uses windows,Dialogs,forms,ExtCtrls,Graphics,Controls,Classes,SysUtils,AppEvnts,messages, StdCtrls;

procedure go(sender:tobject;form:tform);
procedure OnMouseMoveEvent(Self: TObject; Sender: TObject; Shift: TShiftState; X,
    Y: Integer);

implementation

var
tfm: TForm;

procedure OnMouseMoveEvent(Self: TObject; Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
 var
comp_memo:tmemo;
begin
comp_memo := tfm.FindComponent('memo1') as Tmemo;
comp_memo.lines.add(inttostr(x));
end;

procedure go(sender:tobject;form:tform);
var
ti:timage;
tf: TForm;
LMethod : TMethod;
begin
tf:= TForm.Create(nil);
tf.Caption := 'overlay1';
tf.FormStyle:=fsStayOnTop;
tf.width:=200;
tf.Height:=200;
tfm:=form;

LMethod.Code := @sample_module.OnMouseMoveEvent;
LMethod.Data := nil;
tf.OnMouseMove := TMouseMoveEvent(LMethod);
tf.Show;
end;

end.
---------------------------------------

編集 削除
もん  2022-02-10 03:57:46  No: 150053  IP: [192.*.*.*]

マウスがチャタッテ投稿されてしまいました(>_<)
↑な感じで目的の動作になりました。

Mr.XRAY様、take様、みなさまどうもありがとうございました。

編集 削除
Mr.XRAY  2022-02-10 13:55:32  No: 150054  IP: [192.*.*.*]

> ずっと読んでいましたが、なんだかよく分からなくなってきました(汗   
> 説明されればされるほど 内容を理解出来なくなっているのは自分だけでしょうか・・・

私も一体何がしたいのか理解できまんでした.
今回のは結局,イベントとしてのメソッドを手続きに置き換える問題ですね.
UP したコードがそれです.

アプリで使用するフォームに配置するコントロール類は各々のフォームによって違います.
実装するイベントもイベントの処理コードも違います.
イベント以外にもメソッド類も実装するのが一般的です.
更に他のフォーム,つまり,他のユニットを参照することもあります.
もちろん,InputQuery 関数のように汎用的なフォームもあります.
(参考として UP した ZIP 書庫に追加しておきました)

フォームを作成してコントロールの生成も実行時に行う処理を共通化というのは考えにくいです.
ましてや,その処理を別ユニットにするという面倒なことは考えられません.
作成するフォームごとにそのようなユニットが必要になってしまいます.
しかもクラスの機能を使用しないで.
おそらく,[共通した処理をユニットして利用すると便利]といったようなフレーズ
から思いついたのか知れません.

編集 削除
Mr.XRAY  2022-02-10 13:58:14  No: 150055  IP: [192.*.*.*]

ところで,

コマンドラインコンパイルというのは,IDE を起動しないでコンパイルして EXE を生成するものです.
生成した EXE は起動しません.
IDE では [Ctrl] + [F9] に相当します.

> 必要あるなしにかかわらずusesしなくてはいけない、ので、

使用もしない大量のユニットを uses するのは無理があります.
まず,リソースの無駄使いです.
ある機能を実現するのに,Delphi のバージョンによって使用するユニットの指定があります.
同等機能のユニットは uses から外す必要があります.
同名の関数等が別のユニットに存在する場合も同様です.
それらは通常,プログラマが判断して uses への追加を考えます.
また,フォームのユニットの処理ではコンポーネント以外のユニットも必要です.
JEDI 等を利用している場合,それは数百を超えます.
ユニットには依存関係がありますから,それも考える必要があります.
複数のフォームを使用して互いに参照する場合,循環参照の回避も考える必要があります.

> コンポーネントのプロパティーを必要なときに外部アプリで取得をしたい。

できません.
uses 部の時にもできないと書きましたが,
コードの編集等も Tools API の機能を利用すると可能になります.
それは実行時の機能ではなく,設計時の機能です.
コンポーネントエディタの機能を実装した経験がある方にはご存じの機能です.

ただし,クラスはどうのこうのという段階の方にはかなりの困難が予想されます.

編集 削除
もん  2022-02-10 21:02:57  No: 150056  IP: [192.*.*.*]

>おそらく,[共通した処理をユニットして利用すると便利]といったようなフレーズ
から思いついたのか知れません.

JavaScriptやブラウザーアドンを作成する際は外部JSでcreateelementを利用しフォームを作成し、それと同じファイルにイベントをappendのような記述をするのは基本的な手法になるので同じようにやってみようと考えた次第です。

>コマンドラインコンパイルというのは,IDE を起動しないでコンパイルして EXE を生成するものです.生成した EXE は起動しません. 

IDE を起動しないでコンパイルして EXE を生成するものと言う部分は理解していますが、起動しないexeを作るのならコンパイルする意味が・・・・。

コンパイルは、ソースから実行ファイルを生成するのを意味しているという感じで理解していました。

想定としては、usesを物に合わせて加えtypeinfoやOTAのGetPropNameの結果をログだしするソースを与え、コマンドラインコンパイルの実行ファイルを生成し、shellapi等で実行しプロパティーを取得し、そのログを処理すると言う想定でした。

>使用もしない大量のユニットを uses するのは無理があります.
>それらは通常,プログラマが判断して uses への追加を考えます.

そのために、使用するもののみ自身でusesし行おうと考えた次第です。

>フォームのユニットの処理ではコンポーネント以外のユニットも必要です. 

あっ。それは、今回の別ユニットでフォーム作成とは別のはなしで
take様とのRTTI実行時型情報を使ってと言う話についての、その部分での困ったことは
uses関係くらいと言う秘密のやりとりでした。

>フォームを作成してコントロールの生成も実行時に行う処理を共通化というのは考えにくいです. 

利用時は、stringgrid専門の生成&関数を作成したり
editboxだけのフォームを生成する。と言う単一の処理を1ファイルで行うのを目的としており、リネームのように入力した値を返すだけのフォームで返値の先が別とかstringgridのheader有りじのinsertやappend、削除の処理をfixedcolの状態で判断し同じ構文で統一化する感じの関数を持たせようとしていた次第です。

>コードの編集等も Tools API の機能を利用すると可能になります.それは実行時の機能ではなく,設計時の機能です. 

Tools APIを利用すると貼ってあるコンポーネントのプロパティーは実行時にでも表示が可能なので、コンポーネントパレットの情報をグループやコントロールでLBで一覧し、そこで選んだプロパティーを表示させたい。表示させるにはusesが必要なので、動的にさせたいという感じになりました。

配置さえしていればtyopeinfoやGetPropNameで取得ができるので、今回のように思った次第です。

自身のスニペットを見たところ、最終的にレジストリやフォルダーからBPL名を取得して
そこからソースを取得し、正規表現でprocedureとfunction一覧を出す感じで実装していました。

ちなみに、その際にアイコンも取得しようと思いMr.XRAY様のページをめっちゃグルグルさせていただいていました。

アイコンの背景が同じ条件で取得しているのに、まれにピンクになったりならなかったりり、指定色を透過指定等色々試しても改善せず、たまに思い出してはグルグルと(^_^;)

最終的には長期探索の結果DrawIconExの引数で対応できるということが発覚しました。

-------------------
結局、この部分の@sample_module.で対象を明確にするという知識が無かった為に
(LMethod.Code := @sample_module.OnMouseMoveEvent;)

LMethod.Code := OnMouseMoveEvent; 

LMethod.Code := form.OnMouseMoveEvent; 

のような感じで行おうとし、イベントが違うからunitでは使えないという風に捉えていたため、最初のアドバイスが生かせずにマウスイベントは別ですと言う意味が理解できず、すでに教えたのに違うのか?じゃなにをしたいんだ。という感じだったんですね。

ちなみにTools APIですが、cnwizerd(cnscript)で正規表現のtregexprがusesしても利用できな原因は同等機能のユニットがひそんでいるからなのでしょうか?

編集 削除
もん  2022-02-10 21:24:16  No: 150057  IP: [192.*.*.*]

>コンポーネントエディタの機能を実装した経験がある方にはご存じの機能です.

コンポーネントエディタというのはプロパティーを設定したり取得したりの部分だとしましたら
なんとか、わからない状態でもできてしましました(^_^;)

意外と、そこよりもコンポーネントパレットの処理のほうがアイコン関係も踏まえて苦戦しました。

あとは謎は1つしかのこっていないので、早急に解決が必要なものではないので
やることやった後にまた調べて、むりぃ。になったらMr.XRAY さまに応援してもらうと思います♪

(いまは応援をするつもりはないけど、きっと、何かの拍子に応援したくなるかもしれないので・・・・。
たぶん、応援するためにIMEの操作を極めてくれると信じています。)

編集 削除
Mr.XRAY  2022-02-11 08:32:07  No: 150061  IP: [192.*.*.*]

 http://mrxray.on.coocan.jp/Delphi/zip/BetuUnit_OnMouseMove.zip
 
 に up したファイルは削除しました.
 この掲示板に掲載しておいた方がいいと思いますので
 
 
  procedure OnMouseMoveEvent(Self: TObject; Sender: TObject; Shift: TShiftState; X,
    Y: Integer);
  procedure OnClickEvent(Self: TObject; Sender: TObject);

var
  Form1: TForm1;

implementation

{$R *.DFM}

//=============================================================================
//  Memo1 (TMmoe) のイベントをクラスのメンバではない手続きに割り当てる例
//
//  動作確認
//  Windows [Version 10.0.19042] Pro 64 bit + Delphi XE5(UP2) Pro VCL-32
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LMethod : TMethod;
begin
  LMethod.Code := @OnMouseMoveEvent;
   // クラス以外で設定する時は nil にでもしておく
  LMethod.Data := Self;
  Memo1.OnMouseMove := TMouseMoveEvent(LMethod);

  LMethod.Code := @OnClickEvent;
  LMethod.Data := Self;
  Memo1.OnClick := TNotifyEvent(LMethod);
end;

//-----------------------------------------------------------------------------
//  OnMouseMove イベント用の手続き
//-----------------------------------------------------------------------------
procedure OnMouseMoveEvent(Self: TObject; Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  LText : string;
begin
  LText := 'X : ' + IntToStr(X) + '  Y : ' + IntToStr(Y);
  Form1.Memo1.Lines.Add(LText);
end;

//-----------------------------------------------------------------------------
//  OnClick イベント用の手続き
//-----------------------------------------------------------------------------
procedure OnClickEvent(Self: TObject; Sender: TObject);
begin
  ShowMessage('Clicked !!   ' + TControl(Sender).Name);
end;

編集 削除
Mr.XRAY  2022-02-12 22:28:29  No: 150062  IP: [192.*.*.*]

今度は JavaScript が登場して益々訳が分からなくなっていますが,
イベントの例,記事にしました.

[ メソッドのポインタと手続きのポインタ ]
http://mrxray.on.coocan.jp/Delphi/Others/Pointer_Method.htm

> 別アプリで利用の際に都度作り直しになってしまうので
> 作ったFormは他のプロジェクトでも呼び出せるけど違うのかな? 

ということで以下の記事も追加しました.
フォームを作成するための pas ファイルを作るのか,フォームを作るのか ?
修正・編集して再利用するのか ?  それは皆様の勝手です.

[ 123_フォームの再利用 ]
http://mrxray.on.coocan.jp/Delphi/plSamples/123_ReusingForm.htm

# それにしても,私のハンドル名はバーゲンセールなのか ?

編集 削除
AAA  2022-02-15 22:53:25  No: 150063  IP: [192.*.*.*]

フォームではなくユニットでフォームを作ったのでフォームが無いのでイベント先が・・・
って話は

unit Unit3;

interface

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

type
   TX = class(TComponent)
   public
     procedure DoClick(Sender: TObject);
   end;

procedure GO(Sender: TObject; Form: TForm);

implementation

procedure TX.DoClick(Sender: TObject);
begin
    MessageBox (0,'','',0);
end;

procedure GO(Sender: TObject; Form: TForm);
var
   TF: TForm;
   X: TX;
begin
   TF := TForm.Create(nil);
   TF.OnClick := X.DoClick;
   TF.ShowModal;
   TF.Free;
end;

end.

ユニットじゃなくフォームに作れよって話なんだけど

>そのやり方で今まで行っていたのですが、その方法だと別アプリで利用の際に都度作り直しになってしまうので生成処理を別PASに記述し使い回し>で動的生成を行おうと思いました。

その別pas はフォームでいいんだよ

unit Unit2;

interface

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

type
  TForm2 = class(TForm)
    Image1: TImage;
    procedure FormClick(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form2: TForm2;
  procedure GO(Sender: TObject; Form: TForm);

implementation

{$R *.dfm}

procedure GO(Sender: TObject; Form: TForm);
var
   TF: TForm2;
begin
   TF := TForm2.Create(nil);
   TF.OnClick := TF.FormClick;
   TF.ShowModal;
   TF.Free;
end;

procedure TForm2.FormClick(Sender: TObject);
begin
    MessageBox (0,'','',0);
end;

編集 削除
Mr.XRAY  2022-02-21 09:41:12  No: 150069  IP: [192.*.*.*]

> その別pas はフォームでいいんだよ

我々はおそらく誤解しています.
彼の当初の目的は汎用的なユニットの作成だったのではないかと思います.
そこで彼が目を付けたのがフォームです.

> その方法だと別アプリで利用の際に都度作り直しになってしまうので
> 生成処理を別PASに記述し使い回し>で動的生成を行おうと思いました。

だったのですが,方向が変わりました.
フォームは,アプリあるいは〃アプリ内でもフォームによって処理コードが違います.
そこで,実行時に Delphi のコードを作成して,それを実行することを考えたわけです.
つまり,実行時に処理コードを作成すれば,状況に応じたコードにできます.
その時点で「使い回し」はあまり意味を持たなくなりました.
「使い回し」でばなく柔軟性を採用したのです.

使い回しという点では,あらかじめ pas ファイルを作成しておけば済みます
フォームを作成するということは,そのフォームの pas ファイルを作成することと同じです.
そうではない pas ファイルを別に作成するということは,この時点で,
面倒であるとか,手間がかかるという問題は考慮されなくなりました.
彼が言うところの「動的生成」は,
我々の使用している「動的生成」とは意味が違います.例えば,我々の場合,
TButton を「動的生成」する場合,その生成用の pas ファイルを実行時に作成することはありません.

処理コードには当然イベントの処理もあります.
そこでイベントの処理のテストを開始しました.それが最初の質問のコードです.
当然,クラス等の実装がないユニットでテストする必要があったわけです.

おそらく,彼の考えに近いのは InuptQuery のような関数ではないかと思います.
InputQuery 関数は,実行時にフォームを作成して表示します.
そのフォーム作成のコードを実行時に作成して pas ファイルとするものと思われます.

[ 09_実行時にフォームを作成して表示する関数 ] 
http://mrxray.on.coocan.jp/Delphi/plSamples/123_ReusingForm.htm#09

そのためには,uses に記述するユニット名が必要だと思った ( pas ファイルの作成なので ).
そのユニット名を自分が追加するのではなく,
Delphi の IDE から自動的に取得して追加することを考えた.
といったところでしょう.

彼の書き込みを,フォームの利用,あるいはユニットの分割という視点で読んでいると
「訳が分からない」
ということになってしまいます.
あまくまでも,実行時に pas ファイル作成して,それを実行するのが目的です.
その対象をフォームにした,ということになります.

以上が私の分析です.

> その方法だと別アプリで利用の際に都度作り直しになってしまうので

他のアプリで使用していたフォームですから,ある程度の修正は必要です.
たからと言って 彼が主張する pas ファイルを作成すればそれを回避できるのか ?
フォームを作成するのだって,そのフォームの pas ファイルを作成するのと同じなのに.
と思ってしまいますよね.普通に考えれば,多分.

編集 削除
Mr.XRAY  2022-02-21 11:34:13  No: 150070  IP: [192.*.*.*]

> 我々はおそらく誤解しています.
> あまくまでも,実行時に pas ファイル作成して,それを実行するのが目的です.

PPA のことをレスしている方がいましたから,全員というわけではないですね.😀
インタプリタの実装を自前でいうことになりそうですね.

編集 削除
Mr.XRAY  2022-02-22 04:05:34  No: 150071  IP: [192.*.*.*]

> インタプリタの実装を自前でいうことになりそうですね. 

彼 (質問者) の書き込みにコマンドラインコンパイラがでてきます.
コマンドラインコンパイラは,彼が述べているような使用方法はできません.

pas ファイルをコンパイルすると dcu ファイルができます.
Delphi ではコンパイルというと,それらのファイルをリンクして EXE を作成すること意味します.
つまり,Delphi では コンパイル = コンパイル + リンク の意味になっています. 

実行中の EXE に dcu ファイルをリンクして新しい EXE を作成することはできません.
以下のような手順であれば新しい EXE が作成できます.

(1) 実行時に作成した pas ファイルを保存
(2) EXE を終了
(3) EXE を作成したプロジェクトを IDE で開く
(4) 保存した pas ファイルをプロジェクトに追加
(5) その pas ファイルを使用するユニットの uses にその pas ユニット名を追加
(6) コンパイルして EXE を作成

編集 削除
Mr.XRAY  2022-02-22 04:20:00  No: 150072  IP: [192.*.*.*]

> (5) その pas ファイルを使用するユニットの uses にその pas ユニット名を追加

これは EXE 実行中にはできません.
もちろん,追加するユニットを使用するコードも追加する必要がありますが,
これも EXE 起動中にはできません.

編集 削除
take  2022-02-22 04:35:33  No: 150073  IP: [192.*.*.*]

>手段的にブラウザーでソースをテキストで持ち投げるように、
>テキストでソースを持ち必要なときに投げてコンパイルなイメージになっています。

投稿者しかわかりませんが、結局はこれがやりたかったことなのでしょう。

>JavaScriptやブラウザーアドンを作成する際は外部JSでcreateelementを利用しフォームを作成し、
>それと同じファイルにイベントをappendのような記述をするのは基本的な手法になるので同じようにやってみようと考えた次第です。

誤解が無いよう補足しておきますが、JavaScriptでソースをテキストで管理しておいて
それを自分自身から呼ぶってのは至難の業です。
そんなことできたら簡単にマズいプログラム作れちゃいますので

おそらくDelphiで組んでいて一番面白い瞬間が今なのでしょう
今後も学習すれば自分で思うようなプログラムが組めると思いますよ。

私自身も HTMLファイル内に Delphiタグを作って HTML内にDelphiでプログラムを書けないのかな?
なんてことを考えていたこともあります。

周りからは不可能だと言われましたが続けた結果、なんとか完成しました。(役に立つとは言ってない)

今回の挑戦が何か良いことにつながればいいですね。

編集 削除
Mr.XRAY  2022-02-22 10:08:52  No: 150074  IP: [192.*.*.*]

Delphi はコンパイラ言語です.プログラムのコードを全て機械語に翻訳して実行可能ファイルを作成します.
その実行可能ファイルを実行します.
コンパイルという作業は必要ですが,処理は高速です.
JavaScript はスクリプト言語です.インタプリタ言語とも言います.
プログラムのコードを逐次機械語に翻訳しながら実行します.そのため実行速度は遅くなります.

彼 (質問者) がやろうとしていることの可能性の有無はともかく,
Delphi はコンパイラ言語であることを踏まえて.
設計時に (IDE で) pas コードを生成するのではなく,
実行時にコードを生成する必要性についても考える必要があると思われます.

編集 削除
Mr.XRAY  2022-02-24 04:04:24  No: 150075  IP: [192.*.*.*]

実行時にコードを作成してそのコードを実行するというのがどんなものなのか.
一度経験してみるといいかも知れません.
もしかししたら,参考になるかも知れません.いろいろな意味で.

[ PPA(Poor-Pascal for Application) ]
https://ht-deko.com/junkbox.html#PPA

[ Delphi/C++Builderのアプリケーションにプログラム言語を組み込むことができるライブラリ ]
https://www.gesource.jp/weblog/?p=6367

山本隆さんのブログには Fast Script の記事がいろいろあります.  
https://www.gesource.jp/weblog/?s=FastScript&submit=Search&paged=3

以下に RemObjects Pascal Script の記事があります.

[  Pascal Script, FastScript の比較 ]
http://arndevel.blogspot.com/2012/12/pascal-script-fastscript_28.html

Pascal の範囲であればこんなのもあります.

[ Delphi で Pascal-S をコンパイルする ]
https://qiita.com/ht_deko/items/77052d1f3c3c1a927034

# 何かと言うと DEKO さんと山本隆さんが出てきますね.😀

編集 削除
Mr.XRAY  2022-02-25 05:44:10  No: 150076  IP: [192.*.*.*]

> 実行時にコードを作成してそのコードを実行するというのがどんなものなのか.
> 一度経験してみるといいかも知れません.

参考になれば.

[ Fast Script のテスト ]
http://mrxray.on.coocan.jp/Delphi/Others/000-012.htm

編集 削除
もん  2022-02-27 01:49:48  No: 150080  IP: [192.*.*.*]

xmary様

>彼の当初の目的は汎用的なユニットの作成だったのではないかと思います.

たぶん、それを意味していると思います。
要は1つのファイルで複数の関数を定義し、必要な物を選んで利用する目的でした。

>そこで彼が目を付けたのがフォームです.

たぶん、ここからずれてきたんだと思います。

フォームを作り、そのフォームで色々な処理をしたりusesをしたいのでは無く

striggridでヘッダー有りと無し等で同じ関数名でappendしたり
削除したりするには、rowの定義が変わります。

なのでSG処理に関する複数の処理を1つのPASに納め、都度引数で呼びかえる複数作る関数の1つとしてリネーム専用のフォームを動的生成した場合、イベントの記述がわからないという意味でフォームだけを外部で作ることを目的としているわけでは無いので、使い回し=IDEでフォームを作る方が楽とかフレームで作るとかでは無く、複数関数の使い回しを意味した感じです。

>そこで,実行時に Delphi のコードを作成して,それを実行することを考えたわけです

そこは趣旨とは違うのでMr.XRAY様、考えていただかなくてもいいですよ。とかきましたように TAKE様とのやりとりでRTTIで困ったことは各コントロールのプロパティーを得るのには設置が必要になるので動的にコンパイル方法が現実的かなという話と、現行、Mr.XRAY様とやりとりしている話と、全く別の話で2種類進んでいる感じで、メインの質問の関数自体を実行時にコンパイルしたいのではなく、RTTI等を利用した外部アプリでプロパティーを取得する物を作った場合は、usesを動的に行プロパティー取得のためのコントロール設置の部分だけコンパイルが必要かな。と言う感じです。

>他のアプリで使用していたフォームですから,ある程度の修正は必要です.
たからと言って 彼が主張する pas ファイルを作成すればそれを回避できるのか ? 

フォームにteditと閉じるボタンを設置し閉じた時にフォームの座標の値を得るだけの同じ処理のフォームを生成するだけなので、リネームにも使えますし、検索のワード入力にも使えますし、どのアプリ利用時にも同じ処理を行うだけなので修正不要で可能と見たしだいです。

>誤解が無いよう補足しておきますが、JavaScriptでソースをテキストで管理しておいてそれを自分自身から呼ぶってのは至難の業です。 

アドオンやJquery等で常習的に行われていますよぉ。

>そんなことできたら簡単にマズいプログラム作れちゃいますので

mozilla系だとxpcomが提供されているので、レジストリ操作でもファイル書き込みでも更新でも削除でも、iniとsocket以外はdirectで、ほぼすべて操作可能だとおもいます。
(いまは、waterfoxとpalemoonだけかもしれませんが)

>実行時にコードを作成してそのコードを実行するというのがどんなものなのか一度経験してみるといいかも知れません. 

これは面白そうですね。
ただ、あまり使う機会がないので、みおくりで、新たな難題で助けていただければと思います。

IMEとBrowserの質問があるのですが
1つ1つ解決を待たずに、同時に1個1個立ち上げたらエチケット上よくないでしょうかね?

(今回の2種類の質問が混ざっているのはよくないと思っているので、そこは見逃していただければと(>_<))

編集 削除