自分なりに試したのですがうまくいきません。
ご存知の方がおりましたら、教えてください。
FormAとFormBはほぼ同じような画面です。
(ワケがあって、別々にしなくてはいけません。)
FormAで自作した関数をFormBで呼び出して使用したいのですが、
うまくいきません。
原因は、FormBでFormAの関数を呼び出してもFormBと判断してもらえず、
FormAで処理しているためということまではわかりました。
どうすれば、FormAとFormBで同じ処理をする関数を作成することが
できますか?
よろしくお願い致します。
FormBからFormAの関数を呼び出すところはできているのでしょうか。
FormBにある関数を呼んでしまっているのでしょうか。
前者であれば、FormAにある関数の中で、FormAのメンバを直接操作していませんか?関数の中からFormAのメンバを直接操作せず、FormAのインスタンスを引数に渡して、そのインスタンスから操作するようにしておけば、FormBから呼び出してもOKです。
たとえば、
function TFormA.GetMemoText: String;
begin
Result := Memo1.Lines.Text; // フォームに張ってあるMemo1からテキストを取得
end;
と会った場合、FormBから呼び出しても「FormAのMemo1からテキストを取得」ということになります。
function TFormA.GetMemoText(Sender: TForm): String;
begin
if Sender Is TFormA then
Result := (Sender As TFormA).Memo1.Lintes.Text
else if Sender Is TFormB then
Result := (Sender As TFormB).Memo1.Lines.Text;
end;
とすれば、SenderがFormAの場合FormAのMemo1から取得するし、SenderがTFormBであれば、FormBのMemo1から取得します。
後者であれば、FormA.FuncNameというように、「FormAの」関数を呼び出してください。
FormA:TFormAとして
FormA.FuncName();というふうに
FormAの関数を呼び出せば、関数内のSelfはインスタンスFormAを指します
にしの様、るるとん@k様、解答ありがとうございました。
にしの様のアドバイス通りにやったところ、
思っていたように動いてくれました。
ですが、にしの様のアドバイス通りでいくと
フォームの数だけ、if〜else文が増えてしまいますよね?
function TFormA.GetMemoText(Sender: TForm): String;
begin
if Sender Is TFormA then
Result := (Sender As TFormA).Memo1.Lintes.Text
^^^^^^^^^^^^^^^^^^^
↑
ココの部分を何とか変数に持たせて、処理することって
不可能なのでしょうか?
私なりに、TForm型やObjectなどの変数に入れたりして
試しているのですが、ダメでした。
何か方法がありましたら、アドバイスよろしくお願い致します。
TForm には Memo1 なんていうフィールドはないからね。その例で特定の
Memo1 にアクセスしたいなら TMemo型 の変数を渡したらいいんじゃないの。
Interfaceを利用しましょう。
たとえば、
IForm=interface
function GetMemo: TMemo;
end;
というinterfaceを用意して、
TFormA=class(TForm)
を、
TFormA=class(TForm,IForm)
に、
TFormB=class(TForm)
を、
TFormB=class(TForm,IForm)
に、それぞれ変更します。
TFormA,TFormBのそれぞれに、
procedure GetMemo: TMemo;
を実装してやれば、先のコードは、
function TFormA.GetMemoText(Sender: IForm): String;
begin
Result := Sender.GetMemo.Lines.Text
end;
というようになります。
ちょっと補足。
クラスの変数はできるだけpublicにせず、必要であればpropertyをpublicにして公開したほうがよいです。
人によってやり方はありますので、絶対とはいえませんが。
それだと
> フォームの数だけ、if〜else文が増えてしまいますよね?
は解決しますが、フォームすべてにインタフェースを継承させる必要があって、
なんだか本末転倒ではありませんか? Caller に依存した特定の Memo1 に
アクセスしたいなら、たんに TMemo 型の変数を渡すだけではないでしょうか。
> クラスの変数はできるだけpublicにせず、必要であればpropertyをpublicにして公開したほうがよいです。
一般論はそうですけど、フォームデザイナでポトペタした Memo1 なんかは
published ではないでしょうか。
> フォームすべてにインタフェースを継承させる必要があって、
> なんだか本末転倒ではありませんか? Caller に依存した特定の Memo1 に
> アクセスしたいなら、たんに TMemo 型の変数を渡すだけではないでしょう> か。
そういえば、型変換でできるかも。
TFormEx=class(TForm)
public
Memo1: TMemo;
end;
という定義を用意しておいて、
function TForm1.GetMemoText(Sender: TForm): String;
var
Form: TFormEx;
begin
Form := TFormEx(Sender);
Result := Form.Memo1.Text;
end;
とすればもっと簡単にとれますね。
> 一般論はそうですけど、フォームデザイナでポトペタした Memo1 なんかは
> published ではないでしょうか。
「したほうがよい」であって「すべき」という意味で書いたわけではありません。
ですから、
> 人によってやり方はありますので、絶対とはいえませんが。
と書きました。
上に書いたTFormExでも変数をpublicにしてますし^^;
> 上に書いたTFormExでも変数をpublicにしてますし^^;
上の方式では、他のユニットから Memo1 フィールドにアクセスする必要があるの
で、public 以上の可視性にする必要がありますよね。一方、
function TFormA.GetMemoText(Memo:TMemo): String;
begin
Result := Memo.Lines.Text
end;
のように、TMemo 型の変数を渡す場合は、Caller の方で見えていればいいので
どの可視性でもいいわけです。この場合は、Caller が属している TForm 派生
クラスの private であってもかまいません。参照が直接渡されるからです。
私は、投稿者の意図するところが、「それぞれのフォームを指定して、同じ関数で処理する」と思って書いています。
「それぞれのTMemoを指定して」であれば、つっかさんのおっしゃるとおりです。
TMemoを持ち出したのは私で、単なる例ですので。
確かに、各フォームのTMemoだけであれば、それぞれTMemoのインスタンスから取得すればよいはずですから、つっかさんの書いたようなコードになります。
フォームのクラス名は文字列ですから、caseも可能です
しかしインターフェイスを実装するのが妥当かと思われます
AとBが同じクラスにすることが出来れば、それが一番良いのですが
ぁ、文字列は比較できませんでした
文字列はcase ofで使用できません。
使用できるのは順序型です。
みなさん、たくさんのアドバイスありがとうございました。
おかげで、解決することができました。
私が知らないことがまだまだあるのだと思い、
もっと勉強しなくてはと思いました。
本当にありがとうございます。
感謝してます。
ツイート | ![]() |