Hi all
I made a new component derived from TWinControl
.
I put it on a TPanel
and I tried to call the PaintTo
procedure of the panel. The result is the panel and its caption and m开发者_如何转开发y component is not painted on the canvas at all. What should I do about this?
a part of the source (as dear David asked):
Procedure TApListBox.Paint;
var
C: TCanvas;
B: TBitmap;
ItemClient: TPoint;
Begin
Try
If (FUpdating > 0) Then
Exit;
Try
BeginUpdate;
B := TBitmap.Create;
B.Width := Width;
B.Height := Height;
With B.Canvas Do Begin
Lock;
// Begin :
ItemClient := Point(IVisPanel + 3, 2);
// Draw Items
PaintItems(B.Canvas, ItemClient);
Unlock;
End;
C := TCanvas.Create;
C.Handle := GetWindowDC(Self.Handle);
C.Lock;
inherited;
C.Draw(1, 1, B);
If (RenameEdit.Visible) Then
RenameEdit.Repaint;
Finally
C.Unlock;
ReleaseDC(0, C.Handle);
C.Free;
B.Free;
Dec(FUpdating);
End;
Except
End;
End;
You really shouldn't ever need to call or override PaintTo.
Instead, you should do 100% of your painting in an overridden Paint method. Painting can happen at any time, and a component needs to be able to paint itself on demand. The way that happens is Windows sends a WM_PAINT message which the VCL translates into a call to your component's Paint method.
So make sure your component can paint what it needs to at any time, and do all of your painting in the overridden Paint Method.
In your method handling the WM_PAINT message, you can NOT use the Canvas directly, because WM_PAINT specify a GDI handle (HDC) in the Message.DC parameter.
Take a look, for example, at this code snippet from TGraphicControl, which handle it as expected:
procedure TGraphicControl.WMPaint(var Message: TWMPaint);
begin
if Message.DC <> 0 then
begin
Canvas.Lock;
try
Canvas.Handle := Message.DC;
try
Paint; // this is where the painting is done, using a "locked" Canvas
finally
Canvas.Handle := 0;
end;
finally
Canvas.Unlock;
end;
end;
end;
So check your WM_PAINT implementation method, and follow this code scheme.
Instead of the "Paint" method above, put your own drawing code using the Canvas property.
The "PaintTo" method will work as expected.
Another possibility is to use direct Windows API drawings, using the Message.DC handle... but I guess the above method, allowing the use of a regular Canvas, is more easy for most of us! ;)
In all cases, WM_PAINT shouldn't be the place where Delphi components implement the painting, but only an overridden Paint method. So let your component inherits from TGraphicControl, and put all the drawing code into an overridden Paint method.
Your base class should be TCustomControl
, not TWinControl
. The former sets up the control's canvas so you can paint to it properly by overriding Paint
.
If you insist on handling wm_Paint
yourself, make sure you use the WParam
parameter as the display context, if it's provided. Formally, that parameter is unused, but the VCL (and some common controls) use that for the DC, which makes implementing the wm_PrintClient
message easier.
精彩评论