Do not use "invalidate" in the paint handler. Invalidating causes the WM_PAINT to be sent, which, of course, starts the paint processing. Even if you do not move the mouse, the sample code you sent will raise the OnPaint event to fire again and again. Since your drawing depends on the position of the cursor, the OnMouseMove event is used for this. But you also need to intercept mouse messages for other controls using windows. The sample below uses the ApplicationEvents component for this reason. If your application will have more than one form, you need to establish a mechanism to distinguish which form you draw on.
Also see in the docs that VCL Invalidate invalidates the entire window. You do not need to do this, you draw a tiny rectangle, and you know exactly where you are drawing. Just invalid where you draw and where you painted.
As for drawing controls, part of the drawing is actually simple, but you cannot do this with the canvas provided. The forms received WS_CLIPCHILDREN , the surfaces of child windows will be excluded from the update area, so you will need to use GetDCEx or GetWindowDC . Since the βuser205376β mentioned in the comments, erasing what you painted is a bit more complicated, since you can actually draw one rectangle on more than one control. But api also has a shortcut for this, as you will see in the code.
I tried to comment a bit on the code to be able to follow, but skipped error handling. The actual picture may be in the OnPaint event handler, but controls that do not go down from the "TWinControl" are painted after the handler. So this is in the WM_PAINT handler.
type TForm1 = class(TForm) [..] ApplicationEvents1: TApplicationEvents; procedure FormCreate(Sender: TObject); procedure ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean); private FMousePt, FOldPt: TPoint; procedure WM_PAINT(var Msg: TWmPaint); message WM_PAINT; public end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin
source share