首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TTimer未触发

TTimer未触发
EN

Stack Overflow用户
提问于 2012-08-15 01:53:22
回答 2查看 3.5K关注 0票数 3

我有个奇怪的问题。我在我的主窗体上有一个TTimer,它应该触发500毫秒。在创建表单之后。

当我在集成开发环境中运行它时,它工作得很好,但是当我在其他W7 PC上运行它时,主窗体被创建了,但是计时器不会触发。(有些组件不会更新)如果我单击一个控件,所有内容都会更新,计时器会触发,一切都会正常。如果我移动窗体,所有内容都会更新,但计时器不会启动。如果我在安装了Delphi的PC上运行它,它工作得很好。没问题。

MyForm.OnCreate中的代码执行得很好。Timer.Enabled := True不做任何更改。

知道这是什么原因吗?我真的被困在这里了。

诚挚的问候。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-08-16 08:23:44

有多种可能性:

仅当消息队列为空时,才会传递

  1. WM_TIMER消息。如果您的应用程序中的某些内容,或者在其他计算机上运行的另一个应用程序中的某些内容向窗口句柄发布消息的频率足够高,则该窗口的消息队列永远不会清空,则WM_TIMER事件将永远不会触发。如果发生这种情况,您可能需要等待正常TTimer周期的10倍、20倍或30倍,但事件最终可能会触发。到目前为止,我还没有观察到计时器根本不会触发的情况,但这当然是,理论上,你说你知道计时器是启用的(你设置它是启用的),这可能是你的代码中的其他地方禁用了它。
  2. 如果你正在做一些try...except..end代码块,忽略了一个异常,那么可能会发生一些你在其他机器上看不到的糟糕的事情。
  3. 你的计时器代码可能正在触发,但一个异常,在定时器上运行的代码中可能会发生崩溃或挂起。
  4. 你可能在你的代码中有一系列的Delphi事件处理程序,它们造成了几乎“无限循环”的情况,因为你写的一些事件处理程序在你不想要它们的时候触发,导致副作用,这会让你的应用程序忙个不停。你提到你点击了某个地方,问题就消失了。这种点击可能足以中断代码中的其他一些恶性循环。
  5. 你提到它可以在任何安装delphi的PC上运行。您是否正在使用具有某些限制的第三方控件(如要求您在调试器中运行?)。或者,您的应用程序是否加载了一些其他计算机上未安装的DLL或BPLs?

从一个全新的应用程序开始,它里面什么都没有。添加TTimer。现在,在计时器事件上,递增一个整数字段值,并将该值写入表单的标题。现在在其他机器上运行它。它会工作得很好。

现在去看看你写的一大堆代码,并决定如何将你的一大堆代码一分为二,以找到被破坏的那一半。经过足够的步骤,你会发现你的问题所在。这里没有人能帮你调试它。

如果您想在另一台计算机上查看应用程序的一些内部结构,请尝试使用OutputDebugString添加一些日志记录消息,并在其他计算机上运行DebugView

票数 5
EN

Stack Overflow用户

发布于 2018-07-03 06:31:20

老问题我知道,但是我想和你分享这块金子,古老但金子;-)

您还可以将其转换为线程(因为计时器是有限的),我对此做了一个简单的解决方案,一个名为TimerAsThread的单元。将代码另存为TimerAsThread.pas。您需要在extctrls之后包含此单元,或将其作为最后一个单元包含。你不需要改变你的代码,它的工作原理和现在基于线程的一样。线程是一个独立的进程,如果你想了解更多信息,可以在google上搜索。

玩得开心。

代码语言:javascript
复制
{*******************************************************}
{                                                       }
{         Delphi VCL Extensions (RX)                    }
{                                                       }
{         Copyright (c) 1996 AO ROSNO                   }
{         Copyright (c) 1997, 1998 Master-Bank          }
{                                                       }
{*******************************************************}

unit TimerAsThread;

interface



uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  Messages, SysUtils, Classes;

type

{ TTimer }

  TTimer = class(TComponent)
  private
    FEnabled: Boolean;
    FInterval: Cardinal;
    FOnTimer: TNotifyEvent;
    FWindowHandle: HWND;
{$IFDEF WIN32}
    FSyncEvent: Boolean;
    FThreaded: Boolean;
    FTimerThread: TThread;
    FThreadPriority: TThreadPriority;
    procedure SetThreaded(Value: Boolean);
    procedure SetThreadPriority(Value: TThreadPriority);
{$ENDIF}
    procedure SetEnabled(Value: Boolean);
    procedure SetInterval(Value: Cardinal);
    procedure SetOnTimer(Value: TNotifyEvent);
    procedure UpdateTimer;
    procedure WndProc(var Msg: TMessage);
  protected
    procedure Timer; dynamic;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
{$IFDEF WIN32}
    procedure Synchronize(Method: TThreadMethod);
{$ENDIF}
  published
    property Enabled: Boolean read FEnabled write SetEnabled default True;
    property Interval: Cardinal read FInterval write SetInterval default 1000;
{$IFDEF WIN32}
    property SyncEvent: Boolean read FSyncEvent write FSyncEvent default True;
    property Threaded: Boolean read FThreaded write SetThreaded default True;
    property ThreadPriority: TThreadPriority read FThreadPriority write
      SetThreadPriority default tpNormal;
{$ENDIF}
    property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer;
  end;

implementation

uses Forms, Consts, VCLUtils;

{$IFDEF WIN32}

{ TTimerThread }

type
  TTimerThread = class(TThread)
  private
    FOwner: TTimer;
    FInterval: Cardinal;
    FException: Exception;
    procedure HandleException;
  protected
    procedure Execute; override;
  public
    constructor Create(Timer: TTimer; Enabled: Boolean);
  end;

constructor TTimerThread.Create(Timer: TTimer; Enabled: Boolean);
begin
  FOwner := Timer;
  inherited Create(not Enabled);
  FInterval := 1000;
  FreeOnTerminate := True;
end;

procedure TTimerThread.HandleException;
begin
  if not (FException is EAbort) then begin
    if Assigned(Application.OnException) then
      Application.OnException(Self, FException)
    else
      Application.ShowException(FException);
  end;
end;

procedure TTimerThread.Execute;

  function ThreadClosed: Boolean;
  begin
   if( Application.Terminated ) and ( NOT Terminated ) then
    Terminate;

   Result := Terminated or Application.Terminated or (FOwner = nil);
  end;

begin
  repeat
    if not ThreadClosed then
      if SleepEx(FInterval, False) = 0 then begin
        if not ThreadClosed and FOwner.FEnabled then
          with FOwner do
            if SyncEvent then Synchronize(Timer)
            else
              try
                Timer;
              except
                on E: Exception do begin
                  FException := E;
                  HandleException;
                end;
              end;
      end;
  until Terminated;
end;

{$ENDIF}

{ TTimer }

constructor TTimer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FEnabled := True;
  FInterval := 1000;
{$IFDEF WIN32}
  FSyncEvent := True;
  FThreaded := True;
  FThreadPriority := tpNormal;
  FTimerThread := TTimerThread.Create(Self, False);
{$ELSE}
  FWindowHandle := AllocateHWnd(WndProc);
{$ENDIF}
end;

destructor TTimer.Destroy;
begin
  Destroying;
  FEnabled := False;
  FOnTimer := nil;
{$IFDEF WIN32}
  {TTimerThread(FTimerThread).FOwner := nil;}
//  while FTimerThread.Suspended do FTimerThread.Resume;
  FTimerThread.Terminate;
  {if not SyncEvent then FTimerThread.WaitFor;}
  if FWindowHandle <> 0 then begin
{$ENDIF}
    KillTimer(FWindowHandle, 1);
    DeallocateHWnd(FWindowHandle);
{$IFDEF WIN32}
  end;
{$ENDIF}
  inherited Destroy;
end;

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

procedure TTimer.UpdateTimer;
begin
{$IFDEF WIN32}
  if FThreaded then begin
    if FWindowHandle <> 0 then begin
      KillTimer(FWindowHandle, 1);
      DeallocateHWnd(FWindowHandle);
      FWindowHandle := 0;
    end;
    if not FTimerThread.Suspended then FTimerThread.Suspend;
    TTimerThread(FTimerThread).FInterval := FInterval;
    if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then begin
      FTimerThread.Priority := FThreadPriority;
      while FTimerThread.Suspended do FTimerThread.Resume;
    end;
  end
  else begin
    if not FTimerThread.Suspended then FTimerThread.Suspend;
    if FWindowHandle = 0 then FWindowHandle := AllocateHWnd(WndProc)
    else KillTimer(FWindowHandle, 1);
    if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then
      if SetTimer(FWindowHandle, 1, FInterval, nil) = 0 then
        raise EOutOfResources.Create(ResStr(SNoTimers));
  end;
{$ELSE}
  KillTimer(FWindowHandle, 1);
  if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then
    if SetTimer(FWindowHandle, 1, FInterval, nil) = 0 then
      raise EOutOfResources.Create(ResStr(SNoTimers));
{$ENDIF}
end;

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

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

{$IFDEF WIN32}

procedure TTimer.SetThreaded(Value: Boolean);
begin
  if Value <> FThreaded then begin
    FThreaded := Value;
    UpdateTimer;
  end;
end;

procedure TTimer.SetThreadPriority(Value: TThreadPriority);
begin
  if Value <> FThreadPriority then begin
    FThreadPriority := Value;
    if FThreaded then UpdateTimer;
  end;
end;

procedure TTimer.Synchronize(Method: TThreadMethod);
begin
  if (FTimerThread <> nil) then begin
    with TTimerThread(FTimerThread) do begin
      if Suspended or Terminated then Method
      else TTimerThread(FTimerThread).Synchronize(Method);
    end;
  end
  else Method;
end;

{$ENDIF}

procedure TTimer.SetOnTimer(Value: TNotifyEvent);
begin
  if Assigned(FOnTimer) <> Assigned(Value) then begin
    FOnTimer := Value;
    UpdateTimer;
  end else FOnTimer := Value;
end;

procedure TTimer.Timer;
begin
  if FEnabled and not (csDestroying in ComponentState) and
    Assigned(FOnTimer) then FOnTimer(Self);
end;

end. 
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11957954

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档