如何让两个窗体都调用一个类的事件时,能够同时响应?(50分)

  • 主题发起人 主题发起人 GrassDragon
  • 开始时间 开始时间
G

GrassDragon

Unregistered / Unconfirmed
GUEST, unregistred user!
如何让两个窗口都调用一个类的事件时,能够同时响应?

我有两个窗体form1和from2,都需要同时调用窗体Form3的方法。为了让From1和Form2在调用该方法后,能再做各自的事情,我在Form3的方法中定义了一个事件,以被方法的调用者所响应。
但我现在的代码是:始终是事件的后调用者响应该事件,不能让Form1和Form2同时响应我这个Form3的自定义事件。
问题是,要让Form1和For2都同时响应我这个Form3的自定义事件,该如何做?代码如下:

//--------------------
unit Unit1;
//--------------------
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
procedure ShowVolume(V:Integer);
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses unit3;

procedure TForm1.FormCreate(Sender: TObject);
begin
Form3.OnVolumeChanged:=ShowVolume; //调用事件
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Form3.Volume:=Form3.Volume+1;
end;

procedure TForm1.ShowVolume(V:Integer);
begin
label1.Caption:=inttostr(Form3.Volume);
end;

end.


//--------------------
unit Unit2;
//--------------------
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm2 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
procedure ShowVolume(V:Integer);
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;

implementation

uses Form3;

procedure TForm2.FormCreate(Sender: TObject);
begin
Form3.OnVolumeChanged:=ShowVolume; //调用事件
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
Form3.Volume:=Form3.Volume+1;
end;

procedure TForm2.ShowVolume(V:Integer);
begin
label1.Caption:=inttostr(Form3.Volume);
end;

end.


//--------------------
unit Unit3;
//--------------------

interface

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

type
TVolumeChangeEvent = procedure(Volume: integer) of object;

TForm3 = class(TForm)
private
FOnVolumeChanged: TVolumeChangeEvent;
FVolume: integer;
procedure SetVolume(V : Integer);
public
property Volume: Integer read FVolume write SetVolume;
property OnVolumeChanged: TVolumeChangeEvent read FOnVolumeChanged write FOnVolumeChanged;
{ Public declarations }
end;

var
Form3: TForm3;

implementation

procedure TForm3.SetVolume(V : Integer);
begin
Fvolume:=V;
if assigned(OnVolumeChanged) then
FOnVolumeChanged(V); //生成事件
end;

end.


//-----------
program Project1;
//-----------
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2},
Unit3 in 'Unit3.pas' {Form3},
begin
Application.Initialize;
Application.CreateForm(TForm3, Form3);
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);
form1.Show;
form2.Show;
Application.Run;
end.

我的目的是:
无论是按Form1或是Form2的按钮,他都能让两个窗体的label都一起显示当前form3的volume值
 
这个简单,定义事件列表:
在Form3中定义方法:
private
FVolumeChangedEvents: array of TVolumeChangeEvent;
public
procedure RegisterVolumeChanged(AEvent: TVolumeChangeEvent);
////
procedure TForm3.RegisterVolumeChanged(AEvent: TVolumeChangeEvent);
begin
SetLength(FVolumeChangedEvents, Length(FVolumeChangedEvents) + 1);
FVolumeChangedEvents[High(FVolumeChangedEvents)] := AEvent;
end;
//////////
另外,修改
procedure TForm3.SetVolume(V : Integer);
var
I: Integer;
begin
Fvolume:=V;
if Length(FVolumeChangedEvents) > 0 then
begin
for I := 0 to Length(FVolumeChangedEvents) - 1 do
FVolumeChangedEvents(V); //生成事件
end;
end;
 
推荐参考一下 applicationevent 的做法,内部维护一个事件列表,触发时进行多播。
 
1.form1 form2 定义同一个message 函数,
2.form3, 定义一procedur sendvolume 。此过程 appliction.brodcastmessage ,massage中含 form3 的volume。
3.form1 form2 的buttonclick 调用 form3 的sendvolume;
 
一种方法:如LSUPER所说的维护一个事件列表,事件触发时依次调用
另一种方法:
每个调用类都维护一个OldEvent变量如:
TForm1 = class(TForm)
.......................
private
FOldVolume:TVolumeChangeEvent
procedure ShowVolume(V:Integer);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FOldVolume:=Form3.OnVolumeChanged;
Form3.OnVolumeChanged:=ShowVolume; //调用事件
end;

procedure TForm1.ShowVolume(V:Integer);
begin
label1.Caption:=inttostr(Form3.Volume);
if Assigned(FOldVolume) then
FOldVolume(V);
end;
 
xiammy的方法可以,我已经在按他的方法在用了。
但我还想知道lsuper说的“内部维护一个事件列表”,LSUPER和wrl_001,能具体讲一下吗?
 
后退
顶部