1

ですから、適切なタイトルの書き方さえ知りません。

私がやりたいのは、プログレスバーの位置をアニメーション化することです。

タイマーやループなどでこれを行う方法について議論することができます。

ただし、次のようなことができるようにしたいです。

  1. ProgressBar1.Position:=Animate(ToValue); また
  2. Animate(ProgressBar1.Position, ToValue);

これは可能ですか?

整数から継承されたコンポーネントの作成は機能しませんでした。

ポインターを使用して番号2を試し、この手順を作成しました

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

プログレスバーの内部で位置の値を変更しましたが、プログレスバーは視覚的に変化しませんでした。

誰かがこれを行う方法のアイデアを持っているなら、それは素晴らしいことです.

ありがとうございました!

4

4 に答える 4

2

比較的新しいバージョンの Delphi を使用している場合、これはTTimerusingのアニメーション ラッパー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クラスは、アプリケーションの開始/停止時に自己初期化および自己破壊します。アクティブにできるアニメーション プロセスは 1 つだけです。

このように使用します:

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

コメントで説明したように、上記のコードではクラス変数とクラス関数を使用しています。欠点は、1 つのアニメーションしかアクティブにできないことです。

これはより完全なアニメーション クラスで、好きなだけアニメーションをインスタンス化できます。停止/続行の可能性、準備ができたらイベントを追加する機能、およびその他のプロパティを含む機能の拡張。

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ます。

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
); 
于 2013-03-10T14:08:05.640 に答える
1

これは RTTI で簡単に行うことができます。

ループの記述を避けることはできませんが、ループを一度記述して、設定するオブジェクト/プロパティのAnimateメソッドを呼び出すことができます。もちろん、ちらつきや 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;
于 2013-03-10T08:43:21.020 に答える
1

David が言うように、タイマーを使用する必要があります。原則を示すコードを次に示します。アイデアを取り入れて、独自の 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. 

DFM:

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
于 2013-03-10T12:35:09.283 に答える
0

プログレス バーの位置に整数以外を割り当てることはできません。したがって、位置をある値から別の値にスムーズに移動させたい場合は、位置を個々の値に設定する必要があります。

便利なショートカットはありません。jQuery の animate() メソッドのようにすぐに利用できるものはありません。あなたはタイマーとループについて言及しています。これらは、使用する必要がある方法です。

于 2013-03-10T08:43:55.793 に答える