首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确传递带有变量前缀的对象类型参数?

如何正确传递带有变量前缀的对象类型参数?
EN

Stack Overflow用户
提问于 2011-03-06 19:30:58
回答 1查看 1.4K关注 0票数 2

Summarization:

代码语言:javascript
复制
type 
  MyObject = object
  end;

  MyRecord = record
  end;

  MyClass = class
  end;

  procedure ProcA(aMyObject: MyObject);
  procedure ProcB(var aMyObject: MyObject);
  procedure ProcC(aMyRecord: MyRecord);
  procedure ProcD(var aMyRecord: MyRecord);
  procedure ProcE(aMyClass: MyOClass);
  procedure ProcF(var aMyClass: MyClass);

  1. MyObjectMyRecord是值类型,而MyClass是引用类型。值类型变量的
  2. 赋值将复制变量;引用类型变量的赋值将复制引用。

  1. ProcAProcC中的参数是原始参数的副本。

  1. ProcBProcD中的参数是原始的。
  2. ProcE中的参数是原始引用的副本。

  1. ProcF中的参数是原始引用。
  2. 关于如何结束在单元agg_2D.pas中声明的Agg2D对象来绘制,请参见下面的答案。

===========================================

我正在学习使用AggPas,这是一个纯pascal矢量图形绘制API.具体来说,使用单元agg_2D.pas,它包含Agg2D对象,而不是单元Agg2D.pas,后者包含TAgg2D类。选择单元agg_2D.pas而不是单元Agg2D.pas的原因在于跨平台能力。

但是,我无法正确地传递带有var前缀的Agg2D对象类型的参数。如下面的代码所示,我希望将TForm1创建的TForm1对象传递给另一个实际负责绘制形状的类。但是,它不起作用。你能帮我评论一下可能的原因吗?看来我一定错过了关于对象类型的重要概念。任何建议都是非常感谢的!您可以新建一个VCL应用程序,附加FormCreate处理程序,并逐行注释绘图代码以查看效果。

代码语言:javascript
复制
    unit Unit1;

    interface

    uses
      agg_2D,
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;

    type
      TRenderEngine_BMP = class;
      TRenderEngine_Agg = class;
      TForm1 = class;

      TRenderEngine_BMP = class
      private
        fBMP: TBitmap;
      public
        constructor Create(var aBMP: TBitmap);
        procedure DrawEllipse;
      end;

      TRenderEngine_Agg = class
      private
        fVG: Agg2D;
      public
        constructor Create(var aVG: Agg2D);
        procedure DrawEllipse;
      end;

      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }

        fBMP: TBitmap;
        fVG: Agg2D;
        fEngine_BMP: TRenderEngine_BMP;
        fEngine_Agg: TRenderEngine_Agg;

        procedure AttachBMP(var aVG: Agg2D; var aBMP: TBitmap);
        procedure OnSceneResize(Sender: TObject);
        procedure OnScenePaint(Sender: TObject);
      public
        { Public declarations }
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.dfm}

    uses
      Math;

    { TRenderEngine_BMP }

    constructor TRenderEngine_BMP.Create(var aBMP: TBitmap);
    begin
      Self.fBMP := aBMP;
    end;

    procedure TRenderEngine_BMP.DrawEllipse;
    begin
      Self.fBMP.Canvas.ellipse(20, 20, 80, 80);
    end;

    { TRenderEngine_Agg }

    constructor TRenderEngine_Agg.Create(var aVG: Agg2D);
    begin
      Self.fVG := aVG;
    end;

    procedure TRenderEngine_Agg.DrawEllipse;
    begin
      Self.fVG.ellipse(50, 50, 30, 30);
    end;

    { TForm1 }

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Self.OnResize := {$IFDEF FPC} @ {$ENDIF} OnSceneResize;
      Self.OnPaint := {$IFDEF FPC} @ {$ENDIF} OnScenePaint;

      fBMP := TBitmap.Create;
      fBMP.PixelFormat := pf32bit;
      fBMP.Canvas.Brush.Style := bsSolid;
      fBMP.Canvas.Brush.Color := clBlue;
      fBMP.Width := ClientWidth;
      fBMP.Height := ClientHeight;

      fVG.Construct;
      Self.AttachBMP(fVG, fBMP);

      fEngine_BMP := TRenderEngine_BMP.Create(fBMP);
      fEngine_Agg := TRenderEngine_Agg.Create(fVG);
    end;

    procedure TForm1.AttachBMP(var aVG: Agg2D; var aBMP: TBitmap);
    var
      tmpBuffer: pointer;
      tmpStride: integer;
    begin
      tmpStride := integer(aBMP.ScanLine[1]) - integer(aBMP.ScanLine[0]);

      if tmpStride < 0 then
        tmpBuffer := aBMP.ScanLine[aBMP.Height - 1]
      else
        tmpBuffer := aBMP.ScanLine[0];

      aVG.attach(tmpBuffer, aBMP.Width, aBMP.Height, tmpStride);
    end;

    procedure TForm1.OnScenePaint(Sender: TObject);
    begin
      Self.fBMP.Canvas.FillRect(Self.ClientRect);

    //  Self.fBMP.Canvas.ellipse(20, 20, 80, 80);  // Work
    //  Self.fVG.ellipse(50, 50, 30, 30);          // Work
    //  Self.fEngine_BMP.DrawEllipse;              // Work
      Self.fEngine_Agg.DrawEllipse;                // Do not work

      Self.Canvas.Draw(0, 0, fBMP);
    end;

    procedure TForm1.OnSceneResize(Sender: TObject);
    begin
      fBMP.Width := IfThen(ClientWidth > 0, ClientWidth, 2);
      fBMP.Height := IfThen(ClientHeight > 0, ClientHeight, 2);

      Self.AttachBMP(fVG, fBMP);
    end;

    end.

如果删除过程参数的var前缀的所有出现,则第二个循环绘制代码也将停止工作,这一点我不太理解。为方便您的使用,该单元如下:

代码语言:javascript
复制
    unit Unit1;

    interface

    uses
      agg_2D,
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;

    type
      TRenderEngine_BMP = class;
      TRenderEngine_Agg = class;
      TForm1 = class;

      TRenderEngine_BMP = class
      private
        fBMP: TBitmap;
      public
        constructor Create(aBMP: TBitmap);
        procedure DrawEllipse;
      end;

      TRenderEngine_Agg = class
      private
        fVG: Agg2D;
      public
        constructor Create(aVG: Agg2D);
        procedure DrawEllipse;
      end;

      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }

        fBMP: TBitmap;
        fVG: Agg2D;
        fEngine_BMP: TRenderEngine_BMP;
        fEngine_Agg: TRenderEngine_Agg;

        procedure AttachBMP(aVG: Agg2D; aBMP: TBitmap);
        procedure OnSceneResize(Sender: TObject);
        procedure OnScenePaint(Sender: TObject);
      public
        { Public declarations }
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.dfm}

    uses
      Math;

    { TRenderEngine_BMP }

    constructor TRenderEngine_BMP.Create(aBMP: TBitmap);
    begin
      Self.fBMP := aBMP;
    end;

    procedure TRenderEngine_BMP.DrawEllipse;
    begin
      Self.fBMP.Canvas.ellipse(20, 20, 80, 80);
    end;

    { TRenderEngine_Agg }

    constructor TRenderEngine_Agg.Create(aVG: Agg2D);
    begin
      Self.fVG := aVG;
    end;

    procedure TRenderEngine_Agg.DrawEllipse;
    begin
      Self.fVG.ellipse(50, 50, 30, 30);
    end;

    { TForm1 }

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Self.OnResize := {$IFDEF FPC} @ {$ENDIF} OnSceneResize;
      Self.OnPaint := {$IFDEF FPC} @ {$ENDIF} OnScenePaint;

      fBMP := TBitmap.Create;
      fBMP.PixelFormat := pf32bit;
      fBMP.Canvas.Brush.Style := bsSolid;
      fBMP.Canvas.Brush.Color := clBlue;
      fBMP.Width := ClientWidth;
      fBMP.Height := ClientHeight;

      fVG.Construct;
      Self.AttachBMP(fVG, fBMP);

      fEngine_BMP := TRenderEngine_BMP.Create(fBMP);
      fEngine_Agg := TRenderEngine_Agg.Create(fVG);
    end;

    procedure TForm1.AttachBMP(aVG: Agg2D; aBMP: TBitmap);
    var
      tmpBuffer: pointer;
      tmpStride: integer;
    begin
      tmpStride := integer(aBMP.ScanLine[1]) - integer(aBMP.ScanLine[0]);

      if tmpStride < 0 then
        tmpBuffer := aBMP.ScanLine[aBMP.Height - 1]
      else
        tmpBuffer := aBMP.ScanLine[0];

      aVG.attach(tmpBuffer, aBMP.Width, aBMP.Height, tmpStride);
    end;

    procedure TForm1.OnScenePaint(Sender: TObject);
    begin
      Self.fBMP.Canvas.FillRect(Self.ClientRect);

    //  Self.fBMP.Canvas.ellipse(20, 20, 80, 80);  // Work
    //  Self.fVG.ellipse(50, 50, 30, 30);          // Do not Work
    //  Self.fEngine_BMP.DrawEllipse;              // Work
      Self.fEngine_Agg.DrawEllipse;                // Do not work

      Self.Canvas.Draw(0, 0, fBMP);
    end;

    procedure TForm1.OnSceneResize(Sender: TObject);
    begin
      fBMP.Width := IfThen(ClientWidth > 0, ClientWidth, 2);
      fBMP.Height := IfThen(ClientHeight > 0, ClientHeight, 2);

      Self.AttachBMP(fVG, fBMP);
    end;

    end.
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-03-06 20:26:49

我很难理解你在这里做什么。我认为您的基本问题是Agg2Dobject,值类型也是。你拿一份,这样就有两份,而不是一份。作者选择使用object而不是类,但这样做要求您非常警惕TObject后代的值语义,而不是引用语义。

要使其工作起来,最快的方法是将fVG: Agg2D;更改为fVG: ^Agg2D;,在TRenderEngine_Agg.Create中将Self.fVG := aVG更改为Self.fVG := @aVG。随着这个变化,椭圆就画出来了。

现在,我认为你需要重新考虑你的设计。如果要将Agg2D对象包装在呈现类中,那就可以了,但是不能复制Agg2D对象。

下面是我如何编写您的代码来处理这个问题:

代码语言:javascript
复制
TRenderEngine_Agg = class
private
  fVG: Agg2D;
public
  constructor Create;
  procedure AttachBMP(aBMP: TBitmap);
  procedure DrawEllipse;
end;

constructor TRenderEngine_Agg.Create;
begin
  fVG.Construct;
end;

procedure TRenderEngine_Agg.AttachBMP(aBMP: TBitmap);
var
  tmpBuffer: pointer;
  tmpStride: integer;
begin
  tmpStride := integer(aBMP.ScanLine[1]) - integer(aBMP.ScanLine[0]);

  if tmpStride < 0 then
    tmpBuffer := aBMP.ScanLine[aBMP.Height - 1]
  else
    tmpBuffer := aBMP.ScanLine[0];

  fVG.attach(tmpBuffer, aBMP.Width, aBMP.Height, tmpStride);
end;

procedure TRenderEngine_Agg.DrawEllipse;
begin
  Self.fVG.fillColor(30, 50, 20);
  Self.fVG.blendMode(BlendContrast );
  Self.fVG.ellipse(50, 50, 30, 30);
end;

procedure TForm20.OnSceneResize(Sender: TObject);
begin
  fBMP.Width := IfThen(ClientWidth > 0, ClientWidth, 2);
  fBMP.Height := IfThen(ClientHeight > 0, ClientHeight, 2);

  fEngine_Agg.AttachBMP(fBMP);
end;

这样做的目的是将与Agg2D对象有关的所有事情都放在TRenderEngine_Agg中。如果你这么做,我想你会很棒的!!

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5212853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档