Delphi / GDI +: When is a device context created or destroyed?

Normally, using GDI + in Delphi, you can use TPaintBox and draw during the OnPaint event :

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
   g: TGPGraphics;
begin
   g := TGPGraphics.Create(PaintBox1.Canvas.Handle);
   try
      g.DrawImage(FSomeImage, 0, 0);
   finally
      g.Free;
   end;
end;

The problem with this paradigm is that creating a destructive Graphics object is wasteful and poorly executed each time. In addition, there are several availabe constructs in GDI + that you can only use if you have a permanent Graphics object .

The problem, of course, is when can I create a Graphics object ? I need to know when the pen becomes available, and then when it is no longer valid. I need this information, so I can create and destroy a Graphics object .


Solution Attempt NΒΊ1

I can solve the creation problem by creating it when it is really necessary - the drawing cycle is called for the first time:

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
   if FGraphics = nil then
      FGraphics := TGPGraphics.Create(PaintBox1.Canvas.Handle);

   FGraphics.DrawImage(FSomeImage, 0, 0);
end;

But I have to know when the device context is no longer valid, so I can destroy the FGraphcis object so that it is created again the next time. If for any reason the TPaintBox device context is recreated, I will refer to the invalid device context the next time OnPaint is called .

Delphi , , , < TPaintBox?

+2
4

TPaintBox, TPaintBox Canvas TControlCanvas, , , :

TControlCanvas = class(TCanvas)
private
  ...
  procedure SetControl(AControl: TControl);
protected
  procedure CreateHandle; override;
public
  procedure FreeHandle;
  ...
  property Control: TControl read FControl write SetControl;
end;

, FreeHandle SetControl .

: TControlCanvas:

 constructor TGraphicControl.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
   FCanvas := TControlCanvas.Create;
   TControlCanvas(FCanvas).Control := Self;
 end;

, , TMyControlCanvas, , TMyPaintBox, Canvas :

 constructor TMyPaintBox.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
   FCanvas.Free;
   FCanvas := TMyControlCanvas.Create;
   TMyControlCanvas(FCanvas).Control := Self;
 end;

TMyControlCanvas TGPGraphics.

.

-

+3

. CreateHandle TControlCanvas Jeroen. .

, , TGpGraphics , , , , .

if not Assigned(FGraphics)
    or (FGraphics.GetHDC <> PaintBox1.Canvas.Handle) then begin
  FGraphics.Free;
  FGraphics := TGpGraphics.Create(PaintBox1.Canvas.Handle);
end;

, , ; , , HDC , , - OS- OS.


TCanvas Handle, , , . TControlCanvas Handle, Control , TControlCanvas . TControlCanvas , CanvasList. , DC ( TControlCanvas.CreateHandle), FreeDeviceContext, canvas . ( ) FreeHandle. 4 (. CanvasListCacheSize), , TCustomControl TGraphicControl , , , .

TControlCanvas.FreeHandle , . , VCL , .


, , , TGpGraphics. , DC, . . TPaintBox.WindowProc wm_Destroy. , DestroyWnd.

+2

, / , . gdi + drawing . , imo, , , . , , DC ( ).

If you need to cache bitmaps, what you can consider is to create a bitmap that you want to cache using GDI + (make it the right size and any anti-alias settings), saving it to tmemorystream, and then when you need to load it from the stream and draw it using a good bit bit. It will be much faster than using Graphics.DrawImage. I speak much faster.

+1
source
procedure TGraphicControl.WMPaint(var Message: TWMPaint);
begin
  if Message.DC <> 0 then
  begin
    Canvas.Lock;
    try
      Canvas.Handle := Message.DC;
      try
        Paint;
      finally
        Canvas.Handle := 0;
      end;
    finally
      Canvas.Unlock;
    end;
  end;
end;

Canvas.Handle := Message.DC;
-3
source

All Articles