关于在Delphi中设置动画的指针的棘手事情 [英] Tricky thing about pointers to animate something in Delphi

查看:65
本文介绍了关于在Delphi中设置动画的指针的棘手事情的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我什至都不知道该怎么写.

So, I don't even know how to write the proper title.

我想做的是让进度条动画化.

What I want to do is to animate the position of lets say a progressbar.

可以讨论如何使用计时器和循环等.

One could discuss how to do this with timers and loops and so on.

但是,我希望能够执行以下操作:

However, I want to be able to do something like this:

  1. ProgressBar1.Position:= Animate(ToValue); 或
  2. Animate(ProgressBar1.Position,ToValue);
  1. ProgressBar1.Position:=Animate(ToValue); or
  2. Animate(ProgressBar1.Position, ToValue);

这可能吗?

创建从整数继承的组件无效.

creating a component inherited from an integer didnt work.

我使用指针尝试了2号并完成了此过程

I tried number 2 using pointers and made this procedure

procedure TForm1.Animate(ToValue: integer;  var Dest: Integer);
begin    
  Dest:=ToValue;
end;

,它确实在进度条内部更改了位置值, 但是进度条没有视觉上的改变.

and it did change the position value internally of the progress bar, but the progress bar did not change visually.

如果有人知道如何做到这一点,那就太好了.

If anybody has an idea of how to do this it would be great.

谢谢!

推荐答案

如果您有相对较新的Delphi版本, 这是使用anonymous methods围绕TTimer的动画包装.

If you have a relative new version of Delp this is an animation wrapper around a TTimer using anonymous methods.

type
  Animate = class
    private
      class var fTimer : TTimer;
      class var fStartValue : Integer;
      class var fEndValue : Integer;
      class var fProc : TProc<Integer>;
      class Constructor Create;
      class Destructor Destroy;
      class procedure OnTimer(Sender : TObject);
    public
      class procedure Run( aProc : TProc<Integer>; 
                           fromValue, ToValue, AnimationDelay : Integer);
  end;

class constructor Animate.Create;
begin
  fTimer := TTimer.Create(nil);
  fTimer.Enabled := false;
  fTimer.OnTimer := Animate.OnTimer;
end;

class destructor Animate.Destroy;
begin
  fTimer.Free;
end;

class procedure Animate.OnTimer(Sender: TObject);
begin
  if Assigned(fProc) then
  begin
    if (fStartValue <= fEndValue) then
    begin
      fProc(fStartValue);
      Inc(fStartValue);
    end
    else
      fTimer.Enabled := false;
  end;
end;

class procedure Animate.Run( aProc: TProc<Integer>; 
                             fromValue, ToValue, AnimationDelay: Integer);
begin
  fTimer.Interval := AnimationDelay;
  fStartValue := fromValue;
  fEndValue := ToValue;
  fProc := aProc;
  fTimer.Enabled := (fStartValue <= fEndValue);
end;

Animate类在应用程序启动/停止时是自初始化和自破坏的. 只能激活一个动画过程.

The Animate class is self initializing and self destructing on application start/stop. Only one animation process can be active.

以这种方式使用它:

Animate.Run(
  procedure( aValue : Integer)
  begin 
    ProgressBar1.Position := aValue;
    ProgressBar1.Update;
  end,
  1,100,5
);


如注释中所述,以上代码使用类变量和类函数.缺点是只能激活一个动画.


As discussed in comments, the above code use class variables and class functions. Drawback is only one animation can be active.

这是一个更完整的动画类,您可以在其中实例化任意数量的动画.扩展的功能,可以停止/继续进行,在准备就绪时添加事件,还有更多属性.

Here is a more complete animation class, where you can instantiate as many animations you like. Expanded functionallity with possibility to stop/proceed, adding an event when ready, and some more properties.

unit AnimatePlatform;

interface

uses
  System.Classes,System.SysUtils,Vcl.ExtCtrls;

type
  TAnimate = class
    private
      fTimer : TTimer;
      fLoopIx : Integer;
      fEndIx : Integer;
      fProc : TProc<Integer>;
      fOnReady : TProc<TObject>;
      procedure OnTimer(Sender : TObject);
      function GetRunning : boolean;
      procedure SetReady;
    public
      Constructor Create;
      Destructor Destroy; override;
      procedure Run( aProc : TProc<Integer>;
                     FromValue,ToValue,AnimationDelay : Integer); overload;
      procedure Run( aProc : TProc<Integer>;
                     FromValue,ToValue,AnimationDelay : Integer;
                     AReadyEvent : TNotifyEvent); overload;
      procedure Run( aProc : TProc<Integer>;
                     FromValue,ToValue,AnimationDelay : Integer;
                     AReadyEvent: TProc<TObject>); overload;
      procedure Stop;
      procedure Proceed;
      property ActualLoopIx : Integer read fLoopIx write fLoopIx;
      property Running : boolean read GetRunning;
      property OnReady : TProc<TObject> read fOnReady write fOnReady;
  end;

implementation

constructor TAnimate.Create;
begin
  Inherited;
  fTimer := TTimer.Create(nil);
  fTimer.Enabled := false;
  fTimer.OnTimer := Self.OnTimer;
  fOnReady := nil;
end;

destructor TAnimate.Destroy;
begin
  fTimer.Free;
  Inherited;
end;

function TAnimate.GetRunning: boolean;
begin
  Result := fTimer.Enabled;
end;

procedure TAnimate.OnTimer(Sender: TObject);
begin
  if Assigned(fProc) then
  begin
    if (fLoopIx <= fEndIx) then
    begin
      fProc(fLoopIx);
      Inc(fLoopIx);
    end;
    if (fLoopIx > fEndIx) then
      SetReady;
  end
  else SetReady;
end;

procedure TAnimate.Proceed;
begin
  fTimer.Enabled := true;
end;

procedure TAnimate.Run(aProc: TProc<Integer>; FromValue, ToValue,
  AnimationDelay: Integer; AReadyEvent: TNotifyEvent);
begin
  Run(aProc,FromValue,ToValue,AnimationDelay);
  fOnReady := AReadyEvent;
end;

procedure TAnimate.Run(aProc: TProc<Integer>; FromValue, ToValue,
  AnimationDelay: Integer; AReadyEvent: TProc<TObject>);
begin
  Run(aProc,FromValue,ToValue,AnimationDelay);
  fOnReady := AReadyEvent;
end;

procedure TAnimate.Run(aProc: TProc<Integer>; fromValue, ToValue,
  AnimationDelay: Integer);
begin
  fTimer.Interval := AnimationDelay;
  fLoopIx :=         fromValue;
  fEndIx :=          ToValue;
  fProc :=           aProc;
  fTimer.Enabled :=  true;
end;

procedure TAnimate.SetReady;
begin
  Stop;
  if Assigned(fOnReady) then
    fOnReady(Self);
end;

procedure TAnimate.Stop;
begin
  fTimer.Enabled := false;
end;

end.


更新:

这是使用TTimer的动画师. > anonymous thread :

Instead of a TTimer based animator, here is a version using an anonymous thread:

uses
  SyncObjs;

procedure AnimatedThread( aProc: TProc<Integer>;
                          FromValue, ToValue, AnimationDelay: Integer;
                          AReadyEvent: TNotifyEvent);
begin
  TThread.CreateAnonymousThread(
    procedure
    var
      i: Integer;
      w : TSimpleEvent;
    begin
      w := TSimpleEvent.Create(Nil,False,False,'');
      try
        for i := FromValue to ToValue do begin
          TThread.Synchronize(nil,
            procedure
            begin
              aProc(i);
            end
          );
          w.WaitFor(AnimationDelay);
        end;
      finally
        w.Free;
      end;
      if Assigned(AReadyEvent) then
        TThread.Synchronize(nil,
          procedure
          begin
            AReadyEvent(Nil);
          end
        );
    end
  ).Start;
end;

// Example call

AnimateThread(
  procedure(aValue: Integer)
  begin 
    ProgressBar1.Position := aValue;
    ProgressBar1.Update;
  end,
  1,100,5,nil
); 

这篇关于关于在Delphi中设置动画的指针的棘手事情的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆