因为TShape没有公开的canvas属性,而它的父类TGraphicControl在protected部分声明了一个只读的canvas属性,于是我声明了一个类TmyShape = class(TShape)
published
  canvas:TCanvas;
end;但是后来当我调用到这个类的TextOut方法时出错了,是不是与它的只读属性有关呢?应该如何解决?myShape1.canvas.TextOut(0,0,'hello');   //这一句就出错了。

解决方案 »

  1.   

    如果想继承TShape的Canvas属性的话,应该写成:
    TmyShape = class(TShape)
    published
      property canvas:TCanvas;
    end;
    但是刚才我试了一下,这样是编译不通过的,然后我看了一下它的两个父类,
    TShape中没有定义过Canvas属性,TGraphicControl中有Canvas属性,但是它是Protected的,
    照理来说,在TMyShape中只有将Canvas属性重新定义为public的,才可以给外部使用,但是,后来我将TMyShape改为:
    TmyShape = class(TShape)
    published
      //property canvas:TCanvas;
    end;
    后,TMyShape的Canvas属性就可以正常使用了,
    然而,如果直接想使用TShape的Canvas属性则又不可,不知道何故?
      

  2.   

    刚刚看了一下,果然漏写了property。但是就像tonylk(=www.tonixsoft.com=) 说的,这样编译是通不过的,反而是published之后什么都没写就一切OK。但这样的类定义有什么意义?
      

  3.   

    TMyShape = class(TShape)
      public
        property Canvas;
      end;这个能编译通过。如果你在form的OnCreate事件中加入:
    MyShape.canvas.textout(0,0,'123');
    你是不会在MyShape中看见任何东西的,因为执行了这一句之后在Form Paint是会自动调用TMyShape里的Paint函数来重画组件,这时候TMyShape的父类会调用自己的Paint方法来重画组件,因此‘123’会被覆盖掉,要想在TMyShape中显示字体应该重载TShape的Paint方法而不是将它的Canvas属性公开。
      

  4.   

    TCustomShape = class(TShape)
      private
        procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
      protected
        procedure Paint; override;
      public
        property Text;
        property Color;
        property Font;
      end;procedure TCustomShape.CMTextChanged(var Message: TMessage);
    begin
      Invalidate
    end;procedure TCustomShape.Paint;
    begin
      Brush.Color := Color;  inherited;  Canvas.Font := Font;
      Canvas.TextOut(2, 2, Text);
    end;
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      with Shape do
      begin
        Color := clWhite;
        Font.Color := clRed;
        Text := 'WGYKING'
      end;
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
      Shape := TCustomShape.Create(nil);
      Shape.Parent := Self
    end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      FreeAndNil(Shape);
    end;
      

  5.   

    CareYouOnly(只在乎你)和WGYKING(修罗是谁?!) 的方法是通过重载paint方法来调用canvas,我试了一下已经OK了,谢谢!不过我还有一点疑问,那就是为什么
    TMyShape = class(TShape)
      public
        property Canvas;
      end;
    这样声明(公开属性时少写了属性的类型)就可以?
    或者
    TmyShape = class(TShape)
      published
        //property canvas:TCanvas;
      end;
    这样声明的时候,在published部分根本就什么代码都没有,也能调用Canvas,这是什么原因?
      

  6.   

    你是在同一单元申明这个类的吧?
    如果是
    他们为友元类
    任何域字段的字段值都可以访问TmyShape = class(TShape)
      published
        //property canvas:TCanvas;
      end;
    这种声明是错误的
    因为canvas是TMyShape的父类TShape的父类TGraphicControl类protected域的属性
    如果再子类中公布
    应该不加属性的类型
    否则就是一个新的属性
    父类同名属性被覆盖
      

  7.   

    你看看TPaintBox类
    他们父类相同
    这是另一种实现方式^_^
    TPaintBox = class(TGraphicControl)
      private
        FOnPaint: TNotifyEvent;   //定义事件
      protected
        procedure Paint; override;//重载Paint过程
      public
        constructor Create(AOwner: TComponent); override;
        property Canvas;          //公布Canvas属性
      published
        property Align;
        property Anchors;
        property Color;
        property Constraints;
        property DragCursor;
        property DragKind;
        property DragMode;
        property Enabled;
        property Font;
        property ParentColor;
        property ParentFont;
        property ParentShowHint;
        property PopupMenu;
        property ShowHint;
        property Visible;
        property OnClick;
        property OnContextPopup;
        property OnDblClick;
        property OnDragDrop;
        property OnDragOver;
        property OnEndDock;
        property OnEndDrag;
        property OnMouseDown;
        property OnMouseMove;
        property OnMouseUp;
        property OnPaint: TNotifyEvent read FOnPaint write FOnPaint; //公布事件属性
        property OnStartDock;
        property OnStartDrag;
      end;~~~~~~~~~~~~~~~~~~~
    procedure TPaintBox.Paint;
    begin
      Canvas.Font := Font;
      Canvas.Brush.Color := Color;
      if csDesigning in ComponentState then
        with Canvas do
        begin
          Pen.Style := psDash;
          Brush.Style := bsClear;
          Rectangle(0, 0, Width, Height);
        end;
      if Assigned(FOnPaint) then FOnPaint(Self);  //如果你指定了事件,在画玩外框后执行他
    end;
      

  8.   

    To:alexanda2000(期待Delphi9 ^_^) WGYKING(修罗是谁?!) 已经讲得很清楚,呵呵。