delphi2007 教程

delphi2007 教程

首页 新随笔 联系 聚合 管理
  1013 Posts :: 0 Stories :: 28 Comments :: 0 Trackbacks
组件是如何显示出来的? VCL组件开发及应用
http://www.delphi2007.net/DelphiVCL/html/delphi_20061225141614123.html
同是一个基类比如twinctrol派生出来的的控件,显示的样子各不相同,比如说BUTTON和STRINGGRID,看了看CREATE函数,好像里边只是对基本参数赋初试值,那当一个控件被放置到窗口上后即被显示出来,它是如何显示出来的,这个过程怎样处理的?换句话说它都调用了什么函数实现显示控件的,控件的样式又是如何更改成各式各样的?自己如何封装才能让一个控件按自己的样式显示出来?

解答你的问题可以写书了,建议看看入门书或者大全书,就了解了

一般通过调用TCanvas的方法或是GDI的API函数画出的界面。  
  这个要做的多了画起来就得心应手了,一般可以去找网上很多的时间日期控件,有很多比较简单的,很容易看懂,然后就照着他的画,你想画什么样的就画什么样的,呵呵

To:   maozefa(阿发伯)  
        我知道问的问题有点范围太大了,入门的书也看了一点,比如inside   vcl、高手突破、D5指南什么的,只看明白了百分之70左右,总是感觉他讲什么知道,但是只是理性上的认识,没有感性认识,或者说,明白其中的道理,但是让自己作就又不知道如何下手了,希望可以找到以一个控件比如BUTTON为主线讲其整个实现过程。跟过源码,但是总是无攻而返。能不能再给建议一些符合我情况要求的基本的书。顺便问一下,有没有专门介绍关于组件开发的书籍呢?还有关于DELPHI详细语法的书籍,因为看VCL时发现一些语法书上根本就没有介绍,比如说DEFAULT关键字等,看英文帮助总是只能看董个大概,对所介绍知识的灵活运用帮助不大,所以希望能找到一本详细点的书籍。    
   
  To:zhangcheng125(老狼)    
        你说的时间控件能不能给说一个具体的名称,我好搜索以下,谢谢。感觉写控件这个工作还是需要windowsAPI的知识比较多。

其实写控件并不是很难的东西,只是要学好画图的,像DELPHI里的TCANVAS类,还有就是WINDOWS   API中关于GDI的部份,至于时间控件,在DELPHI盒子里很多的,可以去下来看看。个人认为只要把画图的这方面的知识学好了,管他什么组件都可以写出来(组件都是画出来的。:)

下班了,粗粗的写了一个,希望对你有帮助。  
   
  unit   TestButtons;  
   
  interface  
   
  uses  
      SysUtils,   Classes,   Controls,   Buttons,   Windows,   Messages,   Graphics;  
   
  type  
      TTestButton   =   class(TCustomControl)  
      private  
          FShowEdge:   Boolean;  
          FEdgeColor:   TColor;  
          FEdgeWidth:   Integer;  
          procedure   SetShowEdge(const   Value:   Boolean);  
          procedure   SetEdgeColor(const   Value:   TColor);  
          procedure   SetEdgeWidth(const   Value:   Integer);  
          {   Private   declarations   }  
      protected  
          {   Protected   declarations   }  
          procedure   Paint;   override;  
      public  
          {   Public   declarations   }  
          constructor   Create(AOwner:   TComponent);   override;  
      published  
          {   Published   declarations   }  
          property   Caption;  
          property   Color;  
          property   Font;  
          property   ShowEdge:   Boolean   read   FShowEdge   write   SetShowEdge   default   True;  
          property   EdgeColor:   TColor   read   FEdgeColor   write   SetEdgeColor   default   clBlack;  
          property   EdgeWidth:   Integer   read   FEdgeWidth   write   SetEdgeWidth   default   1;  
      end;  
   
  procedure   Register;  
   
  implementation  
   
  procedure   Register;  
  begin  
      RegisterComponents('Samples',   [TTestButton]);  
  end;  
   
  {   TTestButton   }  
   
  constructor   TTestButton.Create(AOwner:   TComponent);  
  begin  
      inherited   Create(AOwner);  
   
      FShowEdge   :=   True;  
      FEdgeColor   :=   clBlack;  
      FEdgeWidth   :=   1;  
  end;  
   
  procedure   TTestButton.Paint;  
  var  
      R:   TRect;  
      procedure   DrawTexts(AText:   string;   ARect:   TRect);  
      begin  
          DrawText(Canvas.Handle,   PChar(AText),   -1,   ARect,   DT_CENTER   or   DT_VCENTER   or   DT_SINGLELINE);  
      end;  
  begin  
      inherited   Paint;  
   
      R   :=   ClientRect;  
      Canvas.Brush.Color   :=   Color;  
      Canvas.Brush.Style   :=   bsSolid;  
   
      Canvas.Pen.Width   :=   EdgeWidth;  
      Canvas.Pen.Color   :=   EdgeColor;  
      Canvas.Pen.Style   :=   psSolid;  
   
      if   ShowEdge   then  
          Canvas.Rectangle(ClientRect);  
   
      InflateRect(R,   -EdgeWidth,   -EdgeWidth);  
      Canvas.Font.Assign(Font);  
      DrawTexts(Caption,   R);  
  end;  
   
  procedure   TTestButton.SetEdgeColor(const   Value:   TColor);  
  begin  
      if   Value   <>   FEdgeColor   then  
      begin  
          FEdgeColor   :=   Value;  
          Repaint;  
      end;  
  end;  
   
  procedure   TTestButton.SetEdgeWidth(const   Value:   Integer);  
  begin  
      if   Value   <>   FEdgeWidth   then  
      begin  
          FEdgeWidth   :=   Value;  
          Repaint;  
      end;  
  end;  
   
  procedure   TTestButton.SetShowEdge(const   Value:   Boolean);  
  begin  
      if   Value   <>   FShowEdge   then  
      begin  
          FShowEdge   :=   Value;  
          Repaint;  
      end;  
  end;  
   
  end.  
 

TO:zhangcheng125(老狼)  
      谢谢,很有帮助,借机会问个问题:  
      property   ShowEdge:   Boolean   read   FShowEdge   write   SetShowEdge   default   True;  
          property   EdgeColor:   TColor   read   FEdgeColor   write   SetEdgeColor   default   clBlack;  
          property   EdgeWidth:   Integer   read   FEdgeWidth   write   SetEdgeWidth   default   1;  
  中都有个default关键字,帮助中说不是默认值,是用来决定是否存储属性值,不太理解什么含义,麻烦给解释一下。  
   
  自己试着写个控件:主要是画个类似GRID控件。  
  具体做法是在TScrollBox控件中来画,代码如下:  
  unit   test;  
   
  interface  
   
  uses  
      Windows,   Controls,   Forms,   Classes,   Graphics,   Messages,         dialogs;  
   
  type  
      TStatu   =   (bgNormal,   bgSelected,   bgMouseIn);  
   
      TCellInfo   =   record  
          Rect:   TRect;  
          Index:   Integer;  
          Status:   TStatu;  
      end;  
   
      TBrxDrawGrid   =   class(TGraphicControl)  
      private  
          FAlign:   TAlign;  
          FContainer:   TScrollBox;  
          FMax:   Integer;  
          FRow:   Integer;  
          FCol:   Integer;  
          FCellWidth:   Integer;  
          FCellHeight:   Integer;  
          FSpRow:   Integer;  
          FSpCol:   Integer;  
          FClientWidth:   Integer;  
          FClientHeight:   Integer;  
          FCIArray:   Array   of   Array   of   TCellInfo;  
          procedure   SetAlign(Value:   TAlign);  
          procedure   SetMax(const   Value:   Integer);  
          function   GetMax:   Integer;  
          procedure   SetRow(const   Value:   Integer);  
          procedure   SetCol(const   Value:   Integer);  
          procedure   SetCellWidth(const   Value:   Integer);  
          procedure   SetCellHeight(const   Value:   Integer);  
          procedure   SetSpRow(const   Value:   Integer);  
          procedure   SetSpCol(const   Value:   Integer);  
          procedure   SetClientHeight(const   Value:   Integer);  
          procedure   SetClientWidth(const   Value:   Integer);  
          procedure   InitCIArray(const   Row,   Col:   Integer);  
          procedure   WMPaint(var   Message:   TWMPaint);   message   WM_PAINT;  
      protected  
          procedure   SetCellInfo(const   Row,   Col:   Integer);  
   
          procedure   DrawCell;  
      published  
          property   Align:   TAlign   read   FAlign   write   SetAlign   default   alNone;  
          property   RowCount:   Integer   read   FRow   write   SetRow   default   5;  
          property   ColCount:   Integer   read   FCol   write   SetCol   default   5;  
          property   DefaultColWidth:   Integer   read   FCellWidth   write   SetCellWidth   default   64;  
          property   DefaultRowHeight:   Integer   read   FCellHeight   write   SetCellHeight   default   24;  
          property   SpaceOfRow:   Integer   read   FSpRow   write   SetSpRow   default   1;  
          property   SpaceOfCol:   Integer   read   FSpCol   write   SetSpCol   default   1;  
          property   Height:   Integer   read   FClientHeight   write   SetClientHeight   default   120;  
          property   Width:   Integer   read   FClientWidth   write   SetClientWidth   default   320;  
      public  
          constructor   Create(AOwner:   TComponent);   override;  
            procedure   Paint;   override;  
          function   GetCellCount:   Integer;  
          function   GetHandle:   HWND;  
      end;  
   
  implementation  
   
  {   TBrxDrawGrid   }  
   
  constructor   TBrxDrawGrid.Create(AOwner:   TComponent);  
  var  
      Max:   Integer;  
  begin  
      inherited   Create(AOwner);  
      FContainer   :=   TScrollBox.Create(AOwner);  
      FContainer.Parent   :=   TWinControl(AOwner);  
      FContainer.Align   :=   alNone;  
      SetRow(5);  
      SetCol(5);  
      SetCellWidth(64);  
      SetCellHeight(24);  
      SetSpRow(1);  
      SetSpCol(1);  
      Max   :=   25;  
      SetMax(Max);  
      InitCIArray(5,   5);  
   
  end;  
   
  procedure   TBrxDrawGrid.DrawCell;  
  var  
      i,   j:   Integer;  
  begin  
      Canvas.Handle   :=   GetDC(FContainer.Handle);  
      Canvas.Pen.Color   :=   clRed;  
      Canvas.Brush.Color   :=   clBlue;  
      for   i   :=   0   to   FRow   -   1   do  
      begin  
          for   j   :=   0   to   FCol   -   1   do  
          begin  
              Canvas.Rectangle(FCIArray[i][j].Rect);  
          end;  
      end;  
  end;  
   
  function   TBrxDrawGrid.GetCellCount:   Integer;  
  begin  
      Result   :=   GetMax;  
  end;  
   
  function   TBrxDrawGrid.GetHandle:   HWND;  
  begin  
      Result   :=   FContainer.Handle;  
  end;  
   
  function   TBrxDrawGrid.GetMax:   Integer;  
  begin  
      Result   :=   FMax;  
  end;  
   
  procedure   TBrxDrawGrid.InitCIArray(const   Row,   Col:   Integer);  
  var  
      i,   j:   Integer;  
  begin  
      SetLength(FCIArray,   Row,   Col);  
      for   i   :=   0   to   Row   -   1   do  
      begin  
          for   j   :=   0   to   Col   -   1   do  
          begin  
              FCIArray[i][j].Rect.Left   :=   j   *   (FCellWidth   +   FSpCol);  
              FCIArray[i][j].Rect.Top   :=   i   *   (FCellHeight   +   FSpRow);  
              FCIArray[i][j].Rect.Right   :=   FCIArray[i][j].Rect.Left   +   FCellWidth;  
              FCIArray[i][j].Rect.Bottom   :=   FCIArray[i][j].Rect.Top   +   FCellHeight;  
              FCIArray[i][j].Index   :=   i   *   Col   +   j;  
              FCIArray[i][j].Status   :=   bgNormal;  
          end;  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.Paint;  
  begin  
      inherited;  
      DrawCell;  
  end;  
   
  procedure   TBrxDrawGrid.SetAlign(Value:   TAlign);  
  begin  
      if   FAlign   <>   Value   then  
      begin  
          FAlign   :=   Value;  
          FContainer.Align   :=   FAlign;  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetCellHeight(const   Value:   Integer);  
  begin  
      if   FCellHeight   <>   Value   then  
      begin  
          FCellHeight   :=   Value;  
          InitCIArray(FRow,   FCol);  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetCellInfo(const   Row,   Col:   Integer);  
  begin  
   
  end;  
   
  procedure   TBrxDrawGrid.SetCellWidth(const   Value:   Integer);  
  begin  
      if   FCellWidth   <>   Value   then  
      begin  
          FCellWidth   :=   Value;  
          InitCIArray(FRow,   FCol);  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetClientHeight(const   Value:   Integer);  
  begin  
      if   FClientheight   <>   Value   then  
      begin  
          FClientHeight   :=   Value;  
          FContainer.Height   :=   FClientHeight;  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetClientWidth(const   Value:   Integer);  
  begin  
      if   FClientWidth   <>   Value   then  
      begin  
          FClientWidth   :=   Value;  
          FContainer.Width   :=   FClientWidth;  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetCol(const   Value:   Integer);  
  begin  
      if   FCol   <>   Value   then  
      begin  
          FCol   :=   Value;  
          InitCIArray(FRow,   FCol);  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetMax(const   Value:   Integer);  
  begin  
      if   FMax   <>   Value   then  
      begin  
          FMax   :=   Value;  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetRow(const   Value:   Integer);  
  begin  
      if   FRow   <>   Value   then  
      begin  
          FRow   :=   Value;  
          InitCIArray(FRow,   FCol);  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetSpCol(const   Value:   Integer);  
  begin  
      if   FSpCol   <>   Value   then  
      begin  
          FSpCol   :=   Value;  
          InitCIArray(FRow,   FCol);  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.SetSpRow(const   Value:   Integer);  
  begin  
      if   FSpRow   <>   Value   then  
      begin  
          FSpRow   :=   Value;  
          InitCIArray(FRow,   FCol);  
      end;  
  end;  
   
  procedure   TBrxDrawGrid.WMPaint(var   Message:   TWMPaint);  
  begin  
      Paint;  
  end;  
   
  end.  
   
  碰到几个问题:  
  1.我的思路是系统发生WMPaint事件,调用Paint函数,Paint函数调用DrawCell,DrawCell完成画图工作并提供接口实现OnDrawCell。实现之后,当窗体最小化再打开,或是被其他船体覆盖后,所画的图形消失,并没有重画,分析原因是因为没有产生WM_PAINT消息,控件部分被挡住,当部分失效区有效时应该会产生个消息,应该对这个消息作处理,但是查看VCL中TDRAWGRID的实现,没有弄明白他这一点是如何作的。  
  2.但宽度大于容器(TScrollBox)时,如何让其产生滚动条。  
   
  3.以上诸如此类的问题,通过学习什么书籍可以掌握解决方法?  
   
  谢谢

首先说明一下Default的问题,Default   是指将Default后面的值保存到窗体的dfm文件中并不是指定默认值,如果要指定默认值的话要在构造函数中给定。  
   
  --------------------------  
  1.重绘的问题中你不用在WMPAINT消息下调用Paint函数,WMPAINT函数本来就会调用PAINT函数的。还有就是Canvas本就是TGraphicControl的一个属性,所以直接用就行了,不用去写这个:Canvas.Handle   :=   GetDC(FContainer.Handle);了,再就是我不懂你为什么要选创建个FContainer,直接画不就行了。  
   
  2.关于滚动条。我一般是这么做的自绘滚动条,比方说垂直的滚动条,道理是:  
  12321321  
  32323232   ----------top  
  43434343     滚动条  
  43434343   ----------Bottom  
  根据当前滚动条滑动的距离把头部不显示出来的画在显示区域外,也就是画的时候:比方一个区域TRect,那么就设他的Top为负的,这样就能把不显示的画在区域外面,(这要根据计算滚动条滑块滑动距离来得出TOp为负多少)同理水平滚动条也一样。  
   
  3.诸如此类问题,最好的学习是看别人的源代码,我是看了一些基础的源代码后自己在实践中摸索的一些东西  
   
   
  以上个人觉的有些没讲清楚,也可能是错的(全是我自己实践中尝试出来的,不过还算行还能用,呵呵),有不当或是不清楚的地方还望楼主和各位见谅,有空我可以写个简单的滚动条的例子给楼主。  
 

学习  
 

TO:zhangcheng125(老狼)  
        "有不当或是不清楚的地方还望楼主和各位见谅"---这我可不敢当,本来就是在向你请教问题,你能回答已经感不尽了。至于Default的问题现在脱您的富很清楚了,读中文就是舒服,帮助可以看懂,但是理解的不透彻。但是还有很多语法好笑一般语法书中也都没有提到过,比如重新声明什么的,不知道你看的是哪本基础的语法书籍,给推荐一下吧   :)  
          1.我故意用WMPAINT调用PAINT是因为我看了一下DRAWGRID的VCL源码,它的WMPAINT好像没有调用PAINT函数,(也可能在更早的父代对象中的WMPAINT中就调用了,但是我没有跟踪出来,没有掠清头绪,干脆就覆写了它),在PAINT中相应ONDRAWCELL,但是发现系统就没有响应WMPAINT,正在郁闷ing中,想不明白怎么连一个WMPAINT消息都没有产生,或者说没有相应。(之所以说没有产生wmpaint消息,是因为其中代码根本没执行)。各位知道是什么原因吗?  
        “Canvas.Handle   :=   GetDC(FContainer.Handle);了,再就是我不懂你为什么要选创建个FContainer,直接画不就行了。”--因为FContainer这个本身是一个TScrollBox对象实例。我的想法是将表格画到这个控件里,本来开始想采用TPANEL,但是他没有滚动条,所以就选择了TScrollBox.虽然CANVAS被封装可以直接使用,但是不将句柄给他就画不到对应控件上。不直接画是因为可以省去一些属性的实现,比如说ALIGN等等,而且他有滚动条,可以直接拿来用,舍得自己画还要做更多的工作。  
          2.你说的滚动条的实现方法,我是听董了,但是图没有看董,还有就是我想要是真的实现起来可能还会有接连不断的问题随之而来,不是怕遇到问题,只是想先解决目前的问题。  
   
          最后,谢谢zhangcheng125(老狼),目前还不会结帖,因为还有很多问题困扰。所以分迟迟不能发,请见谅。不过我知道您也不是为了分数对吧:),只是我心里过不去。哈哈,还希望以后多多指教。  
   
   
 

今天又确认了一下,其他从TGraphicControl派生下来的控件比如说TBevel,就是通过改写Paint方法来实现绘制的,我直接派生了一个,只改写了Paint方法,但是结果是又是会响应WMPAINT消息,有时又不会,赶到纳闷。在回到原来的控件上来,同样也是改写了Paint方法,为什么就不行呢,希望高人指点。

问题解决,开始是我有些基本属性没有初始化,初始化后问题解决。还有前面zhangcheng125(老狼)所说的Canva可以直接使用,是我多此一举了。  
   
  最后再次感谢zhangcheng125(老狼),以后还请多指教。

posted on 2008-09-19 13:43 delphi2007 阅读(149) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。