怎样让TShape输出文字?

时间:2022-01-03 23:46:43
因为TShape没有公开的canvas属性,而它的父类TGraphicControl在protected部分声明了一个只读的canvas属性,于是我声明了一个类

TmyShape = class(TShape)
published
  canvas:TCanvas;
end;

但是后来当我调用到这个类的TextOut方法时出错了,是不是与它的只读属性有关呢?应该如何解决?

myShape1.canvas.TextOut(0,0,'hello');   //这一句就出错了。

9 个解决方案

#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(修罗是谁?!) 已经讲得很清楚,呵呵。

#9


呵呵,明白了。多谢!!

#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(修罗是谁?!) 已经讲得很清楚,呵呵。

#9


呵呵,明白了。多谢!!