9

バックグラウンド

いくつかの FireMonkey コントロールを使用して GUI を作成しました。

  • 一部のコントロールはアニメーション化され、外観が自動的に更新されます。
  • 一部のコントロールは、ユーザーの操作 (スライダーなど) に応じてのみ更新されます。

問題

ユーザー コントロールを操作すると、アニメーション化されたコントロールの更新が妨げられ、ぎくしゃくした不連続なアニメーションが発生します。

グリッチアニメーションのビデオ

上のビデオのアニメーション コントロールは、TTimer コンポーネントによって駆動されます。FireMonkey のアニメーション コンポーネントを使用すると、問題が解決しません。

調査

スライダー コントロールは、調整時に Repaint() を呼び出します。スライダーをスムーズに調整すると、他のコントロールの更新をブロックする Repaint() 呼び出しの密なストリームが生成されます。

何をすべきか?

1 つのコントロールが継続的に更新されている間にアニメーションをフリーズすることは、私のアプリケーションには適していません。私が最初に考えたのは、Repaint() 呼び出しを VCL の Invalidate() メソッドに似たものに交換することですが、FireMonkey には同等のものはありません。

この問題の適切な回避策はありますか?

4

1 に答える 1

4

上記のコメントで 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() 呼び出しが行うように、他のコントロールの更新をブロックすることはありません。

于 2011-12-08T00:42:09.007 に答える