At the risk of sounding like a broken record, you are going about this the wrong way. A TImage
is useful for a static image – it's the wrong thing to use to show anything dynamic. What you need to do is:
- Load your image into a
TBitmap
or TPNGImage
or some such TGraphic
descendent.
- Put a
TPaintBox
onto your form.
- Run a timer that ticks at the desired refresh rate.
- From the timer call
Invalidate
or perhaps Refresh
on the paint box.
- Add an
OnPaint
handler for the paint box that paints your dynamic image.
The code looks like this:
type
TForm1 = class(TForm)
PaintBox1: TPaintBox;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
FBitmap: TBitmap;
FOpacity: Integer;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Png: TPngImage;
begin
Png := TPngImage.Create;
Try
Png.LoadFromFile('C:\desktop\YoshiMarioParty9.png');
FBitmap := TBitmap.Create;
FBitmap.Assign(Png);
Finally
Png.Free;
End;
BorderIcons := [biSystemMenu, biMinimize];
BorderStyle := bsSingle;
PaintBox1.Align := alClient;
ClientWidth := FBitmap.Width;
ClientHeight := FBitmap.Height;
Timer1.Interval := 1000 div 25; // 25Hz refresh rate
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Timer1.Enabled := False;
FBitmap.Free;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
inc(FOpacity, 5);
PaintBox1.Invalidate;
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
PaintBox1.Canvas.Brush.Color := clWhite;
PaintBox1.Canvas.Brush.Style := bsSolid;
PaintBox1.Canvas.FillRect(PaintBox1.ClientRect);
PaintBox1.Canvas.Draw(0, 0, FBitmap, FOpacity);
end;
This results in a reasonable result, but there is flicker. This can be eliminated by setting the form's DoubleBuffered
property to True
, but I'd prefer a better solution to that.
This approach to solving the flicker is to make the paint box a windowed control. The VCL TPaintBox
is a non-windowed control and so paints on its parent's window. This does tend to lead to flicker. So, here's a version with a simple paint box control derived from TCustomControl
. This variant sets everything up at run time because I've not bother registering the paint box control as a design time control, although it's perfectly simple to do so.
program PaintBoxDemo;
uses
Classes, Graphics, Controls, Forms, ExtCtrls, Diagnostics, pngimage;
type
TWindowedPaintBox = class(TCustomControl)
private
FOnPaint: TNotifyEvent;
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property Canvas;
published
property Align;
property Anchors;
property Color;
property Constraints;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property Font;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Touch;
property Visible;
property OnClick;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnEndDrag;
property OnGesture;
property OnMouseActivate;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
property OnStartDock;
property OnStartDrag;
end;
constructor TWindowedPaintBox.Create(AOwner: TComponent);
begin
inherited;
ControlStyle := ControlStyle + [csReplicatable];
Width := 105;
Height := 105;
end;
procedure TWindowedPaintBox.Paint;
begin
Canvas.Font := Font;
Canvas.Brush.Color := Color;
if csDesigning in ComponentState then
begin
Canvas.Pen.Style := psDash;
Canvas.Brush.Style := bsClear;
Canvas.Rectangle(0, 0, Width, Height);
end;
if Assigned(FOnPaint) then
FOnPaint(Self);
end;
var
Form: TForm;
PaintBox: TWindowedPaintBox;
Timer: TTimer;
Bitmap: TBitmap;
Stopwatch: TStopwatch;
type
TEventHandlers = class
class procedure TimerHandler(Sender: TObject);
class procedure PaintHandler(Sender: TObject);
end;
class procedure TEventHandlers.TimerHandler(Sender: TObject);
begin
PaintBox.Invalidate;
end;
class procedure TEventHandlers.PaintHandler(Sender: TObject);
var
t: Double;
Opacity: Integer;
begin
t := Stopwatch.ElapsedMilliseconds;
Opacity := Trunc(128.0*(1.0+Sin(t/300.0)));
PaintBox.Canvas.Brush.Color := clWhite;
PaintBox.Canvas.Brush.Style := bsSolid;
PaintBox.Canvas.FillRect(PaintBox.ClientRect);
PaintBox.Canvas.Draw(0, 0, Bitmap, Opacity);
end;
procedure BuildForm;
var
Png: TPngImage;
begin
Png := TPngImage.Create;
Try
Png.LoadFromFile('C:\desktop\YoshiMarioParty9.png');
Bitmap := TBitmap.Create;
Bitmap.Assign(Png);
Finally
Png.Free;
End;
PaintBox := TWindowedPaintBox.Create(nil);
PaintBox.Parent := Form;
PaintBox.Align := alClient;
PaintBox.DoubleBuffered := True;
PaintBox.OnPaint := TEventHandlers.PaintHandler;
Timer := TTimer.Create(nil);
Timer.Interval := 1000 div 25; // 25Hz refresh rate
Timer.Enabled := True;
Timer.OnTimer := TEventHandlers.TimerHandler;
Form.Caption := 'PaintBox Demo';
Form.BorderIcons := [biSystemMenu, biMinimize];
Form.BorderStyle := bsSingle;
Form.ClientWidth := Bitmap.Width;
Form.ClientHeight := Bitmap.Height;
Form.Position := poScreenCenter;
Stopwatch := TStopwatch.StartNew;
end;
procedure TidyUp;
begin
Timer.Free;
PaintBox.Free;
Bitmap.Free;
end;
begin
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm, Form);
BuildForm;
Application.Run;
TidyUp;
end.
This is a GUI program contained in a single file, which is obviously not the way to write production code. I just do it like this here to make it possible for you to paste the code into a .dpr file verbatim and so prove to yourself that this approach works.
Fade an image using GDI+ (i.e. Change only the Alpha channel of a TGPGraphic)
. – LU RDCanvas.Draw
don't you? I'm not discarding it. I'm just asking you. About the diference I know. But I'm trying to "abstract" (don't know if it is the better word) it to my user. He doesn't need to know about, specially, these things. @LU This routine is not applicable to PNGImage, is it? – GuillOnPaint
event and the timer alters state and calls paintbox.invalidate. – LU RD