Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi中指针动画的技巧_Delphi_Pointers_Jquery Animate - Fatal编程技术网

Delphi中指针动画的技巧

Delphi中指针动画的技巧,delphi,pointers,jquery-animate,Delphi,Pointers,Jquery Animate,所以,我甚至不知道如何写正确的标题 我想做的是设置进度条位置的动画 我们可以讨论如何使用计时器和循环等来实现这一点 但是,我希望能够做到以下几点: ProgressBar1.Position:=动画(ToValue); 或 设置动画(ProgressBar1.Position,ToValue) 这可能吗 创建从整数继承的组件无效 我用指针尝试了数字2,并完成了这个过程 procedure TForm1.Animate(ToValue: integer; var Dest: Integer);

所以,我甚至不知道如何写正确的标题

我想做的是设置进度条位置的动画

我们可以讨论如何使用计时器和循环等来实现这一点

但是,我希望能够做到以下几点:

  • ProgressBar1.Position:=动画(ToValue); 或
  • 设置动画(ProgressBar1.Position,ToValue) 这可能吗

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

    我用指针尝试了数字2,并完成了这个过程

    procedure TForm1.Animate(ToValue: integer;  var Dest: Integer);
    begin    
      Dest:=ToValue;
    end;
    
    它确实改变了进度条内部的位置值, 但是进度条在视觉上没有改变

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


    谢谢大家!

    使用RTTI,您可以轻松做到这一点

    无法避免编写循环,但可以编写一次循环,并为要设置的任何对象/属性调用动画方法。当然,编写这样的函数仍然很棘手,因为您必须考虑闪烁、UI阻塞的时间等因素

    一个非常简单的例子如下:

    implementation
    uses RTTI;
    
    
    procedure TForm1.Animate(AObj: TObject; APropertyName: string; AValue: Integer);
    var
      Context: TRTTIContext;
      OType: TRTTIType;
      Prop: TRTTIProperty;
      StartValue: Integer;
    begin
      Context := TRTTIContext.Create;
      OType := context.GetType(AObj.ClassType);
      Prop := OType.GetProperty(APropertyName);
      StartValue := Prop.GetValue(AObj).AsInteger;
      for AValue := StartValue to AValue do
      begin
        Prop.SetValue(AObj, AValue);
        if AObj is TWinControl then
        begin
          TWinControl(AObj).Update;
          Sleep(3);
        end;
      end;
    end;
    
    
    //call it like this:
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Animate(ProgressBar1, 'Position', 30);
      Animate(Self, 'Height', 300);
    end;
    

    使用RTTI可以很容易地做到这一点

    无法避免编写循环,但可以编写一次循环,并为要设置的任何对象/属性调用动画方法。当然,编写这样的函数仍然很棘手,因为您必须考虑闪烁、UI阻塞的时间等因素

    一个非常简单的例子如下:

    implementation
    uses RTTI;
    
    
    procedure TForm1.Animate(AObj: TObject; APropertyName: string; AValue: Integer);
    var
      Context: TRTTIContext;
      OType: TRTTIType;
      Prop: TRTTIProperty;
      StartValue: Integer;
    begin
      Context := TRTTIContext.Create;
      OType := context.GetType(AObj.ClassType);
      Prop := OType.GetProperty(APropertyName);
      StartValue := Prop.GetValue(AObj).AsInteger;
      for AValue := StartValue to AValue do
      begin
        Prop.SetValue(AObj, AValue);
        if AObj is TWinControl then
        begin
          TWinControl(AObj).Update;
          Sleep(3);
        end;
      end;
    end;
    
    
    //call it like this:
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Animate(ProgressBar1, 'Position', 30);
      Animate(Self, 'Height', 300);
    end;
    

    只能将整数指定给进度条的位置。因此,如果要使位置从一个值平滑移动到另一个值,则需要将位置设置为每个单独的值


    没有便捷的捷径。没有比jQuery的animate()方法更现成的方法了。你提到计时器和循环。这些是你需要使用的方法

    除了给进度条的位置分配整数外,不能分配其他任何内容。因此,如果要使位置从一个值平滑移动到另一个值,则需要将位置设置为每个单独的值


    没有便捷的捷径。没有比jQuery的animate()方法更现成的方法了。你提到计时器和循环。这些是你需要使用的方法

    正如大卫所说,你需要使用计时器。下面是一些代码,演示了这个原理。我建议您接受这个想法,并将其应用到您自己的TProgressbar后代中

    请注意,在Vista和Windows 7下,当递增位置时,TProgressBar具有一些内置动画。使用自己的动画时,这可能会产生奇怪的效果

    您没有提到您使用的是哪个版本的Delphi。此示例是使用XE2创建的。如果您使用的是早期版本,则可能需要修复uses子句中的虚线单元名称,例如Winapi。Windows应为Windows

    代码:

    unit Unit11;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ExtCtrls,
      Vcl.Samples.Spin;
    
    type
      TForm11 = class(TForm)
        ProgressBar1: TProgressBar;
        Timer1: TTimer;
        Button1: TButton;
        Button2: TButton;
        spnIncrement: TSpinEdit;
        Label1: TLabel;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        FDestPos: Integer;
        FProgInc: Integer;
        procedure AnimateTo(const DestPos, Increment: Integer);
      public
        { Public declarations }
      end;
    
    var
      Form11: TForm11;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm11.Button1Click(Sender: TObject);
    begin
      AnimateTo(10, spnIncrement.Value);
    end;
    
    procedure TForm11.Button2Click(Sender: TObject);
    begin
      AnimateTo(90, spnIncrement.Value);
    end;
    
    procedure TForm11.Timer1Timer(Sender: TObject);
    begin
      if ((FProgInc > 0) and (ProgressBar1.Position + FProgInc >= FDestPos)) or
         ((FProgInc < 0) and (ProgressBar1.Position + FProgInc <= FDestPos)) then
      begin
        ProgressBar1.Position := FDestPos;
    
        Timer1.Enabled := FALSE;
      end
      else
      begin
        ProgressBar1.Position := ProgressBar1.Position + FProgInc;
      end;
    end;
    
    procedure TForm11.AnimateTo(const DestPos, Increment: Integer);
    begin
      FDestPos := DestPos;
    
      FProgInc := Increment;
    
      if FDestPos < ProgressBar1.Position then
        FProgInc := -FProgInc;
    
      Timer1.Enabled := FProgInc <> 0;
    end;
    
    end. 
    
    object Form11: TForm11
      Left = 0
      Top = 0
      BorderStyle = bsDialog
      Caption = 'Animated Progressbar'
      ClientHeight = 77
      ClientWidth = 466
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      Position = poScreenCenter
      PixelsPerInch = 96
      TextHeight = 13
      object Label1: TLabel
        Left = 309
        Top = 42
        Width = 53
        Height = 13
        Caption = 'Increment:'
      end
      object ProgressBar1: TProgressBar
        Left = 24
        Top = 16
        Width = 417
        Height = 17
        TabOrder = 0
      end
      object Button1: TButton
        Left = 24
        Top = 39
        Width = 75
        Height = 25
        Caption = '10%'
        TabOrder = 1
        OnClick = Button1Click
      end
      object Button2: TButton
        Left = 105
        Top = 39
        Width = 75
        Height = 25
        Caption = '90%'
        TabOrder = 2
        OnClick = Button2Click
      end
      object spnIncrement: TSpinEdit
        Left = 368
        Top = 39
        Width = 73
        Height = 22
        MaxValue = 100
        MinValue = 1
        TabOrder = 3
        Value = 0
      end
      object Timer1: TTimer
        Enabled = False
        Interval = 20
        OnTimer = Timer1Timer
        Left = 240
        Top = 40
      end
    end
    

    正如大卫所说,你需要使用计时器。下面是一些代码,演示了这个原理。我建议您接受这个想法,并将其应用到您自己的TProgressbar后代中

    请注意,在Vista和Windows 7下,当递增位置时,TProgressBar具有一些内置动画。使用自己的动画时,这可能会产生奇怪的效果

    您没有提到您使用的是哪个版本的Delphi。此示例是使用XE2创建的。如果您使用的是早期版本,则可能需要修复uses子句中的虚线单元名称,例如Winapi。Windows应为Windows

    代码:

    unit Unit11;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ExtCtrls,
      Vcl.Samples.Spin;
    
    type
      TForm11 = class(TForm)
        ProgressBar1: TProgressBar;
        Timer1: TTimer;
        Button1: TButton;
        Button2: TButton;
        spnIncrement: TSpinEdit;
        Label1: TLabel;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        FDestPos: Integer;
        FProgInc: Integer;
        procedure AnimateTo(const DestPos, Increment: Integer);
      public
        { Public declarations }
      end;
    
    var
      Form11: TForm11;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm11.Button1Click(Sender: TObject);
    begin
      AnimateTo(10, spnIncrement.Value);
    end;
    
    procedure TForm11.Button2Click(Sender: TObject);
    begin
      AnimateTo(90, spnIncrement.Value);
    end;
    
    procedure TForm11.Timer1Timer(Sender: TObject);
    begin
      if ((FProgInc > 0) and (ProgressBar1.Position + FProgInc >= FDestPos)) or
         ((FProgInc < 0) and (ProgressBar1.Position + FProgInc <= FDestPos)) then
      begin
        ProgressBar1.Position := FDestPos;
    
        Timer1.Enabled := FALSE;
      end
      else
      begin
        ProgressBar1.Position := ProgressBar1.Position + FProgInc;
      end;
    end;
    
    procedure TForm11.AnimateTo(const DestPos, Increment: Integer);
    begin
      FDestPos := DestPos;
    
      FProgInc := Increment;
    
      if FDestPos < ProgressBar1.Position then
        FProgInc := -FProgInc;
    
      Timer1.Enabled := FProgInc <> 0;
    end;
    
    end. 
    
    object Form11: TForm11
      Left = 0
      Top = 0
      BorderStyle = bsDialog
      Caption = 'Animated Progressbar'
      ClientHeight = 77
      ClientWidth = 466
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      Position = poScreenCenter
      PixelsPerInch = 96
      TextHeight = 13
      object Label1: TLabel
        Left = 309
        Top = 42
        Width = 53
        Height = 13
        Caption = 'Increment:'
      end
      object ProgressBar1: TProgressBar
        Left = 24
        Top = 16
        Width = 417
        Height = 17
        TabOrder = 0
      end
      object Button1: TButton
        Left = 24
        Top = 39
        Width = 75
        Height = 25
        Caption = '10%'
        TabOrder = 1
        OnClick = Button1Click
      end
      object Button2: TButton
        Left = 105
        Top = 39
        Width = 75
        Height = 25
        Caption = '90%'
        TabOrder = 2
        OnClick = Button2Click
      end
      object spnIncrement: TSpinEdit
        Left = 368
        Top = 39
        Width = 73
        Height = 22
        MaxValue = 100
        MinValue = 1
        TabOrder = 3
        Value = 0
      end
      object Timer1: TTimer
        Enabled = False
        Interval = 20
        OnTimer = Timer1Timer
        Left = 240
        Top = 40
      end
    end
    

    如果您有相对较新的Delphi版本, 这是一个使用
    匿名方法围绕
    TTimer
    的动画包装器

    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;
    

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

    这里是一个更完整的动画类,您可以在其中实例化任意数量的动画。扩展功能,可停止/继续,准备好后添加事件,以及更多属性

    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.
    

    如果您有相对较新的Delphi版本, 这是一个使用
    匿名方法围绕
    TTimer
    的动画包装器

    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;
    

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

    这里是一个更完整的动画类,您可以在其中实例化任意数量的动画。扩展功能,可停止/继续,准备好后添加事件,以及更多属性

    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.
    

    您是否有一组特定的对象/属性用于此操作?“动画制作”方法仅指定值?是否有一组特定的对象/属性用于此操作?Animate方法只分配值?问题是希望Animate将位置设置为一个值范围,并避免编写计时器代码。也就是说,RTTI的使用很奇怪。写:ProgressBar1.位置:=30David,你说得对,我只是在写我答案的第一个版本时还没有理解动画部分。现在我来讨论这一部分。虽然我认为如果您确实有类似jqueryanimate的东西,那么RTTI将是好的。+1为了保持它的重用性,没有必要使用TForm1.animate(只是animate)。增强功能可能是将其包装到一个线程中,并添加睡眠时间作为参数。@David yes RTTI是来帮助我们的,但遗憾的是,您失去了IDE/编译器传递属性名的帮助。我真的很想直接将属性作为var参数传递,我认为编译器可以做到这一点。在我看来,求助于RTTI似乎很奇怪。问题是希望Animate将位置设置为一个值范围,并避免编写计时器代码。也就是说,RTTI的使用很奇怪。写:ProgressBar1.Position:=30David,你说得对,我只是在写我的a的第一个版本时还没有理解动画部分