Search code examples
delphivcl

Delphi button transitions using VCL


Is there any way to do a transition (for example, a red button turning green when you click it) using Delphi with VCL? Something similar to CSS transitions...


Solution

  • This is the fruit of a quick research I made

    • First you will need TAnimateEasing from this sourceForge repository.
    • This Answer written in java about how to go from one color to another.
    • This Answer (mine) about a custom TSpeedButton.

    And you combine all these to have this

    enter image description here

    and as you can see my translation of the java answer is not that good but that would be a different question. You asked how would you transition in a button and this is your answer

    unit NCRSpeedButton;
    
    interface
    
    uses
      Winapi.Windows, Vcl.Controls, Winapi.Messages, Vcl.Graphics, System.Classes, AnimateEasing;
    
    type
      TButtonState = (bs_Down, bs_Normal, bs_Active);
    
      TNCRSpeedButton = class(TGraphicControl)
      private
        FEasingAnimation: TAnimateEasing;
        FColor: TColor;
        FFromColor : TColor;
        FToColor : TColor;
        FBorderColor: TColor;
        procedure CMMouseDown(var Message: TMessage); message WM_LBUTTONDOWN;
        procedure CMMouseUp(var Message: TMessage); message WM_LBUTTONUP;
        procedure SetBorderColor(aBorderColor: TColor);
        procedure SetFromColor(const Value: TColor);
        procedure SetToColor(const Value: TColor);
        procedure AnimateTickEvent(Sender: TObject; Value: Extended);
        procedure ANotifyEvent(Sender: TObject);
      protected
        procedure Paint; override;
      public
        Constructor Create(Owner: TComponent); override;
        Destructor Destroy; override;
      published
        property FromColor: TColor read FFromColor write SetFromColor;
        property ToColor: TColor read FToColor write SetToColor;
        property BorderColor: TColor read FBorderColor write SetBorderColor;
        property ParentShowHint;
        property ParentBiDiMode;
        property PopupMenu;
        property ShowHint;
        property Visible;
        property OnClick;
        property OnDblClick;
        property OnMouseActivate;
        property OnMouseDown;
        property OnMouseEnter;
        property OnMouseLeave;
        property OnMouseMove;
        property OnMouseUp;
      end;
    
    
    implementation
     Uses
      System.Math,
      System.UITypes;
    
    
    { TNCRSpeedButton }
    
    Constructor TNCRSpeedButton.Create(Owner: TComponent);
    begin
      inherited Create(Owner);
      FColor := clBtnFace;
      FBorderColor := clBlue;
      SetBounds(0, 0, 200, 50);
      FEasingAnimation := TAnimateEasing.Create;
      FEasingAnimation.OnTick := AnimateTickEvent;
      FEasingAnimation.OnFinish := ANotifyEvent;
    end;
    
    Destructor TNCRSpeedButton.Destroy;
    begin
      FEasingAnimation.Free;
      inherited;
    end;
    
    procedure TNCRSpeedButton.Paint;
    begin
    
      Canvas.Brush.Color := FColor;
      Canvas.FillRect(ClientRect);
    
      // Drawing Borders
    
      Canvas.Pen.Color := FBorderColor;
      Canvas.MoveTo(0, 0);
      Canvas.LineTo(Width-1, 0);
      Canvas.LineTo(Width-1, Height-1);
      Canvas.LineTo(0, Height-1);
      Canvas.LineTo(0, 0);
    
    end;
    
    procedure TNCRSpeedButton.AnimateTickEvent(Sender: TObject; Value: Extended);
    var
      Ratio: Integer;
    begin
      Ratio := 1 - Floor(Value);
    
      TColorRec(FColor).R := Floor((Ratio  * TColorRec(FToColor).R) + ((1 - Ratio) * TColorRec(FFromColor).R));
      TColorRec(FColor).G := Floor((Ratio  * TColorRec(FToColor).G) + ((1 - Ratio) * TColorRec(FFromColor).G));
      TColorRec(FColor).B := Floor((Ratio  * TColorRec(FToColor).B) + ((1 - Ratio) * TColorRec(FFromColor).B));
    
      Invalidate;
    end;
    
    procedure TNCRSpeedButton.ANotifyEvent(Sender: TObject);
    begin
      FColor := FToColor;
      Invalidate;
    end;
    
    procedure TNCRSpeedButton.CMMouseDown(var Message: TMessage);
    begin
      inherited;
      Invalidate;
    end;
    
    procedure TNCRSpeedButton.CMMouseUp(var Message: TMessage);
    begin
      inherited;
      Invalidate;
      FColor := FFromColor;
    
      FEasingAnimation.Animating(0, 500, 2000, TEasingType.etBackEaseIn);
    end;
    
    procedure TNCRSpeedButton.SetBorderColor(aBorderColor: TColor);
    begin
      FBorderColor := aBorderColor;
      Invalidate;
    end;
    
    procedure TNCRSpeedButton.SetFromColor(const Value: TColor);
    begin
      FColor := Value;
      FFromColor  := Value;
      Invalidate;
    end;
    
    procedure TNCRSpeedButton.SetToColor(const Value: TColor);
    begin
      FToColor := Value;
      Invalidate;
    end;
    
    end. 
    

    I will leave how you solve the black color in the transition to you :).