加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – FireMonkey控件不能平滑地设置动画

发布时间:2020-12-15 10:12:29 所属栏目:大数据 来源:网络整理
导读:背景 我使用一些FireMonkey控件创建了一个GUI. 某些控件是动画的,其外观会自动更新. 某些控件仅响应用户交互(滑块等)而更新. 问题 与用户控件的交互可防止更新动画控件,从而导致不稳定的不连续动画. Video of glitchy animation 上面视频中的动画控件由TTime
背景

我使用一些FireMonkey控件创建了一个GUI.

>某些控件是动画的,其外观会自动更新.
>某些控件仅响应用户交互(滑块等)而更新.

问题

与用户控件的交互可防止更新动画控件,从而导致不稳定的不连续动画.

Video of glitchy animation

上面视频中的动画控件由TTimer组件驱动.使用FireMonkey的动画组件时问题仍然存在.

调查

滑块控件在调整时调用Repaint().平滑调整滑块将生成密集的Repaint()调用流,阻止其他控件更新.

该怎么办?

在一个控件不断更新时冻结动画不适合我的应用程序.我的第一个想法是交换Repaint()调用类似于VCL Invalidate()方法,但FireMonkey没有任何可比的AFAIK.

这个问题有一个很好的解决方法吗?

解决方法

我已经创建了一个基于计时器的重绘方法,正如Arnaud Bouchez在上面的评论中所建议的那样.到目前为止似乎有效.

unit FmxInvalidateHack;

interface

uses
  Fmx.Types;

procedure InvalidateControl(aControl : TControl);


implementation

uses
  Contnrs;

type
  TInvalidator = class
  private
  protected
    Timer : TTimer;
    List  : TObjectList;
    procedure Step(Sender : TObject);
  public
    constructor Create;
    destructor Destroy; override;

    procedure AddToQueue(aControl : TControl);
  end;

var
  GlobalInvalidator : TInvalidator;

procedure InvalidateControl(aControl : TControl);
begin
  if not assigned(GlobalInvalidator) then
  begin
    GlobalInvalidator := TInvalidator.Create;
  end;
  GlobalInvalidator.AddToQueue(aControl);
end;


{ TInvalidator }

constructor TInvalidator.Create;
const
  FrameRate = 30;
begin
  List  := TObjectList.Create;
  List.OwnsObjects := false;

  Timer := TTimer.Create(nil);
  Timer.OnTimer  := Step;
  Timer.Interval := round(1000 / FrameRate);
  Timer.Enabled  := true;
end;

destructor TInvalidator.Destroy;
begin
  Timer.Free;
  List.Free;
  inherited;
end;

procedure TInvalidator.AddToQueue(aControl: TControl);
begin
  if List.IndexOf(aControl) = -1 then
  begin
    List.Add(aControl);
  end;
end;

procedure TInvalidator.Step(Sender: TObject);
var
  c1: Integer;
begin
  for c1 := 0 to List.Count-1 do
  begin
    (List[c1] as TControl).Repaint;
  end;
  List.Clear;
end;


initialization

finalization
  if assigned(GlobalInvalidator) then GlobalInvalidator.Free;

end.

==

用法

可以通过调用重新绘制控件:

InvalidateControl(MyControl);

InvalidateControl()过程不会立即重新绘制控件.相反,它将控件添加到列表中.全局计时器稍后检查列表,调用Repaint()并从列表中删除控件.使用此方法,可以根据需要使控件无效,但不会像快速Repaint()调用那样阻止其他控件被更新.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读