掲示板システム
ホーム
アクセス解析
カテゴリ
ログアウト
複数データ対象のDDEのOnChangeでの動作がうまくいきません。 (ID:19434)
名前
ホームページ(ブログ、Twitterなど)のURL (省略可)
本文
Delphi6 Personal、Win2000の環境です。 DDEを使用して、複数のデータを取り込もうとしています。その際、サーバー側のデータが変わった場合に自動的にクライアント側のデータの表示も変更されるようにOnChangeイベントを利用しました。 いろいろ試行錯誤した経緯はあるのですが、自分のしたいことが実現できない根本的な原因の現象を以下の通り把握しました。 テスト用のDDEサーバーとして、3つのアイテムを持ち、タイマーで自動的に乱数を発生させて数字を変化させるものを用意しました。 ddeserver.exeとして作成 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DdeMan, ExtCtrls, StdCtrls; type TForm1 = class(TForm) Topic1: TDdeServerConv; item1: TDdeServerItem; item2: TDdeServerItem; item3: TDdeServerItem; Timer1: TTimer; Label1: TLabel; Label2: TLabel; Label3: TLabel; procedure Timer1Timer(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Timer1Timer(Sender: TObject); begin item1.Text:=IntToStr(Random(100)); Label1.Caption:=item1.Text; item2.Text:=IntToStr(Random(100)); Label2.Caption:=item2.Text; item3.Text:=IntToStr(Random(100)); Label3.Caption:=item3.Text; end; end. これに対して、クライアント側として、以下のようなものを作成しました。こちらでは、DDEに関するコンポーネントは動的に作成しています。OnChangeイベントとしては、どのデータが変化しても、変化したデータだけではなく、そのときの3つ、すべてのデータをラベルに表示させるようにしています。 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DdeMan, StdCtrls,Contnrs, ExtCtrls,Menus; type //動的に生成するTDdeClientItemのItem TDdeClientItemItem = class (TDdeClientItem); //TDdeClientItemを管理するクラス //TComponentListはTListから派生したクラスで,便利な機能がある TDdeClientItemList = class(TComponentList); TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; Label3: TLabel; Memo1: TMemo; MainMenu1: TMainMenu; Exit1: TMenuItem; Exit2: TMenuItem; procedure FormShow(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure DdeClientItemChange(Sender: TObject); procedure Exit2Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } ADdeClientItemList : TDdeClientItemList; DdeClientItem:TDdeClientItem; DdeClientConv:TDdeClientConv; end; var Form1: TForm1; aryDdeItem :array [0..2] of String= ('item1','item2','item3'); implementation {$R *.dfm} var Changing:Integer; //DDeClientConv,DdeClietnItemListの作成 procedure TForm1.FormShow(Sender: TObject); var i:Integer; lbl:TComponent; begin Changing:=0; DdeClientConv:=TDdeClientConv.Create(self); //PanelItemを管理するTComponentListを作成 //生成Itemオブジェクトを自動破棄するには引数をTureにする ADdeClientItemList:=TDdeClientItemList.Create(True); DDeClientConv.ServiceApplication:='ddeserver'; DDeClientConv.ConnectMode:=ddeManual; DdeClientConv.SetLink('ddeserver','topic1'); DdeClientConv.OpenLink; for i:=0 to 2 do begin DdeClientItem:=TDdeClientItemItem.Create(self); DdeClientItem.DdeConv:=DdeClientConv; DdeClientItem.DdeItem:=aryDdeItem[i]; DdeClientItem.OnChange:=DdeClientItemChange; ADdeClientItemList.Add(DdeClientItem); lbl:=FindComponent('Label'+IntToStr(i+1)); if (DdeClientItem.Text<>' ') and (DdeClientItem.Text<>'') then begin (lbl as TLabel).Caption:=DdeClientItem.Text; end else begin (lbl as TLabel).Caption:=''; end; end; end; //変化した場合にLabel表示に反映 procedure TForm1.DdeClientItemChange(Sender: TObject); var i:Integer; lbl:TComponent; begin if Changing=1 then Exit; Changing:=1; //変化した部分だけの更新にしようと思うのだが、頻繁に変化する部分ばかりの動きで //まったく反映されない部分もある。なので、どの部分が変化しても、すべてのLabelを //一括して更新することにしてみる。 for i:=0 to 2 do begin lbl:=FindComponent('Label'+IntToStr(i+1)); if ((ADdeClientItemList[i] as TDdeClientItem).Text<>' ') and ((ADdeClientItemList[i] as TDdeClientItem).Text<>' ') then begin (lbl as TLabel).Caption:=(ADdeClientItemList[i] as TDdeClientItem).Text; //状況確認のため Memo1.lines.add(IntToStr(i)+(ADdeClientItemList[i] as TDdeClientItem).Text); end else begin (lbl as TLabel).Caption:=''; end; end; Changing:=0; end; //Formがなくなる前にADdeClientItemListを解放. procedure TForm1.FormDestroy(Sender: TObject); begin //DdeClientConv.Freeの実行によりDdeClientItemの //onChangeイベントが発生し、そちらが一瞬実行されエラーとなるのを回避 Changing:=1; //順番重要 -逆だとエラー- DdeClientConv.Free; FreeandNil(ADdeClientItemList); end; procedure TForm1.Exit2Click(Sender: TObject); begin Close; end; end. で、この両方を起動してみると、私の環境では、クライアント側での動的作成時のサーバー側の数字が、とりあえず入りますが、その後のサーバー側でのタイマーによる変化では、3つあるうちの最初のデータ(item1)に対応するラベルしかクライアント側では変化しません。 これは、例えば、サーバー側のTimer1Timerで、乱数を発生させる順番を以下のように、item3で最初に発生させるようにすると、今度は、クライアント側ではitem3しか変化しないようになります。 procedure TForm1.Timer1Timer(Sender: TObject); begin item3.Text:=IntToStr(Random(100)); Label3.Caption:=item3.Text; item2.Text:=IntToStr(Random(100)); Label2.Caption:=item2.Text; item1.Text:=IntToStr(Random(100)); Label1.Caption:=item1.Text; end; なぜこのようなことが起こるのでしょうか。回避する方法はありますでしょうか。 良いアドバイスがあれば、よろしくお願いします。 なお、上記の動作では、サーバー側→クライアント側の順番で起動する必要があり、サーバー側を再起動すると、クライアント側もその後に再起動が必要になります。
←解決時は質問者本人がここをチェックしてください。
更新する
戻る
掲示板システム
Copyright 2021 Takeshi Okamoto All Rights Reserved.