如何保留 TControlCanvas 的所有属性并在以后恢复它们?
How can I keep all properties of a TControlCanvas and restore them later?
我正在尝试为 TDBGridEh
编写自定义绘制单元格方法。问题是当我改变钢笔、画笔的属性时,……绘画变得凌乱。这是因为控件在调用事件处理程序后会自行进行一些额外的绘制。所以我必须保留所有道具,然后在我自己的画完成后重新设置它们。
我试图创建自己的 TControlCanvas
并将网格的一个分配给它,但我收到 运行 次异常消息:
Cannot assign a TControlCanvas to a TControlCanvas
,表示 AssignTo
方法没有为 TControlCanvas
实现,也没有为它的祖先实现。所以我的问题是:
为什么 TControlCanvas
没有 AssignTo
方法?有什么问题吗?
如何保留和恢复 TControlCanvas 的所有属性?我的意思是比创建 TPen
、TBrush
、TFont
等更方便。
不确定这是否符合您的预期,但是有 TPenRecall
、TBrushRecall
和 TFontRecall
可以在 [=30= 中保存和恢复这三个属性的设置] 方式。
处理非常简单:使用相应的属性作为参数创建这些 类 的实例,然后用 Pen、[=24= 做任何你想做的事]画笔和字体。最后释放那些实例,这将恢复设置。
结合 TObjectList
和一些内部引用计数,可以将保存和恢复这些 canvas 属性所需的工作量减少到一行。
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;
用法:
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;
虽然TCanvas
实际上并没有封装这些API函数,但是可以使用SaveDC
和RestoreDC
来做你需要的。来自 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.
可能的代码示例:
uses
Winapi.Windows;
...
var
SavedDC: Integer;
begin
SavedDC := SaveDC(Canvas.Handle);
try
// Painting code
finally
RestoreDC(Canvas.Handle, SavedDC);
end;
end;
编辑:
我意识到仅此一项可能不是答案。这将处理 Windows 端的设备上下文,它由 Delphi 的 VCL 端的 TCanvas
/TControlCanvas
对象表示。
但它不会改变 VCL 持有的任何 TFont
、TBrush
或 TPen
对象。从测试看来,例如每当Delphi使用Canvas的Brush.GetHandle
(FillRect
、FrameRect
)时,它仍然是改变后的画笔。
所以最好的办法是将 SaveDC
和 RestoreDC
与存储和恢复 Pen
、Font
和 Brush
结合使用,就像答案中一样来自 Uwe Raabe。
我正在尝试为 TDBGridEh
编写自定义绘制单元格方法。问题是当我改变钢笔、画笔的属性时,……绘画变得凌乱。这是因为控件在调用事件处理程序后会自行进行一些额外的绘制。所以我必须保留所有道具,然后在我自己的画完成后重新设置它们。
我试图创建自己的 TControlCanvas
并将网格的一个分配给它,但我收到 运行 次异常消息:
Cannot assign a TControlCanvas to a TControlCanvas
,表示 AssignTo
方法没有为 TControlCanvas
实现,也没有为它的祖先实现。所以我的问题是:
为什么
TControlCanvas
没有AssignTo
方法?有什么问题吗?如何保留和恢复 TControlCanvas 的所有属性?我的意思是比创建
TPen
、TBrush
、TFont
等更方便。
不确定这是否符合您的预期,但是有 TPenRecall
、TBrushRecall
和 TFontRecall
可以在 [=30= 中保存和恢复这三个属性的设置] 方式。
处理非常简单:使用相应的属性作为参数创建这些 类 的实例,然后用 Pen、[=24= 做任何你想做的事]画笔和字体。最后释放那些实例,这将恢复设置。
结合 TObjectList
和一些内部引用计数,可以将保存和恢复这些 canvas 属性所需的工作量减少到一行。
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;
用法:
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;
虽然TCanvas
实际上并没有封装这些API函数,但是可以使用SaveDC
和RestoreDC
来做你需要的。来自 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.
可能的代码示例:
uses
Winapi.Windows;
...
var
SavedDC: Integer;
begin
SavedDC := SaveDC(Canvas.Handle);
try
// Painting code
finally
RestoreDC(Canvas.Handle, SavedDC);
end;
end;
编辑:
我意识到仅此一项可能不是答案。这将处理 Windows 端的设备上下文,它由 Delphi 的 VCL 端的 TCanvas
/TControlCanvas
对象表示。
但它不会改变 VCL 持有的任何 TFont
、TBrush
或 TPen
对象。从测试看来,例如每当Delphi使用Canvas的Brush.GetHandle
(FillRect
、FrameRect
)时,它仍然是改变后的画笔。
所以最好的办法是将 SaveDC
和 RestoreDC
与存储和恢复 Pen
、Font
和 Brush
结合使用,就像答案中一样来自 Uwe Raabe。