[delphi-users:1419] 循環参照回避法

554 views
Skip to first unread message

かぶだれ

unread,
Oct 19, 2010, 5:20:33 PM10/19/10
to delphi...@freeml.com
こんにちは。 かぶだれです。

Delphi宿命の循環参照を回避するにはimplementation部にusesで登録するのが
一般的だと思いますが、これが なかなか「おもむき」の有るテーマでして...

例えばCADなどでは、マウスイベントでパーツオブジェクトの操作用として、
TInserterやTDraggerというクラスを用意されると思いますが、
この操作クラスは親の変数や関数を参照するのが必至で
親は操作クラスを参照しますので典型的な循環参照になります。
親クラスはTObjectとしておいて、リダイレクトで逃げ、
列挙型なんかはIntegerとして置いてリダイレクトすれば解決します。
複雑な型になるとプリミティブなメモリ構造を知らないとできない方法です。
で これが面倒になって implementation部のuses以降にvarを宣言したり
手抜きを...

なにかスマートな方法はないもんでしょうか?
みなさんは、どのように回避されてますか。

MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習の予定も共有スケジュールに登録しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fZFWL
-----------------------------------------------------[freeml by GMO]--

高木太郎

unread,
Oct 19, 2010, 8:27:34 PM10/19/10
to delphi...@freeml.com
皆さま

 おはようございます。 イマジオムの高木です。

かぶだれさん:
> 例えばCADなどでは、マウスイベントでパーツオブジェクトの操作用と
> して、TInserterやTDraggerというクラスを用意されると思いますが、


> この操作クラスは親の変数や関数を参照するのが必至で
> 親は操作クラスを参照しますので典型的な循環参照になります。
> 親クラスはTObjectとしておいて、リダイレクトで逃げ、
> 列挙型なんかはIntegerとして置いてリダイレクトすれば解決します。
> 複雑な型になるとプリミティブなメモリ構造を知らないとできない
> 方法です。

> なにかスマートな方法はないもんでしょうか?
> みなさんは、どのように回避されてますか。

 TInserter や TDragger は、マウスイベントを受けてCADの
パーツ(要素)を操作するためのユーティリティですよね?

 そうだとすれば、パーツの抽象クラス(たとえば TCustomPart)を
TInserter や TDragger と同じユニットに定義すればいいと思います
(クラス間での循環参照は起きますが、ユニット間では起きません)。
パーツの種類を定義する時には、TCustomPart から継承させるように
します。

 TInserter や TDragger がパーツに依存するのでしたら、それらの
抽象クラス(たとえば TOperator)も定義するといいかもしれませんね。

 これまでずいぶんプログラムを作ってきましたが、ユニットの循環
参照が本当に必要だったことは一度もありません。 抽象クラスを
うまく使うのがコツだと思います。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
学園祭で撮った写真をMLにアップしよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fZH8A

かぶだれ

unread,
Oct 19, 2010, 9:07:35 PM10/19/10
to delphi...@freeml.com
こんにちは。高木さん かぶだれです。

具体的なコードをぶら下げてみます。
CADのふるまいクラスは巨大なので掲載できませんが、
最近作っているGridの例を単純化したものです。

------------TxxxxGrid-------------------
type
TxxxxGrid = class(TCustomControl)
private
_Resizer: TResizer;


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
新メンバーを便利な@招待機能で一気に登録しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fZIhg

かぶだれ

unread,
Oct 19, 2010, 11:11:41 PM10/19/10
to delphi...@freeml.com
かぶだれです。
失礼しました。 Resizerの使い方が抜けていました。

> 具体的なコードをぶら下げてみます。
> CADのふるまいクラスは巨大なので掲載できませんが、
> 最近作っているGridの例を単純化したものです。
>
> ------------TxxxxGrid-------------------
> type
> TxxxxGrid = class(TCustomControl)
> private
> _Resizer: TResizer;

> .
> .
> end;
>
> procedure xxxxGrid.MouseDown(........)
> .
> .
> if state = csEmpty then
> begin
> _Inserter := TInserter.Create(Self, cell, p);
> end
> else if state = csCenter then
> begin
> _Dragger := TDragger.Create(Self, cell, p);
> end
> else
> _Resizer := TResizer.Create(Self, Integer(state), cell, p);
> end.
>
> ------------TResizer-----------
> type
> TResizer = class
> private
> _parent: TControl;
> .
> .
> procedure Draw;
> procedure ResizeToL(yhePoint: TPoint; theDelta: Integer);
> procedure ResizeToR(yhePoint: TPoint; theDelta: Integer);
>
> public
> constructor Create(theParent: TControl; theState: Integer; cell: TCell; thePoint: TPoint);
> procedure Fin;
> procedure ResizeTo(thePoint: TPoint);
> end;
>
> implementation
>
> uses
> xxxxGrid;
>
> xxxxGridは本体です。
>
> でResizerから参照する場合は
> with xxxxGrid(_parent) do
> state := TCellState(theState);
> などとやっています。
> Resizerクラスのinterface部uses節でxxxxGridを入れると循環参照になります。
>
> 以上 具体例でした。
> 最適な例ではありませんが、適当な題材が思いつかないもので。;^^
>

procedure TxxxxGrid.MouseMove(.......);


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
「あなたはマック?それともマクド?」気になるコトを調査しました!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fZKe8

かぶだれ

unread,
Oct 20, 2010, 4:51:20 AM10/20/10
to delphi...@freeml.com
こんにちは。かぶだれです。

循環参照はふるまい(behavior)クラスに発生しやすくなりますね。
姿・特質(shape)クラスでは、抽象クラスの利用で逃げ道はありますが。

MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
一部のメンバーだけにMLメールを送ることができるようになりました!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fZQKn

かぶだれ

unread,
Oct 20, 2010, 4:28:53 PM10/20/10
to delphi...@freeml.com
こんにちは。かぶだれです。
高木さん アドバイス ありがとうございます。

> そうだとすれば、パーツの抽象クラス(たとえば TCustomPart)を
>TInserter や TDragger と同じユニットに定義すればいいと思います
>(クラス間での循環参照は起きますが、ユニット間では起きません)。
>パーツの種類を定義する時には、TCustomPart から継承させるように
>します。
>
> TInserter や TDragger がパーツに依存するのでしたら、それらの
>抽象クラス(たとえば TOperator)も定義するといいかもしれませんね。
>
> これまでずいぶんプログラムを作ってきましたが、ユニットの循環
>参照が本当に必要だったことは一度もありません。 抽象クラスを
>うまく使うのがコツだと思います。

まったく その通りですね。
アルゴリズム構築中だったのでリファクタリングしていなかったのですが、
典型的なState構造でしたので、関数名を統一しAbstractクラスから
inheritするようにすると循環参照から回避できました。


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
iPadが当たる!新しい農場ゲーム「ベジモン」を始めよう♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=fZY0m

かぶだれ

unread,
Oct 20, 2010, 7:19:08 PM10/20/10
to delphi...@freeml.com
こんにちは。かぶだれです。
すみません。脳内で解決できただけで、なんか ちらしの裏になってきました。(笑

abstractクラスでstateパターンのfactory methodに
フライベート型(TCellState等々)を引数に渡さなければならないのは変わりないので
循環になってしまいます。
Pointerで渡せば全て解決しますが...(笑 スマートではないですね。
これが言語限界という事か?

MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習の予定も共有スケジュールに登録しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fZZts

かぶだれ

unread,
Oct 20, 2010, 8:09:44 PM10/20/10
to delphi...@freeml.com
こにんちは。かぶだれです。
解決すますた。

アプリケーションと違い、コンポーネントはメインの1ファイルにまとめる癖がついてました。 (笑
プライベート型をタイプユニットにまとめる事で解決です。


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
ちょっとした連絡に♪メンバー掲示板を有効活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fZZUY

のぶ

unread,
Oct 21, 2010, 4:36:18 AM10/21/10
to delphi...@freeml.com
お世話になります
バージョンは7です

StringGridについて2つ質問があります

1、ある列の中で1番大きい値を取得するにはどうしたらいいでしょか?

'021'
'003'
'015'

  のように文字列として値が入っています
  何か関数があるでしょうか??

2、コードの中で、ある特定のセルを選択するにはどうしたらいいでしょうか??
  以下のようにしてもうまくいきませんでした・・・
SGridBuiAll.Row := ;
  SGridBuiAll.Col := 2;
  SGridBuiAll.SetFocus;

時間のあるときで構いませんのでなにかわかる方いましたら
よろしくお願いします。


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
学園祭で撮った写真をMLにアップしよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gaibP

ありい

unread,
Oct 21, 2010, 5:14:25 AM10/21/10
to delphi...@freeml.com
 のぶさん、こんばんは。

 こちらでは新規プロジェクトに単純にStringGridとBitBtnを
貼り付けて

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
StringGrid1.Row := 2;
StringGrid1.Col := 2;
StringGrid1.SetFocus;
end;

....とするだけで選択されますねぇ。何か後の方で、他の処理
が動いたりしていませんか?

#D7、Windows2000です。

ありい

MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
「あなたはマック?それともマクド?」気になるコトを調査しました!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gaiMm

のぶ

unread,
Oct 21, 2010, 6:29:36 AM10/21/10
to delphi...@freeml.com
ありい さん

無事できました。


少々余計な処理があったようです。

ありがとうございます!!

(2010/10/21 18:14), ありい wrote:
>  のぶさん、こんばんは。
>
>  こちらでは新規プロジェクトに単純にStringGridとBitBtnを
> 貼り付けて
>
> procedure TForm1.BitBtn1Click(Sender: TObject);
> begin
> StringGrid1.Row := 2;
> StringGrid1.Col := 2;
> StringGrid1.SetFocus;
> end;
>
> ....とするだけで選択されますねぇ。何か後の方で、他の処理
> が動いたりしていませんか?


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
一部のメンバーだけにMLメールを送ることができるようになりました!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gakdL

ねこ

unread,
Oct 21, 2010, 8:10:15 PM10/21/10
to delphi...@freeml.com
金子です。
D6からXEへの切り替えがさっぱり進行していませんが、リハビリを兼ねてちょっ
といじっていました。

On Thu, 21 Oct 2010 17:36:16 +0900 (JST)
のぶ <delphi...@freeml.com> wrote:
>   のように文字列として値が入っています
>   何か関数があるでしょうか??

関数は知らないですが、StringGrid の Cols は TStrings なので、
TStringList を使用すればソートできるのでは?

procedure TForm1.Button1Click(Sender: TObject);
var
x:TStringList;
begin
x:=TStringList.Create;
with StringGrid1.Cols[1] do begin
StringGrid1.Cols[1].CommaText:=',1,5,2,3,4' ;
x.Assign(StringGrid1.Cols[1]);
x.Sort;
ShowMessage(x.Strings[x.Count-1]);
end;
x.Free;
end;


****************************
金子 純一
<kane...@nifty.com
****************************

MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習の日程や合宿の行き先など、みんなの意見をアンケートで集約しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gasRV

Delフサギコ

unread,
Oct 23, 2010, 1:45:58 PM10/23/10
to delphi...@freeml.com
こんばんは。

多段階の循環参照で、ユニットが何十個も絡んでくると
どこが循環参照になっているかわかりにくて
どこを改善すればいいのかも見えない場合がありました。

手書きのメモでどれがどれに依存しているかを書いて、見つけた事があります。


そういう場合に
こちらで紹介されているツールが役に立つと思います。

Owl's perspective: ユニット間の依存関係を解析する
http://owlsperspective.blogspot.com/2010/08/analyze-unit-dependency.html

--
Delフサギコ ミ・д・彡 <delfu...@gmail.com>


2010年10月20日6:20 かぶだれ <delphi...@freeml.com>:


> こんにちは。 かぶだれです。
>
> Delphi宿命の循環参照を回避するにはimplementation部にusesで登録するのが
> 一般的だと思いますが、これが なかなか「おもむき」の有るテーマでして...
>
> 例えばCADなどでは、マウスイベントでパーツオブジェクトの操作用として、
> TInserterやTDraggerというクラスを用意されると思いますが、
> この操作クラスは親の変数や関数を参照するのが必至で
> 親は操作クラスを参照しますので典型的な循環参照になります。
> 親クラスはTObjectとしておいて、リダイレクトで逃げ、
> 列挙型なんかはIntegerとして置いてリダイレクトすれば解決します。
> 複雑な型になるとプリミティブなメモリ構造を知らないとできない方法です。
> で これが面倒になって implementation部のuses以降にvarを宣言したり
> 手抜きを...
>
> なにかスマートな方法はないもんでしょうか?
> みなさんは、どのように回避されてますか。
>


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
学園祭で撮った写真をMLにアップしよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gaK39

かぶだれ

unread,
Oct 23, 2010, 8:34:42 PM10/23/10
to delphi...@freeml.com
こんにちは。かぶだれです。
Delフサギコさん サンクスです。

>
> そういう場合に
> こちらで紹介されているツールが役に立つと思います。
>
> Owl''s perspective: ユニット間の依存関係を解析する
> http://owlsperspective.blogspot.com/2010/08/analyze-unit-dependency.html
>
> --
> Delフサギコ ミ・д・彡 <delfu...@gmail.com>
>
>

速達、使ってみます。

従来のコンポーネント開発手法で1本のファイルに入れているときは問題なかったのですが、デザパタやアジャイルやTed Faison等の思想にかぶれてしまったら
細切れクラスとファイルのオンパレードになってしまって循環参照で怒られる事しばし。 (笑
循環参照でIDEが文句を言うときは、リファクタリングしろという命令だと思う事にしました。


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
新メンバーを便利な@招待機能で一気に登録しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gaLUx

のぶ

unread,
Oct 24, 2010, 11:26:06 PM10/24/10
to delphi...@freeml.com
金子さん
ありがとうございます。

なるほど
こういったやり方があるんですね!
助かります。。


(2010/10/22 9:10), ねこ wrote:
> 金子です。
> D6からXEへの切り替えがさっぱり進行していませんが、リハビリを兼ねてちょっ
> といじっていました。
>
> On Thu, 21 Oct 2010 17:36:16 +0900 (JST)
> のぶ <delphi...@freeml.com> wrote:
>> >   のように文字列として値が入っています
>> >   何か関数があるでしょうか??
> 関数は知らないですが、StringGrid の Cols は TStrings なので、
> TStringList を使用すればソートできるのでは?
>
> procedure TForm1.Button1Click(Sender: TObject);
> var
> x:TStringList;
> begin
> x:=TStringList.Create;
> with StringGrid1.Cols[1] do begin
> StringGrid1.Cols[1].CommaText:=',1,5,2,3,4' ;
> x.Assign(StringGrid1.Cols[1]);
> x.Sort;
> ShowMessage(x.Strings[x.Count-1]);
> end;
> x.Free;
> end;


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習の日程や合宿の行き先など、みんなの意見をアンケートで集約しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gba7s

中村@ブレーン

unread,
Oct 26, 2010, 12:08:58 AM10/26/10
to delphi...@freeml.com
中村@ブレーンです。

かぶだれ さんは書きました:


>まったく その通りですね。
>アルゴリズム構築中だったのでリファクタリングしていなかったのですが、
>典型的なState構造でしたので、関数名を統一しAbstractクラスから
>inheritするようにすると循環参照から回避できました。

もう終わっている話題だと思いますが、循環参照はたいてい

DIP(Dependency Inversion Pronciple)

で解消できます。これの具体例はあちこちにありますが、

「アジャイルソフトウェア開発の奥義」
ロバート・C・マーチン, 瀬谷 啓介, ソフトバンククリエイティブ

が詳しくて、とてもよくまとまっていると思います。

----------
東京都 日野市 中村拓男


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習の予定も共有スケジュールに登録しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gbqKz

のぶ

unread,
Oct 26, 2010, 2:22:40 AM10/26/10
to delphi...@freeml.com
たびたびすいません。

のぶです


StringGridにチェックボックスを組み込みたいと思っています。

DrawFrameControl関数を使えば出来るようなんですが


if (ACol = 0) then
  DrawFrameControl(TStringGrid(Sender).Canvas.Handle,
        Rect,
           DFC_BUTTON,
           DFCS_CHECKED or DFCS_BUTTONCHECK );
end;


やってみましたがうまく行きません。


何かいい方法を知ってる方いらっしゃいませんか?


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
ちょっとした連絡に♪メンバー掲示板を有効活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gbsu8

のぶ

unread,
Oct 26, 2010, 5:18:09 AM10/26/10
to delphi...@freeml.com
以下の件

if文とやらいろいろ駆使して
なんとか解決しました。

考えてくださった方ありがとうございます・・・

(2010/10/26 15:22), のぶ wrote:
> StringGridにチェックボックスを組み込みたいと思っています。
>
> DrawFrameControl関数を使えば出来るようなんですが
>
>
> if (ACol = 0) then
>   DrawFrameControl(TStringGrid(Sender).Canvas.Handle,
>         Rect,
>            DFC_BUTTON,
>            DFCS_CHECKED or DFCS_BUTTONCHECK );
> end;
>
>
> やってみましたがうまく行きません。
>
>
> 何かいい方法を知ってる方いらっしゃいませんか?


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
学園祭で撮った写真をMLにアップしよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gbuND

かぶだれ

unread,
Oct 26, 2010, 10:01:16 PM10/26/10
to delphi...@freeml.com
こんにちは。かぶだれです。
中村@ブレーンさん レスありがとうございます。
P板からFPGA基板が上がってきたものですから組立てで忙しく遅れて失礼致しました。

>
> DIP(Dependency Inversion Pronciple)
>
> で解消できます。これの具体例はあちこちにありますが、
>
> 「アジャイルソフトウェア開発の奥義」
> ロバート・C・マーチン, 瀬谷 啓介, ソフトバンククリエイティブ
>
> が詳しくて、とてもよくまとまっていると思います。
>

名著という事で、題名は目にしていたのですが購入していませんでした。
速達 読んでみます。

今のテーマがビッグプログラムのアーキテクチャア研究ですので
アドバイスはありがたいです。


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
新メンバーを便利な@招待機能で一気に登録しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gb3ti

中村@ブレーン

unread,
Oct 27, 2010, 12:33:16 AM10/27/10
to delphi...@freeml.com
中村@ブレーンです・

かぶだれ さんは書きました:
>今のテーマがビッグプログラムのアーキテクチャア研究ですので
>アドバイスはありがたいです。
>

この本はパッケージ分割がひとつの大きなテーマになっていて
面白いですよ。パッケージ間の循環参照の話も有りますが
パッケージ分割の良し悪しを評価する方法なども載っていて、
おもしろいです。
これを読んでからパッケージ分割の試行錯誤の量をだいぶ減らすことが
できました。

----------
東京都 日野市 中村拓男


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
一部のメンバーだけにMLメールを送ることができるようになりました!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gb52X

中村@ブレーン

unread,
Oct 27, 2010, 12:41:35 AM10/27/10
to delphi...@freeml.com
中村@ブレーンです。

のぶ さんは書きました:
>StringGridにチェックボックスを組み込みたいと思っています。

これも終わっている話題ですが、私はこうやりました。
ソースが残ってないので、やり方だけですが

1) チェックボックスの ON/OFF はObjects プロパティで保持。
2) チェックボックスの描画は OnDrawCell が担当。
  On/Offのビットマップを描く方式でした。
3) マウスは OnMouseDown で受け、MouseToCellでセルを特定して、
Objects を変更、Invalidate か Refresh で再描画。
4) キーボードは OnKeyDown で受けてスペースだったら
現在のセルに対応する Objects を反転。
Invalidate か Refresh で再描画。

----------
東京都 日野市 中村拓男


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習の日程や合宿の行き先など、みんなの意見をアンケートで集約しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gb59b

のぶ

unread,
Oct 28, 2010, 8:29:12 PM10/28/10
to delphi...@freeml.com
中村@ブレーンさん
ありがとうございます

やはり
動的なチェックボックスを
貼り付けることはできないんでしょうか??

(2010/10/27 13:41), 中村@ブレーン wrote:
> これも終わっている話題ですが、私はこうやりました。
> ソースが残ってないので、やり方だけですが
>
> 1) チェックボックスの ON/OFF はObjects プロパティで保持。
> 2) チェックボックスの描画は OnDrawCell が担当。
>   On/Offのビットマップを描く方式でした。
> 3) マウスは OnMouseDown で受け、MouseToCellでセルを特定して、
> Objects を変更、Invalidate か Refresh で再描画。
> 4) キーボードは OnKeyDown で受けてスペースだったら
> 現在のセルに対応する Objects を反転。
> Invalidate か Refresh で再描画。


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
ちょっとした連絡に♪メンバー掲示板を有効活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=gbWsU

Reply all
Reply to author
Forward
0 new messages