Here is a solution from simplifying and adapting my component TFPCustomCanvasBridge ..and using the "buffer" technique....
unit FPCustomCanvasBridge;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, FPImage,
FPCanvas, FPImgCanv, fpreadpng;
(*
From: http://wiki.freepascal.org/Developing_with_Graphics
"You can draw images which won't be displayed in the screen without the LCL, by just using fcl-image directly.
For example a program running on a webserver without X11 could benefit from not having a visual library
as a dependency.
FPImage (alias fcl-image) is a very generic image and drawing library written completely in pascal.
In fact the LCL uses FPImage too for all the loading and saving from/to files and implements the
drawing function through calls to the widgetset (winapi, gtk, carbon, ...).
Fcl-image on the other hand also has drawing routines.
For more information, please read the article about fcl-image" (http://wiki.freepascal.org/fcl-image).
*)
type
TFPCustomCanvasBridge = class
{ Private declarations }
private
FImgMem: TFPCustomImage;
FReaderPNG: TFPCustomImageReader;
protected
{ Protected declarations }
public
{ Public declarations }
Canvas: TFPCustomCanvas;
procedure CopyToCanvas(ShiftX,ShiftY: integer; ACanvas: TFPCustomCanvas);
procedure CopyFromCanvas(ACanvas: TFPCustomCanvas);
constructor Create(W, H: integer; backgroundImageFile: string);
destructor Destroy; override;
end;
implementation
constructor TFPCustomCanvasBridge.Create(W, H: integer; backgroundImageFile: string);
begin
FReaderPNG:= TFPReaderPNG.Create;
FImgMem:= TFPMemoryImage.Create(W,H);
FImgMem.UsePalette:= False;
if backgroundImageFile <> '' then //TODO... "Sanity" code here!!!
FImgMem.LoadFromFile(backgroundImageFile, FReaderPNG);
Canvas := TFPImageCanvas.Create(FImgMem);
if backgroundImageFile = '' then Canvas.Rectangle(0,0,W,H);
end;
destructor TFPCustomCanvasBridge.Destroy;
begin
Canvas.Free;
FImgMem.Free;
FReaderPNG.Free;
inherited Destroy;
end;
procedure TFPCustomCanvasBridge.CopyToCanvas(ShiftX,ShiftY: integer; ACanvas: TFPCustomCanvas);
begin
ACanvas.CopyRect(ShiftX, ShiftY,Canvas, Rect(0,0,Canvas.Width,Canvas.Height));
end;
procedure TFPCustomCanvasBridge.CopyFromCanvas(ACanvas: TFPCustomCanvas);
begin
Canvas.CopyRect(0,0,ACanvas,Rect(0,0,ACanvas.Width,ACanvas.Height));
end;
end.
App Form code:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, FPImage, FPCustomCanvasBridge;
type
{ TForm1 }
TForm1 = class(TForm)
PaintBox1: TPaintBox;
Panel1: TPanel;
Panel2: TPanel;
StatusBar1: TStatusBar;
TrackBar1: TTrackBar;
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
private
{ private declarations }
MainCanvas: TFPCustomCanvasBridge;
BackupCanvas: TFPCustomCanvasBridge;
DraftCanvas: TFPCustomCanvasBridge;
InDrawingMode: boolean;
pX: integer;
pY: integer;
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
//create canvas objects
MainCanvas:= TFPCustomCanvasBridge.Create(PaintBox1.Width, PaintBox1.Height, 'VU_Meter01.png'); //Main canvas...
BackupCanvas:= TFPCustomCanvasBridge.Create(PaintBox1.Width, PaintBox1.Height, ''); //Backup Canvas..
DraftCanvas:= TFPCustomCanvasBridge.Create(PaintBox1.Width, PaintBox1.Height, ''); //Draft Canvas..
//inits....
PY:= 20;
BackupCanvas.CopyFromCanvas(MainCanvas.Canvas);
DraftCanvas.Canvas.Pen.Width:= 3;
DraftCanvas.Canvas.Pen.FPColor:= colLime;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
InDrawingMode:= True;
end;
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if InDrawingMode then
begin
DraftCanvas.CopyFromCanvas(BackupCanvas.Canvas);//copy backup...
if TrackBar1.Position = 0 {Min} then PX:= 5
else if TrackBar1.Position = TrackBar1.Max {20} then PX:= PaintBox1.Width-5
else pX:= Round(TrackBar1.Position*(PaintBox1.Width-10)/TrackBar1.Max);
//dinamyc draw on draft canvas...
DraftCanvas.Canvas.Line(Round(PaintBox1.Width/2),PaintBox1.Height, PX, PY);
//No flick.... updade Main Canvas
MainCanvas.CopyFromCanvas(DraftCanvas.Canvas);
PaintBox1.Invalidate; //call PaintBoxPaint..
end;
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
if InDrawingMode then
MainCanvas.CopyToCanvas(0,0,PaintBox1.Canvas);
end;
end.
Follows attached the complete project ...
Greetings...