Элементы управления FireMonkey не анимируются плавно

Фон

Я создал графический интерфейс с использованием некоторых элементов управления FireMonkey.

  • Некоторые элементы управления анимированы, и их внешний вид обновляется автоматически.
  • Некоторые элементы управления обновляются только в ответ на взаимодействие с пользователем (ползунки и т. Д.).

проблема

Взаимодействие с пользовательскими элементами управления предотвращает обновления анимированных элементов управления, что приводит к прерывистой прерывистой анимации.

Видео глючной анимации

Анимированное управление в видео выше управляется компонентом TTimer. Проблема сохраняется при использовании компонентов анимации FireMonkey.

изучение

Слайдер управляет вызовом Repaint() при настройке. Плавная настройка ползунка создаст плотный поток вызовов Repaint(), которые блокируют обновление других элементов управления.

Что делать?

Замораживание анимации, когда один элемент управления постоянно обновляется, не подходит для моего приложения. Моя первая мысль - поменять вызовы Repaint() на что-то похожее на метод VCL Invalidate(), но FireMonkey не имеет ничего похожего на AFAIK.

Есть ли хорошее решение этой проблемы?

1 ответ

Решение

Я создал метод перерисовки на основе таймера, как предложил Арно Буше в комментариях выше. Пока что похоже на работу.

Код

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().

Другие вопросы по тегам