I can duplicate your problem if I do not place any control over the test frame (this is also probably the reason why none of us can duplicate your problem - fi drop the control to visually verify that the frame is in shape).
The reason PaintHandler
not called when there are no controls on it, and the reason when it is called when DoubleBuffered
installed, although there are no controls on it, is just like the WM_PAINT
TWinControl
message TWinControl
:
procedure TWinControl.WMPaint(var Message: TWMPaint); var .. begin if not FDoubleBuffered or (Message.DC <> 0) then begin if not (csCustomPaint in ControlState) and (ControlCount = 0) then inherited else PaintHandler(Message); end else begin ..
As you can see, when DoubleBuffered
not installed and when there are no controls, PaintHandler
not called (because there is nothing to draw: we are not a custom drawing (there is no csCustomPaint flag), and there are no controls to display). When the DoubleBuffered
parameter is set, the following code path is WMPrintClient
that calls WMPrintClient
, which in turn calls PaintHandler
.
If you intend to use the frame without any controls (although this is unlikely), the fix is obvious (also reasonable when you know it), from the code snippet: include csCustomPaint
in ControlState
:
type TMyFrame = class(TFrame) .. protected procedure WMPaint(var Message: TWMPaint); message WM_PAINT; .. procedure TMyFrame.WMPaint(var Message: TWMPaint); begin ControlState := ControlState + [csCustomPaint]; inherited; ControlState := ControlState - [csCustomPaint]; end;
then the WM_PAINT
inherited handler will call PaintHandler
.
As for why drawing using
BeginPaint
/
EndPaint
in the
WM_PAINT
message handler doesn't seem to work, the reason is that the
inherited
call that precedes your drawing checks the update area. Check your
rcPaint
member
PAINTSTRUCT
after calling
BeginPaint
, you will find it (0, 0, 0, 0).
Since there is no invalidation area in this case, the OS simply ignores the following drawing calls. You can verify this by not paying attention to the client frame rectangle before drawing on the canvas:
procedure TMyFrame.WMPaint(var Message: TWMPaint); var PS: PAINTSTRUCT; begin inherited; InvalidateRect(Handle, nil, False); // <- here FCanvas.Handle := BeginPaint(Handle, PS); FCanvas.Pen.Width := 3; FCanvas.Pen.Color := clRed; FCanvas.MoveTo(0, 0); FCanvas.LineTo(ClientWidth, ClientHeight); FCanvas.Pen.Color := clGreen; FCanvas.MoveTo(ClientWidth, 0); FCanvas.LineTo(0, ClientHeight); EndPaint(Handle, PS); end;
and now you will see that your drawing takes effect. Of course, you can refuse to call inherited
or invalidate only the part you draw on.