【发布时间】:2012-05-05 01:18:09
【问题描述】:
我的第一个问题 - 如果不够具体,请道歉!
我自愿在 Delphi 中为当地的帆船俱乐部编写了一个应用程序。这会每 3 分钟触发各种(RS232 命令)灯 + Klaxon 启动信号,整个序列可能需要 24 分钟。由于水手设置了秒表,因此这必须比 24 分钟内的 1 秒好得多。
我有一个准确的线程计时器组件,并且在Timer.Execute proc 中我需要更新 GUI 等 - 这会导致冻结/崩溃等。有什么更好的方法来做到这一点?
我认为我不应该在执行时更改 GUI 对象,但是如何解决呢? (我对线程不是很熟悉)。非常感谢您的建议。如果需要任何进一步的信息,我很乐意提供。
克里斯
加法 - CairnTimer 类
code
unit CairnTimer;
interface
uses
Windows,SysUtils,Classes,Dialogs;
type
TCairnTimer=class(TComponent)
private
TimerOn: Boolean;
TimerThreadPriority: TThreadPriority;
TimerPaused: Boolean;
TimerDelay: Cardinal;
TimerResolution: Cardinal;
TimerTicks: Cardinal;
TimerMilliSeconds: Cardinal;
OnTimerEvent: TNotifyEvent;
OnTimerEventHandle: Integer;
TimerName: Integer;
protected
procedure InitTimer;
procedure SetTimerTicks(NewTicks: Cardinal);
procedure UpdateTimerStatus(NewOn: Boolean);
procedure UpdateTimerPriority(NewPriority: TThreadPriority);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Resume;
procedure Pause;
property Ticks: Cardinal read TimerTicks default 0;
property MilliSeconds: Cardinal read TimerMilliSeconds default 0;
published
property Enabled: Boolean read TimerOn write UpdateTimerStatus default False;
property TimerPriority: TThreadPriority read TimerThreadPriority write UpdateTimerPriority default tpNormal;
property Delay: Cardinal read TimerDelay write TimerDelay default 100;
property Resolution: Cardinal read TimerResolution write TimerResolution default 10;
property OnTimer: TNotifyEvent read OnTimerEvent write OnTimerEvent;
end;
TCairnTimerThread=class(TThread)
public
CairnTimer: TCairnTimer;
procedure Execute; override;
end;
TCairnTimerCallBack=procedure(NA1,NA2,CairnTimerUser,NA3,NA4: Integer) stdcall;
ECairnTimer=class(Exception);
var
CairnTimerThread: TCairnTimerThread;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('System',[TCairnTimer]);
end;
function KillTimer(CairnTimerName: Integer): Integer;stdcall;
external 'WinMM.dll' name 'timeKillEvent';
function SetTimer(TimerDelay,TimerResolution: Integer;
CairnTimerCallBack: TCairnTimerCallBack;
CairnTimerUser,CairnTimerFlags: Integer): Integer;stdcall;
external 'WinMM.dll' name 'timeSetEvent';
procedure TCairnTimerThread.Execute;
var
TickRecord: Cardinal;
begin
TickRecord:=0;
while not(Terminated)and Assigned(CairnTimer)do
begin
WaitForSingleObject(CairnTimer.OnTimerEventHandle,INFINITE);
Inc(TickRecord);
CairnTimer.SetTimerTicks(TickRecord);
if Assigned(CairnTimer.OnTimerEvent)then
CairnTimer.OnTimerEvent(CairnTimer);
end;
end;
constructor TCairnTimer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
TimerOn:=False;
TimerDelay:=100;
TimerResolution:=10;
TimerPaused:=False;
TimerTicks:=0;
TimerMilliSeconds:=0;
TimerThreadPriority:=tpNormal;
OnTimerEventHandle:=CreateEvent(nil,False,False,nil);
end;
destructor TCairnTimer.Destroy;
begin
Enabled:=False;
CloseHandle(OnTimerEventHandle);
inherited Destroy;
end;
procedure TCairnTimer.SetTimerTicks(NewTicks: Cardinal);
begin
TimerTicks:=NewTicks;
TimerMilliSeconds:=TimerMilliSeconds+TimerDelay;
end;
procedure CairnTimerCallBack(NA1,NA2,CairnTimerUser,NA3,NA4: Integer); stdcall;
var
CairnTimer: TCairnTimer;
begin
CairnTimer:=TCairnTimer(CairnTimerUser);
if Assigned(CairnTimer) then
if not CairnTimer.TimerPaused then
SetEvent(CairnTimer.OnTimerEventHandle);
end;
procedure TCairnTimer.InitTimer;
begin
TimerName:=SetTimer(TimerDelay,TimerResolution,@CairnTimerCallBack,Integer(Self),1);
if TimerName=0 then
begin
TimerOn:=False;
raise ECairnTimer.Create('Cairn timer creation error.');
end;
end;
procedure TCairnTimer.UpdateTimerStatus(NewOn: Boolean);
begin
if NewOn=TimerOn then Exit;
if (csDesigning in ComponentState) then
begin
TimerOn:=NewOn;
Exit;
end;
if(NewOn)then
begin
CairnTimerThread:=TCairnTimerThread.Create(True);
CairnTimerThread.CairnTimer:=Self;
CairnTimerThread.FreeOnTerminate:=True;
CairnTimerThread.Priority:=TimerThreadPriority;
CairnTimerThread.CairnTimer.InitTimer;
CairnTimerThread.Resume;
TimerTicks:=0;
TimerMilliSeconds:=0;
end;
if(not(NewOn))then
begin
KillTimer(TimerName);
TerminateThread(CairnTimerThread.Handle,0);
CairnTimerThread.Free;
end;
TimerOn:=NewOn;
end;
procedure TCairnTimer.UpdateTimerPriority(NewPriority: TThreadPriority);
begin
if NewPriority=TimerThreadPriority then Exit;
if Assigned(CairnTimerThread) then
begin
CairnTimerThread.Priority:=NewPriority;
end;
TimerThreadPriority:=NewPriority;
end;
procedure TCairnTimer.Pause;
begin
if TimerOn then CairnTimerThread.Suspend;
TimerPaused:=True;
end;
procedure TCairnTimer.Resume;
begin
if TimerOn then CairnTimerThread.Resume;
TimerPaused:=False;
end;
end.
【问题讨论】:
-
欢迎来到 StackOverflow。如果没有任何代码来显示您在做什么,很难说出您可能做错了什么。你用的是什么线程定时器?您是否正在使用
Synchronize更新 GUI?如果没有,您将如何尝试更新它?请编辑您的问题以提供更多信息(最好以某些代码的形式),以便更清楚您当前正在做什么。 (另外,freezes/crashes/etc.是对错误或问题的毫无意义的描述;它也没有提供太多信息。) -
也许[delphi] update gui thread搜索中的一个问题对你有一些有用的信息。
-
我正在使用一个名为 CairnTimer 的免费软件组件。我没有使用同步。线程计时器执行如下所示:
-
过程 TCairnTimerThread.Execute; var TickRecord:红衣主教;开始 TickRecord:=0;而不是(终止)和分配(CairnTimer)开始 WaitForSingleObject(CairnTimer.OnTimerEventHandle,INFINITE);公司(滴答记录); CairnTimer.SetTimerTicks(TickRecord);如果已分配(CairnTimer.OnTimerEvent)则 CairnTimer.OnTimerEvent(CairnTimer);结尾;结束;
-
为什么需要用线程来做这个?我看不出他们有什么帮助。相反,线程可能只会使事情复杂化