背景
我使用一些 FireMonkey 控件创建了一个 GUI。
- 某些控件具有动画效果,其外观会自动更新。
- 某些控件仅根据用户交互( slider 等)进行更新。
问题
与用户控件的交互会阻止动画控件的更新,从而导致动画不连续。
上面视频中的动画控件由 TTimer 组件驱动。使用 FireMonkey 的动画组件时问题仍然存在。
调查
slider 控件在调整时调用 Repaint()。平滑地调整 slider 将生成密集的 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() 调用那样阻止其他控件更新。
关于delphi - FireMonkey 控件的动画效果不流畅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8411143/