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...
-
just curios Do you know about easing functions? – Nasreddine Galfout Apr 17 '19 at 15:35
-
If you say yes then that is your answer. :) – Nasreddine Galfout Apr 17 '19 at 15:36
-
@NasreddineGalfout yes, I'm new to Delphi, is there any way I can use an animation loop? I can take it from there :P – nick Apr 17 '19 at 15:40
-
Then you will be interested in [this article](https://www.codeproject.com/articles/827808/control-animation-in-winforms) from codeProject c#, It is basically the same idea – Nasreddine Galfout Apr 17 '19 at 15:41
-
That's using C# though, I can't seem to find any form of animation loop for Delphi :/ – nick Apr 17 '19 at 15:45
2 Answers
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
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 :).

- 2,550
- 2
- 18
- 36
-
-
1@nick I hope this gives you some insight about how you could've done it, otherwise translating that C# project is another way to go. – Nasreddine Galfout Apr 17 '19 at 17:24
-
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.

- 555,201
- 31
- 458
- 770