开发者

PaintTo doesn't work with my component

开发者 https://www.devze.com 2023-02-04 02:58 出处:网络
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 com

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消