TTimer 作为组件属性问题

Posted

技术标签:

【中文标题】TTimer 作为组件属性问题【英文标题】:TTimer as a component property issue 【发布时间】:2021-05-18 02:09:22 【问题描述】:

我从 (TShape) 创建了一个新组件,并将 Timer 属性设置为下一个 ::

property Timer:TTimer read FDeviceTimer write SetDeviceTimer ;

这个计时器的目的是我希望它在设计时通过使用下一个过程来更改组件高度:

procedure TFireDeviceWTimer.OnTimerRepaint(Sender: TObject);
begin
    //==================
    if ChangDim then begin
        Height:=Height+10;
        //Repaint;
        Sleep(FDeviceTimer.Interval);
        ChangDim:=False;
    end 
    else begin
        Height:=Height-10;
        //Repaint;
        Sleep(FDeviceTimer.Interval);
        ChangDim:=true;
    end;
end;

而且效果很好,但是我在运行时使用它后注意到的问题是,它使应用程序太慢了...

任何人都可以解释此类问题的原因和解决方案..

谢谢你。

【问题讨论】:

OnTimer 事件使用应用程序的 UI 线程(主线程)运行。由于您将两个 Sleep 语句放入此事件中,因此您阻塞了 UI 线程,不允许它执行任何其他操作(例如重绘或响应鼠标/键盘事件)。只需丢失Sleep 语句并设置所需的计时器间隔。 您将不得不抛弃整个设计,并了解基于事件驱动的基于 Windows 线程的 UI 设计的工作原理 没有充分的理由将 TTimer 直接作为属性公开。它只能用作组件实现中的内部细节。 如果 OnTimerRepaint 是 FDeviceTimer.OnTimer 的处理程序,则只需删除两个 Sleep 调用。为了使您的代码更常用,请重命名 OnTimerRepaint DeviceTimerTimer。雷米的建议也很好。公开时间间隔,而不是计时器。 亲爱的 R.Hoek ..你已经解决了这个问题 ..非常感谢.. 【参考方案1】:

原因:TTimer 在主应用程序的同一线程中工作。

解决方案:创建一个循环直到主要组件被销毁的线程,而不是计时器。

为此,您可以在组件的构造函数中放入类似这样的内容

FPaintThread := CreateAnonymouseThread(procedure
begin
    while assigned(Self) and (not Application.Terminated) do
    begin
        RepainInstruction;
        Sleep(100);
    end;
end);
FPaintThread.Start;

但请记住使用 TThread.Synchronize 与主要的 Thread 对象进行交互以防止错误。

【讨论】:

以上是关于TTimer 作为组件属性问题的主要内容,如果未能解决你的问题,请参考以下文章

作为对象的 Vue 道具的反应性

Angular2 中组件属性变化的可观察性

重用具有不同样式的 React 组件

材料组件 Web 和 React:无法读取未定义的属性“querySelector”;

如何切换 VueJs 组件的可见性?

添加中心性度量作为顶点属性