0

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...

nick
  • 2,819
  • 5
  • 33
  • 69

2 Answers2

3

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 :).

Nasreddine Galfout
  • 2,550
  • 2
  • 18
  • 36
2

The standard TButton does not support what you are asking for. It gets its coloring from the OS by default, not the VCL.

You need an owner-drawn button in order to change coloring, like TBitBtn or TSpeedBtn, otherwise you can subclass TButton to manually enable the BS_OWNERDRAW window style and handle the WM_DRAWITEM notification. Or use a 3rd party skinning framework. Or use VCL Styles if your IDE supports them.

Either way, once you have a button that can change color, you can simply use a TTimer to animate the shifting of one color into another as needed.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770