我在做一个自定义组件,到处是错误?
我还是照着书上来的!
那位高手,帮我看看!
unit MyButton;interfaceuses
  SysUtils, Classes, Controls, StdCtrls,Graphics,Messages,Types;type
  TMyButton = class(TButton)
  private
    FColor:TColor;
    FCanvas:TCanvas;
    IsFocused:Boolean;
    SetColor:TColor;
    procedure CNDrawItem(var CMessage: TWMDrawItem); message WM_DRAWITEM;
    { Private declarations }
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure SetButton(var ADefault:Boolean);
    { Protected declarations }
  public
    procedure Create(AOwner:TComponent);override;
    procedure Destroy;override;
    { Public declarations }
  published
    property Color:TColor read FColor write SetColor default clWhite;
    { Published declarations }
  end;procedure Register;implementation
procedure CNDrawItem(var CMessage: TWMDrawItem); message WM_DRAWITEM;
var
  IsDown, IsDefault: Boolean;
  ARect: TRect;
  Flags: Longint;
  DrawItemStruct: TDrawItemStruct;
  wh:TSize;
begin
  DrawItemStruct:=CMessage.DrawItemStruct^;
  FCanvas.Handle := DrawItemStruct.hDC;
  ARect := ClientRect;
  with DrawItemStruct do
  begin
    IsDown := itemState and ODS_SELECTED <> 0;
    IsDefault := itemState and ODS_FOCUS <> 0;
  end;  Flags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT;
  if IsDown then Flags := Flags or DFCS_PUSHED;
  if DrawItemStruct.itemState and ODS_DISABLED <> 0 then
     Flags := Flags or DFCS_INACTIVE;  if IsFocused or IsDefault then
  begin
    //按钮得到焦点时的状态绘制
    FCanvas.Pen.Color := clWindowFrame;
    FCanvas.Pen.Width := 1;
    FCanvas.Brush.Style := bsClear;
    FCanvas.Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom);
    InflateRect(ARect, -1, -1);
  end;  FCanvas.Pen.Color := clBtnShadow;
  FCanvas.Pen.Width := 1;
  FCanvas.Brush.Color := FColor;
  if IsDown then begin
    //按钮被按下时的状态绘制
     FCanvas.Rectangle(ARect.Left , ARect.Top, ARect.Right, ARect.Bottom);
     InflateRect(ARect, -1, -1);
  end else
     //绘制一个未按下的按钮
     DrawFrameControl(DrawItemStruct.hDC, ARect, DFC_BUTTON, Flags);
  FCanvas.FillRect(ARect);  //绘制Caption文本内容
  FCanvas.Font := Self.Font;
  ARect:=ClientRect;
  wh:=FCanvas.TextExtent(Caption);
  FCanvas.Pen.Width := 1;
  FCanvas.Brush.Style := bsClear;
  if not Enabled then
  begin //按钮失效时应多绘一次Caption文本
     FCanvas.Font.Color := clBtnHighlight;
     FCanvas.TextOut((Width div 2)-(wh.cx div 2)+1,
                     (height div 2)-(wh.cy div 2)+1,
                      Caption);
     FCanvas.Font.Color := clBtnShadow;
  end;
  FCanvas.TextOut((Width div 2)-(wh.cx div 2),(height div 2)-(wh.cy div 2),Caption);  //绘制得到焦点时的内框虚线
  if IsFocused and IsDefault then
  begin
     ARect := ClientRect;
     InflateRect(ARect, -4, -4);
     FCanvas.Pen.Color := clWindowFrame;
     FCanvas.Brush.Color := FColor;
     DrawFocusRect(FCanvas.Handle, ARect);
  end;
  FCanvas.Handle := 0;end;
procedure SetButton(var ADefault:Boolean);
begin
  if ADefault <> IsFocused then
  begin
    IsFocused := ADefault;
    Refresh;
  end;
end;
procedure CreateParams(var Params:TCreateParams);override;
begin
 with Params do
   Style=Style or BS_OWNERDRAW;
end;
procedure Create(AOwner:TComponent);override;
begin
  inherited;
  FCanvas:=TCanvas.Create;
end;
procedure Destroy;override;
begin
  FCanvas.Free;
  inherited;
end;
procedure Register;
begin
  RegisterComponents('MyLib', [TMyButton]);
end;end.

解决方案 »

  1.   

    你看的是什么书啊.稍稍看了一下,N多错,看不下去了,自定义控件很多书上有,换一本书吧
    前面的几个错为:
    public
        procedure Create(AOwner:TComponent);override; //1
        procedure Destroy;override; //2
    1. 你的控件基于TButton,它的Create定义为构造函数,所以要定义为:
    constructor Create(AOwner:TComponent);override;
    2.同理:
     destructor Destroy;override;
    implementation
    procedure CNDrawItem(var CMessage: TWMDrawItem); message WM_DRAWITEM; //3
    3.CNDrawItem是你类中的函数.所以要写成
    procedure TMyButton.CNDrawItem(var CMessage: TWMDrawItem);
    另外,message WM_DRAWITEM;是函数申明时用,实现(定义)时不能有
     DrawItemStruct: TDrawItemStruct;
    你的TDrawItemStruct在哪里定义的?
    ...
      

  2.   

    TDrawItemStruct没有定义.它应该是一个系统中的变量吧?
      

  3.   

    TDrawItemStruct是WINDOWS中定义的.我加入了.
    但是它提示:
      IsDown := (itemState) and (ODS_SELECTED <> 0);
      IsDefault := (itemState) and (ODS_FOCUS <> 0);
    这个句出错.
    提示:"Operator not applicable to this Operand type."
      

  4.   

    很简单,找个简单组件看一下就好了,如SPCOMM等,主要是继承自TComponent类,增加些属性方法,构造析构,然后Register注册组件
      

  5.   

    你看参考下vcl的源代码, tbitbtn这个类是从tbutton继承过来的.
    建议去看看windows程序设计.
      

  6.   

    tbitbtn这个类,应该很有参考价值。
      

  7.   

    编译完成了,并已安装了.在是在使用时出错,
    system error. code:87
    参数错误.怎回事?
      

  8.   

    帮你改了一下,可以编译安装成功,至于能否达到你的要求,你可试一下:
    unit MyButton;interfaceuses
      SysUtils, Classes, Controls, StdCtrls,Graphics,Messages,Types,WINDOWS;type
      TMyButton = class(TButton)
      private
        FColor:TColor;
        FCanvas:TCanvas;
        IsFocused:Boolean;
        SetColor:TColor;
        procedure CNDrawItem(var CMessage: TWMDrawItem); message WM_DRAWITEM;
        { Private declarations }
      protected
        procedure CreateParams(var Params: TCreateParams); override;
        procedure SetButton(var ADefault:Boolean);
        { Protected declarations }
      public
        constructor Create(AOwner:TComponent);override;
       destructor Destroy;override;
        { Public declarations }
      published
        property Color:TColor read FColor write SetColor default clWhite;
        { Published declarations }
      end;procedure Register;implementation
    procedure TMyButton.CNDrawItem(var CMessage: TWMDrawItem); // message WM_DRAWITEM;
    var
      IsDown, IsDefault: Boolean;
      ARect: TRect;
      Flags: Longint;
      DrawItemStruct: TDrawItemStruct;
      wh:TSize;
    begin
      DrawItemStruct:=CMessage.DrawItemStruct^;
      FCanvas.Handle := DrawItemStruct.hDC;
      ARect := ClientRect;
      with DrawItemStruct do
      begin
        IsDown := itemState and ODS_SELECTED <> 0;
        IsDefault := itemState and ODS_FOCUS <> 0;
      end;  Flags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT;
      if IsDown then Flags := Flags or DFCS_PUSHED;
      if DrawItemStruct.itemState and ODS_DISABLED <> 0 then
         Flags := Flags or DFCS_INACTIVE;  if IsFocused or IsDefault then
      begin
        //按钮得到焦点时的状态绘制
        FCanvas.Pen.Color := clWindowFrame;
        FCanvas.Pen.Width := 1;
        FCanvas.Brush.Style := bsClear;
        FCanvas.Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom);
        InflateRect(ARect, -1, -1);
      end;  FCanvas.Pen.Color := clBtnShadow;
      FCanvas.Pen.Width := 1;
      FCanvas.Brush.Color := FColor;
      if IsDown then begin
        //按钮被按下时的状态绘制
         FCanvas.Rectangle(ARect.Left , ARect.Top, ARect.Right, ARect.Bottom);
         InflateRect(ARect, -1, -1);
      end else
         //绘制一个未按下的按钮
         DrawFrameControl(DrawItemStruct.hDC, ARect, DFC_BUTTON, Flags);
      FCanvas.FillRect(ARect);  //绘制Caption文本内容
      FCanvas.Font := Self.Font;
      ARect:=ClientRect;
      wh:=FCanvas.TextExtent(Caption);
      FCanvas.Pen.Width := 1;
      FCanvas.Brush.Style := bsClear;
      if not Enabled then
      begin //按钮失效时应多绘一次Caption文本
         FCanvas.Font.Color := clBtnHighlight;
         FCanvas.TextOut((Width div 2)-(wh.cx div 2)+1,
                         (height div 2)-(wh.cy div 2)+1,
                          Caption);
         FCanvas.Font.Color := clBtnShadow;
      end;
      FCanvas.TextOut((Width div 2)-(wh.cx div 2),(height div 2)-(wh.cy div 2),Caption);  //绘制得到焦点时的内框虚线
      if IsFocused and IsDefault then
      begin
         ARect := ClientRect;
         InflateRect(ARect, -4, -4);
         FCanvas.Pen.Color := clWindowFrame;
         FCanvas.Brush.Color := FColor;
         DrawFocusRect(FCanvas.Handle, ARect);
      end;
      FCanvas.Handle := 0;end;
    procedure TMyButton.SetButton(var ADefault:Boolean);
    begin
      if ADefault <> IsFocused then
      begin
        IsFocused := ADefault;
        Refresh;
      end;
    end;
    procedure TMyButton.CreateParams(var Params:TCreateParams);
    begin
      inherited CreateParams(Params);
     with Params.WindowClass do
      Style:=Style or BS_OWNERDRAW;
    end;
    constructor TMyButton.Create(AOwner:TComponent);
    begin
      inherited;
      FCanvas:=TCanvas.Create;
    end;
    destructor TMyButton.Destroy;
    begin
      FCanvas.Free;
      inherited;
    end;
    procedure Register;
    begin
      RegisterComponents('MyLib', [TMyButton]);
    end;end.
      

  9.   

    keiy() :
    我编译完成了,并已安装了.只是在使用时出错,我新建一个工程,当我把这个控件放到FORM中时出错:
    system error. code:87
    参数错误.怎回事?
      

  10.   

    keiy改得没有问题,是你自己编译没有更新
    最好将以期的代码改名备份重新编译
    参考下面改进后的代码:unit MyButton;interfaceuses
      Windows, Messages, SysUtils, Classes, Controls, StdCtrls, Graphics;type
      TMyButton = class(TButton)
      private
        FCanvas: TCanvas;
        IsFocused: Boolean;
        procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM; // 换成CN_DRAWITE不是WM_DRAWITE
      protected
        procedure CreateParams(var Params: TCreateParams); override;
        procedure SetButtonStyle(ADefault: Boolean); override; // 这条必须加,才能触发CN_DRAWITEM
      public
        constructor Create(AOwner: TComponent);override;
        destructor Destroy; override;
      published
        property Color default clWhite; // Color在父类中已经有声明
      end;procedure Register;implementationprocedure Register;
    begin
      RegisterComponents('MyLib', [TMyButton]);
    end;procedure TMyButton.CNDrawItem(var Message: TWMDrawItem);
    var
      IsDown, IsDefault: Boolean;
      ARect: TRect;
      Flags: Longint;
      DrawItemStruct: TDrawItemStruct;
      wh: TSize;
    begin
      DrawItemStruct := Message.DrawItemStruct^;
      FCanvas.Handle := DrawItemStruct.hDC;
      ARect := ClientRect;
      with DrawItemStruct do
      begin
        IsDown := itemState and ODS_SELECTED <> 0;
        IsDefault := itemState and ODS_FOCUS <> 0;
      end;  Flags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT;
      if IsDown then Flags := Flags or DFCS_PUSHED;
      if DrawItemStruct.itemState and ODS_DISABLED <> 0 then
        Flags := Flags or DFCS_INACTIVE;  if IsFocused or IsDefault then
      begin
        //按钮得到焦点时的状态绘制
        FCanvas.Pen.Color := clWindowFrame;
        FCanvas.Pen.Width := 1;
        FCanvas.Brush.Style := bsClear;
        FCanvas.Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom);
        InflateRect(ARect, -1, -1);
      end;  FCanvas.Pen.Color := clBtnShadow;
      FCanvas.Pen.Width := 1;
      FCanvas.Brush.Color := Color;
      if IsDown then
      begin
       //按钮被按下时的状态绘制
        FCanvas.Rectangle(ARect.Left , ARect.Top, ARect.Right, ARect.Bottom);
        InflateRect(ARect, -1, -1);
      end else
        //绘制一个未按下的按钮
        DrawFrameControl(DrawItemStruct.hDC, ARect, DFC_BUTTON, Flags);
      FCanvas.FillRect(ARect);  //绘制Caption文本内容
      FCanvas.Font.Assign(Font);
      ARect := ClientRect;
      wh := FCanvas.TextExtent(Caption);
      FCanvas.Pen.Width := 1;
      FCanvas.Brush.Style := bsClear;
      if not Enabled then
      begin //按钮失效时应多绘一次Caption文本
        FCanvas.Font.Color := clBtnHighlight;
        FCanvas.TextOut((Width div 2) - (wh.cx div 2) + 1,
          (Height div 2) - (wh.cy div 2) + 1, Caption);
        FCanvas.Font.Color := clBtnShadow;
      end;
      FCanvas.TextOut((Width div 2) - (wh.cx div 2),
        (Height div 2) - (wh.cy div 2), Caption);  //绘制得到焦点时的内框虚线
      if IsFocused and IsDefault then
      begin
        ARect := ClientRect;
        InflateRect(ARect, -4, -4);
        FCanvas.Pen.Color := clWindowFrame;
        FCanvas.Brush.Color := Color;
        DrawFocusRect(FCanvas.Handle, ARect);
      end;
      FCanvas.Handle := 0;
    end;procedure TMyButton.SetButtonStyle(ADefault: Boolean);
    begin
      if ADefault <> IsFocused then
      begin
        IsFocused := ADefault;
        Refresh;
      end;
    end;procedure TMyButton.CreateParams(var Params: TCreateParams);
    begin
      inherited CreateParams(Params);
      with Params do Style := Style or BS_OWNERDRAW; // 不是Params.WindowClass
    end;constructor TMyButton.Create(AOwner: TComponent);
    begin
      inherited;
      FCanvas := TCanvas.Create;
      Color := clWhite; // 默认值需要在Create中设置
    end;destructor TMyButton.Destroy;
    begin
      FCanvas.Free;
      inherited;
    end;end.
      

  11.   

    开始我也发现system error. code:87错,用我上面的,注意以下部分procedure TMyButton.CreateParams(var Params:TCreateParams);
    begin
      inherited CreateParams(Params);
     with Params.WindowClass do
      Style:=Style or BS_OWNERDRAW;
    end;另外,按zswang(伴水清清)(专家门诊清洁工)所说,重新编译
      

  12.   

    出错:
     procedure SetButtonStyle(ADefault: Boolean); override;提示:Declaration of 'setbuttonstyle' differs from previous declaration.
    是不是说定义出父类的不一样?
      

  13.   

    不会吧,用我的程序,贴到你的unit中试试(我安装使用没问题)
    如果你用zswang(伴水清清)(专家门诊清洁工)的程序,头上和下面的SetButtonStyle都要改
      

  14.   

    ok了,谢谢大家!
    不过有几个问题不明白:
    1、procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM; // 换成CN_DRAWITEM不是WM_DRAWITE 为什么要换成CN_DRAWITEM ,WINDOWS消息不是WM_DRAWITEM,怎么变成CN_DRAWITEM。
    2、 SetButtonStyle(ADefault: Boolean); 函数既然是父类的函数,在我DELPHI的帮助中TBUTTON类里找不到SetButtonStyle 这个函数?
      

  15.   

    1、你自己换成WM_DRAWITEM自己看看效果,少动口多动手
      看TBitBtn怎么封装就怎么封装,VCL是开源的
      你学自定义组建最好的学习对象就是VCL的源代码2、
      TButton = class(TButtonControl)
      private
    //。
      protected
    //。
        procedure SetButtonStyle(ADefault: Boolean); virtual;
    //。
      end;
      

  16.   

    WIDNOWS消息以WM开头的,怎么又变成CN开头了,我想知道原因,我现在已经搞定了,可我还是不知道为什么是CN_ 
    我要知道它为什么这样.
      

  17.   

    CN_XXX是delphi使用的自定义消息
      

  18.   

    那用WM_DRAWITEM代替CN_DRAWITEM可以吗?
      

  19.   

    我试过了不行,可是我不明白为什么WM_DRAWITEM不行,WINDOWS中本来就有这条消息.为什么不行.
    还有既然有CN_DRAWITEM,那有没有CN_LBUTTON等呢?