关于在Delphi中设置动画的指针的棘手事情 [英] Tricky thing about pointers to animate something in 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:
- ProgressBar1.Position:= Animate(ToValue); 或
- Animate(ProgressBar1.Position,ToValue);
- ProgressBar1.Position:=Animate(ToValue); or
- 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屋!