如何保留TControlCanvas的所有属性并在以后恢复它们?

时间:2018-03-27 07:46:01

标签: delphi graphics tcanvas

我正在尝试为TDBGridEh编写自定义绘制单元格方法。问题是当我改变钢笔,画笔的属性时...画面变得混乱。那是因为控件在调用事件处理程序后会执行一些额外的绘制。因此,我必须保留所有道具,然后在我自己的绘画完成后重置它们。

我尝试创建自己的TControlCanvas并为其分配网格,但是我收到了一条带有消息的运行时异常:

  

无法将TControlCanvas分配给TControlCanvas

,表示AssignTo或其祖先未实现TControlCanvas方法。所以我的问题是:

  1. 为什么TControlCanvas没有AssignTo方法?有什么问题?

  2. 如何保留和恢复TControlCanvas的所有属性?我认为这比创建TPenTBrushTFont等更方便。

2 个答案:

答案 0 :(得分:6)

虽然TCanvas实际上并未封装这些API函数,但可以使用SaveDCRestoreDC来执行您需要的操作。来自MSDN:

  

SaveDC函数通过复制描述所选对象的数据来保存指定设备上下文(DC)的当前状态   图形模式(如位图,画笔,调色板,字体,笔,区域,   绘制模式和映射模式)到上下文堆栈。

[...]

  

RestoreDC函数将设备上下文(DC)恢复为   指定的状态。通过弹出状态信息来恢复DC   早先调用SaveDC函数创建的堆栈。

可能的代码示例:

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所拥有的任何TFontTBrushTPen个对象。从测试来看,它看起来像是每当Delphi使用Canvas的Brush.GetHandleFillRectFrameRect)时,它仍然是更改的Brush。

因此,最好的办法是将SaveDCRestoreDC与存储和恢复PenFontBrush结合使用,如同Uwe的回答一样拉贝。

答案 1 :(得分:5)

不确定这是否符合您的预期,但有TPenRecallTBrushRecallTFontRecall以半自动方式保存和恢复这三个属性的设置。< / p>

处理非常简单:使用相应的属性作为参数创建这些类的实例,并使用 Pen Brush Font执行任何操作。最后释放那些将恢复设置的实例。

结合TObjectList和一些内部引用计数,保存和恢复这些画布属性所需的工作量可以减少到一行。

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;