关于在非窗体类中创建定时器的问题 ( 积分: 100 )

  • 主题发起人 主题发起人 零度
  • 开始时间 开始时间

零度

Unregistered / Unconfirmed
GUEST, unregistred user!
大家好,最近在编程中碰到这样一个问题,不知如何解决,非常的苦恼。
在程序中,我写了一个类作为基类,它没有从任何地方派生,同时在此基类上,派生出自己的子类,现在,我就想在这一子类中,创建一个定时器,但是,无论是基类还是派生类都不是窗体类,因此无法得到系统的消息,不能采用procedure TimerTick(var Msg:TMessage);Message WM_TIMER;SetTimer(Handle,1,1000,nil);的方法写定时器的过程,请问,我该怎么办,需要说明的是,所有派生的子类是作为对象在主程序中创建的,下面我以简单的代码,说明这一过程:
定义基类:TA = class
定义派生类:TB = class(TA)
在主程序中动态创建对象temp := TB.Create;{可动态创建多个}
 
大家好,最近在编程中碰到这样一个问题,不知如何解决,非常的苦恼。
在程序中,我写了一个类作为基类,它没有从任何地方派生,同时在此基类上,派生出自己的子类,现在,我就想在这一子类中,创建一个定时器,但是,无论是基类还是派生类都不是窗体类,因此无法得到系统的消息,不能采用procedure TimerTick(var Msg:TMessage);Message WM_TIMER;SetTimer(Handle,1,1000,nil);的方法写定时器的过程,请问,我该怎么办,需要说明的是,所有派生的子类是作为对象在主程序中创建的,下面我以简单的代码,说明这一过程:
定义基类:TA = class
定义派生类:TB = class(TA)
在主程序中动态创建对象temp := TB.Create;{可动态创建多个}
 
首先Handle就有问题,Handle在TControl类中还没有出现呢,在它的派生类TWinControl才第一次出现,不只你是如何Handle的
 
另外,如果你是自定义Handle的话,有没有用AllocateHWnd函数创建了一个隐藏窗口并且返回它的句柄?其实就是回调函数
procedure WndProc(var Msg: TMessage);
Handle:= Classes.AllocateHWnd(WndProc);
 
unit Unit20;

interface
uses Windows,Forms,ExtCtrls,Dialogs;
type
TA=class

end;

TB = class(TA)
myTimer:TTimer;
public
constructor Create;
procedure OnTimerTick(Sender: TObject);

end;


implementation

constructor TB.Create;
begin
inherited;
mytimer:=TTimer.Create(Application);
myTimer.OnTimer:=OnTimerTick;
myTimer.Interval:=5;
end;

procedure TB.OnTimerTick(Sender: TObject);
begin
ShowMessage('ticked');
end;

end.
 
消息只能在有Handle的窗体或构件中传递,无论这个窗体是可是的还是隐藏的。
如果Handle不正确,就像非要把没有写名字的信送出去一样为难,即使信是如何正确。

ps:我写了一个类作为基类,它没有从任何地方派生 这句话也欠妥,其实你是从基类TObject继承下来的。
TObject是Object Pascal中所有类的祖先,TClass是Object Pascal中所有类引用的祖先.
type
TObject = class;
TClass = class of TObject;

详见system单元
 
给你两个建议吧
一是创建一个大小为0的隐藏窗体(其实不显示就行)作为宿主窗体
二是主窗体(或者一个专门的窗体)作为管理器,专门为它派发消息
不过这样需要自己来管理好多东西了
 
三楼的可以
 
hannuman的方法可行,cactus123456的方法似乎有道理,不过我试了一下,总是报错,没有成功,如果能说仔细点,我另外再派分给你,谢谢!!
 
接收答案!
 
其实非常简单,hannuman的方法可以实现你的功能,不过你非要在类中实现的话,可以这样
另外不需要另外给分了,我们只是共同探讨问题。
unit Unit2;

interface

uses
Windows,Classes,Messages;

const
SNoTimers = 'Not enough timers available';

Type
TA=class
public
constructor Create(AOwner: TA); virtual;
end;

TB= class(TA)
private
FInterval: Cardinal;
FWindowHandle: HWND;
FOnTimer: TNotifyEvent;
FEnabled: Boolean;
procedure UpdateTimer;
procedure SetEnabled(Value: Boolean);
procedure SetInterval(Value: Cardinal);
procedure SetOnTimer(Value: TNotifyEvent);
procedure WndProc(var Msg: TMessage);
protected
procedure Timer; dynamic;
public
constructor Create(AOwner: TA); override;
destructor Destroy; override;
published
property Enabled: Boolean read FEnabled write SetEnabled default True;
property Interval: Cardinal read FInterval write SetInterval default 1000;
property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer;
end;


implementation

constructor TA.Create(AOwner: TA);
begin
end;

constructor TB.Create(AOwner: TA);
begin
inherited Create(AOwner);
FEnabled := True;
FInterval := 1000;
FWindowHandle := Classes.AllocateHWnd(WndProc); //我说的问题的关键在这里
end;

destructor TB.Destroy;
begin
FEnabled := False;
UpdateTimer;
Classes.DeallocateHWnd(FWindowHandle);
inherited Destroy;
end;

procedure TB.WndProc(var Msg: TMessage);
begin
with Msg do
if Msg = WM_TIMER then
try
Timer;
except
end
else
Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
end;

procedure TB.UpdateTimer;
begin
KillTimer(FWindowHandle, 1);
if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then
if SetTimer(FWindowHandle, 1, FInterval, nil) = 0 then
raise EOutOfResources.Create(SNoTimers);
end;

procedure TB.SetEnabled(Value: Boolean);
begin
if Value <> FEnabled then
begin
FEnabled := Value;
UpdateTimer;
end;
end;

procedure TB.SetInterval(Value: Cardinal);
begin
if Value <> FInterval then
begin
FInterval := Value;
UpdateTimer;
end;
end;

procedure TB.SetOnTimer(Value: TNotifyEvent);
begin
FOnTimer := Value;
UpdateTimer;
end;

procedure TB.Timer;
begin
if Assigned(FOnTimer) then FOnTimer(Self);
end;


end.
 
我试试,谢谢!
 
后退
顶部