I'm trying to write a custom draw cell method for a TDBGridEh
. The problem is when I change properties of pen, brush, ... the painting becomes messy. That's because the control does some extra painting itself after it calls the event handler. So I have to keep all props and then reset them when my own painting was finished.
I tried to create my own TControlCanvas
and assign grid's one to it, but I get a run-time exception with message:
Cannot assign a TControlCanvas to a TControlCanvas
, that indicates the AssignTo
method is not implemented for TControlCanvas
nor for its ancestors. So my questions are:
Why TControlCanvas
does not have an AssignTo
method? What is the problem?
How can I keep and restore all properties of a TControlCanvas? And by that I mean something more convenient than creating TPen
, TBrush
, TFont
, etc. .
While TCanvas
does not actually encapsulate these API functions, it is possible to use SaveDC
and RestoreDC
to do what you need. From the MSDN:
The SaveDC function saves the current state of the specified device context (DC) by copying data describing selected objects and graphic modes (such as the bitmap, brush, palette, font, pen, region, drawing mode, and mapping mode) to a context stack.
[...]
The RestoreDC function restores a device context (DC) to the specified state. The DC is restored by popping state information off a stack created by earlier calls to the SaveDC function.
A possible code sample:
uses
Winapi.Windows;
...
var
SavedDC: Integer;
begin
SavedDC := SaveDC(Canvas.Handle);
try
// Painting code
finally
RestoreDC(Canvas.Handle, SavedDC);
end;
end;
Edit:
I realized that this alone will likely not be the answer. This will handle the Device Context on the Windows side that is represented by the TCanvas
/TControlCanvas
object on Delphi's VCL side.
But it will not alter any of the TFont
, TBrush
or TPen
objects that the VCL holds. From tests it looks like that e.g. whenever Delphi uses the Canvas's Brush.GetHandle
(FillRect
, FrameRect
), it is still the changed Brush.
So the best bet is to use SaveDC
and RestoreDC
in combination with storing and restoring Pen
, Font
and Brush
like in the answer from Uwe Raabe.
Not sure if this fits what your expects, but there are TPenRecall
, TBrushRecall
and TFontRecall
to save and restore the settings of these three properties in a semi-automatic way.
The handling is pretty simple: Create an instance of these classes with the corresponding properties as the parameter and do whatever you want with Pen, Brush and Font. In the end free those instances, which will restore the settings.
In combination with a TObjectList
and some internal reference counting the effort needed to save and restore these canvas properties can be reduced to a one liner.
type
TCanvasSaver = class(TInterfacedObject)
private
FStorage: TObjectList<TRecall>;
public
constructor Create(ACanvas: TCanvas);
destructor Destroy; override;
class function SaveCanvas(ACanvas: TCanvas): IInterface;
end;
constructor TCanvasSaver.Create(ACanvas: TCanvas);
begin
inherited Create;
FStorage := TObjectList<TRecall>.Create(True);
FStorage.Add(TFontRecall.Create(ACanvas.Font));
FStorage.Add(TBrushRecall.Create(ACanvas.Brush));
FStorage.Add(TPenRecall.Create(ACanvas.Pen));
end;
destructor TCanvasSaver.Destroy;
begin
FStorage.Free;
inherited;
end;
class function TCanvasSaver.SaveCanvas(ACanvas: TCanvas): IInterface;
begin
Result := Self.Create(ACanvas);
end;
Usage:
procedure TForm274.DoYourDrawing(ACanvas: TCanvas);
begin
TCanvasSaver.SaveCanvas(ACanvas);
{ Change Pen, Brush and Font of ACanvas and do whatever you need to do.
Make sure that ACanvas is still valid and the same instance as at the entry of this method. }
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With