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

Delphi 如何保留TControlCanvas的所有属性并在以后恢复它们?,delphi,graphics,tcanvas,Delphi,Graphics,Tcanvas,我正在尝试编写一个自定义的绘制单元格方法。问题是,当我更改笔、画笔等的属性时。。。这幅画变得凌乱不堪。这是因为控件在调用事件处理程序后会自己进行一些额外的绘制。所以我必须保留所有道具,然后在我自己的画完成后重置它们 我试图创建我自己的TControlCanvas并将网格的一个分配给它,但我得到一个运行时异常消息: 无法将TControlCanvas分配给TControlCanvas ,表示未为TControlCanvas或其祖先实现AssignTo方法。因此,我的问题是: 为什么TControl

我正在尝试编写一个自定义的绘制单元格方法。问题是,当我更改笔、画笔等的属性时。。。这幅画变得凌乱不堪。这是因为控件在调用事件处理程序后会自己进行一些额外的绘制。所以我必须保留所有道具,然后在我自己的画完成后重置它们

我试图创建我自己的
TControlCanvas
并将网格的一个分配给它,但我得到一个运行时异常消息:

无法将TControlCanvas分配给TControlCanvas

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

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

  • 如何保留和恢复TControlCanvas的所有属性?我指的是比创建
    TPen
    TBrush
    TFont
    等更方便的东西


  • 不确定这是否符合您的期望,但有
    TPenRecall
    TBrushRecall
    tfontecall
    以半自动方式保存和恢复这三个属性的设置

    处理非常简单:创建这些类的一个实例,并将相应的属性作为参数,然后使用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;
    

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

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

    [……]

    此函数用于将设备上下文(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持有的任何
    TFont
    TBrush
    TPen
    对象。从测试来看,它看起来是这样的,例如,每当Delphi使用画布的
    画笔.GetHandle
    FillRect
    FrameRect
    )时,它仍然是更改过的画笔


    因此,最好的办法是将
    SaveDC
    RestoreDC
    与存储和恢复
    Pen
    Font
    Brush
    结合使用,就像Uwe Raabe的回答一样

    Graphics.pas
    SaveDC
    /
    RestoreDC
    中,在
    Windows.pas
    中有
    TFontRecall
    及其同级。Tnx,它解决了所有刷子问题。但是我的钢笔还是有一些问题。最后,我使用了
    TRecall
    substands.Hm,您在绘制时是否仍在创建一个新的临时
    TControlCanvas
    ?调用
    Canvas.Refresh时笔问题是否消失
    RestoreDC
    之后?是<代码>刷新
    修复了它。问题是什么?@saa是一篇试图解释刷新的文章。虽然我对用法和解释都不太确信,
    tcavassaver.Create(ACanvas)因电弧而产生的线路工作?在D2007中,不调用析构函数。而且,
    是继承的行没有编译-它必须是
    Create继承的在D2007中。@UliGerhardt,谢谢你的提示!似乎我的剪贴板上有一个过时的代码版本。TCanvasSaver.SaveCanvas返回一个接口,该接口隐式保持,直到方法结束。
    
    uses
      Winapi.Windows;
    ...
    var
      SavedDC: Integer;
    begin
      SavedDC := SaveDC(Canvas.Handle);
      try
       // Painting code
      finally
        RestoreDC(Canvas.Handle, SavedDC);
      end;
    end;