zoukankan      html  css  js  c++  java
  • TCoolMemo

    我们先起个名字叫做TCoolMemo。以上篇已经讲了很多组件的技术,这里就只说出几个重点。其余不多说了。

    首先,该Memo从CustomMemo继承,它有这样外观:属于平面的,边框是可以设置颜色的线,对应的颜色变量为FEdgeColor,另外,离边框以内的两个象素处,还有另一个框,当鼠标进入Memo时,这个框会显示,当鼠标离开时,为个框消失,同样也可以设置颜色,对应变量为FEnterColor。

    那么鼠标进入和离开怎么判断呢,这里Memo将截获两个Delphi的内部消息:
    //下面两个获得Delphi的内部消息,鼠标进入和离开时发生
         procedure CMMouseEnter (var Message: TMessage); message CM_MOUSEENTER;
         procedure CMMouseLeave (var Message: TMessage); message CM_MOUSELEAVE;

    其实父类已经截获了这两个消息,并作了相应处理,所以TCoolMemo中的消息处理函数要
    Inherited;再作自己的处理。这里又用到了一个变量
    MouseIn:Boolean;//标识鼠标是否进入组件
     

    接下来TCoolMemo还要截获两个消息:
    procedure WMPaint (var Message: TMessage); message WM_PAINT;
    procedure WMNCCalcSize (var Message: TWMNCCalcSize); message WM_NCCALCSIZE;

    第一个很熟悉,当需要重画时,触发该消息,
    第二个是当窗体需要计算位置和尺寸时触发,消息中包含了窗口客户区的大小,我们用这个的目的主要是将客户区缩小三个象素,以便画组件时不会画到客户区。

    procedure TCoolMemo.WMNCCalcSize (var Message: TWMNCCalcSize);
    begin
      inherited;
      InflateRect(Message.CalcSize_Params^.rgrc[0], -3, -3);
    end;

    而上面几个消息处理函数,CM_MOUSEENTER和CM_MOUSELEAVE;将引起TCoolMemo的外观变化,WM_PAINT保存其外观不被擦去。所以要用到一个画组件的函数,即:
    drawBorder;

    里面用到了几个API的GDI函数。我在代码中有详细的说明,加上自己看帮助,应该是可以看懂的。

    另外,相比于Memo,它的扩展了这样的功能:设置边距和获得光标的位置。这两个对应的性属为Margin,Position。他们都是Public的,不可以在对象察看器中看到。

    我们一个个来说

    边距设置
    property Margin:byte read FMargin write setMargin default 0;
    其中setMargin函数中发送了两个消息:
    //该消息取得输入区的尺寸
    SendMessage(Handle, EM_GETRECT, 0, Longint(@Rect));
    //该消息设定输入区的大小
    SendMessage(Handle, EM_SETRECT, 0, Longint(@Rect));

    光标的位置:
    property Position:TPosition read getPosition;
    TPostion是一个结构,其中有行和列两个值:
    TPosition=record  //指定光标的行和列
         row:longint;
         col:longint;
       end;
    getPosition;中还要处理中文的问题,代码有详细说明,如果文本中有中文,一样也可以得到正确的行和列。

    最后增加了两个事件
    property OnEnter;
    property OnExit;
    都是从父类中显化出来的,其实就是CM_MOUSEENTER和CM_MOUSELEAVE;消息引起的。,当你想作一个三态按钮,这两个事件很有作用。


    好了,重点就是上面那几个了,以下是源代码,其中也有详细的说明:

    unit CoolMemo;
    
    interface
    uses
       Windows, Messages, Classes, Forms,Controls, Graphics, StdCtrls;
    
    type
        //用设定边缘的空白
       TPosition=record  //指定光标的行和列
         row:longint;
         col:longint;
       end;
    
       TCoolMemo=class(TCustomMemo)
       private
         FMargin:byte;  //边距的大小
         FEdgeColor:TColor;//边框的颜色
         FEnterColor:TColor;//鼠标进入时边框内侧的框颜色
         MouseIn: Boolean; //标识鼠标是否进入
    
         function getPosition:TPosition;//光标的行和列
         procedure setMargin(value:byte);
         procedure setEdgeColor(Value:TColor);
         procedure setEnterColor(Value:TColor);
    
         //下面两个获得Delphi的内部消息,鼠标进入和离开时发生
         procedure CMMouseEnter (var Message: TMessage); message CM_MOUSEENTER;
         procedure CMMouseLeave (var Message: TMessage); message CM_MOUSELEAVE;
         //当一个窗口的外观必须被画时,应用程序发送这个消息给该窗口
         procedure WMPaint (var Message: TMessage); message WM_PAINT;
         //窗体需要计算位置和尺寸时触发
         //我们用这个的目的主要是将客户区缩小三个象素,以便画组件时不会画到客户区。
      procedure WMNCCalcSize (var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
    
       protected
       //画窗体的边框,使其看起来更美观.
         procedure drawBorder;
    
       public
         constructor Create (AOwner: TComponent); override;
         property Position:TPosition read getPosition;
         property Margin:byte read FMargin write setMargin default 0;
       published
        property EdgeColor:TColor read FEdgeColor write SetEdgeColor default $ff0000;
        property EnterColor:TColor read FEnterColor write SetEnterColor default $0000ff;
        //显式化父类的属性
        property Align;
        property Alignment;
        property DragCursor;
        property DragMode;
        property Enabled;
        property Color;
        property Font;
        property Lines;
        property MaxLength;
        property OEMConvert;
        property ParentFont;
        property ParentShowHint;
        property PopupMenu;
        property ReadOnly;
        property ShowHint;
        property ScrollBars;
        property TabOrder;
        property TabStop;
        property Visible;
        property WantReturns;
        property WantTabs;
        property WordWrap;
        property OnChange;
        property OnClick;
        property OnDblClick;
        property OnDragDrop;
        property OnDragOver;
        property OnEndDrag;
        //增加这两个事件,处理鼠标进入和离开
        property OnEnter;
        property OnExit;
        property OnKeyDown;
        property OnKeyPress;
        property OnKeyUp;
        property OnMouseDown;
        property OnMouseMove;
        property OnMouseUp;
        property OnStartDrag;
       end;
     
    procedure Register;
    
    implementation
    
    procedure Register;
    begin
      RegisterComponents('Samples', [TCoolMemo]);
    end;
    
    constructor TCoolMemo.Create(AOwner:TComponent);
    begin
      inherited Create(Aowner);
      ControlStyle := ControlStyle - [csFramed];
      ParentFont := True;
      FEdgeColor := $ff0000;
      FEnterColor := $0000ff;
      //设定外观,平面无边形
      Ctl3D := False;
      FMargin:=0;
      BorderStyle:=bsNone;
      height:=150;
      =200;
    end;
    
    procedure TCoolMemo.setMargin(Value:byte);
    var
      Rect: TRect;
    begin
    //该消息取得客户区的尺寸
      SendMessage(Handle, EM_GETRECT, 0, Longint(@Rect));
      //以下是重新确定尺寸
      Rect.Top := Value;
      Rect.Left := Value;
      Rect.Right := Width -Value;
      Rect.Bottom := Height -Value;
    //该消息设定客户区的大小
      SendMessage(Handle, EM_SETRECT, 0, Longint(@Rect));
      Fmargin:=value;
    end;
    
    function TCoolMemo.getPosition:TPosition;
    var
      row,Col:longint;
      CBLines:longint;
      str:WideString;
    begin
    //该消息取得光标所在的行,
      row:= SendMessage(Handle,EM_LINEFROMCHAR,SelStart,0);
      //该消息取得光标所在行开始的位置,位置从第一行的0开始计数,
      //每过一个字符增加1,
      CBLines:=SendMessage(Handle,EM_LINEINDEX,row,0);
      //得到光标的所在行的所在列
      Col:=SelStart-CBLines;
      //为了解决中文的问题,需要用宽字符型来取得光标所在行
      //,行中光标所在列之前的字符串,这样可以解决中文列数的确定问题.
      str:=Copy(Lines[row],1,col);
      col:=Length(Str)+1;
      result.row:=row+1;
      result.col:=col;
    end;
    
    procedure TCoolMemo.setEdgeColor(Value:TCOlor);
    begin
     if FEdgeColor<>value then
     begin
      FEdgeColor:=value;
      drawBorder;
     end;
    end;
    
    procedure TCoolMemo.setEnterColor(Value:TColor);
    begin
     if FEnterColor<>value then
     begin
       FEnterColor:=value;
       drawBorder;
     end;
    end;
    
    procedure TCoolMemo.CMMouseEnter(var Message: TMessage);
    begin
      inherited;
        MouseIn:= True;
        drawBorder;
    end;
    
    procedure TCoolMemo.CMMouseLeave(var Message:TMessage);
    begin
      inherited;
      MouseIn:=False;
      drawBorder;
    end;
    
    procedure TCoolMemo.WMPaint (var Message: TMessage);
    begin
      inherited;
      drawBorder;
    end;
    
    procedure TCoolMemo.WMNCCalcSize (var Message: TWMNCCalcSize);
    begin
      inherited;
      InflateRect(Message.CalcSize_Params^.rgrc[0], -3, -3);
    end;
    
    procedure TCoolMemo.drawBorder;
    var
      DC: HDC;  //设备描述表
      R: TRect; //客户区
      EnterBrush,OuterBrush,BorderBrush:HBRUSH;  //画笔句柄,API
    begin
      DC:= GetWindowDC(Handle);  //取得该组件的设备描述表
      try
        GetWindowRect(Handle, R);  //取得该组件的客户区尺寸
        OffsetRect(R, -R.Left, -R.Top); //左上偏移
        //创建画笔,两个,分别代码边框,边框内,白色画笔
        BorderBrush := CreateSolidBrush(ColorToRGB(FEdgeColor));
        EnterBrush:= CreateSolidBrush(ColorToRGB(FEnterColor));
        OuterBrush:=CreateSolidBrush(ColorToRGB(clWhite));
    //not(csDesigning in ComponentState保证在设计期不变
        if (not(csDesigning in ComponentState)) and
        (MouseIn=true) then  //如果鼠标进入
        begin
          //画一个矩形框,用BorderBrush画笔
          FrameRect(DC, R, BorderBrush);
          //把R缩小一个象素
          InflateRect(R, -1, -1);
          //画一个矩形框,用outerBrush画笔
          FrameRect(DC, R, outerBrush);
          InflateRect(R, -1, -1);
          FrameRect(DC, R, EnterBrush);
        end
        else  //如果鼠标没有进入
        begin
          FrameRect(DC, R, BorderBrush);
          InflateRect(R, -1, -1);
          FrameRect(DC, R, outerBrush);
          InflateRect(R, -1, -1);
          FrameRect(DC, R, outerBrush);
        end;
      finally
        ReleaseDC(Handle, DC);  //释放设备描述表
      end;
      DeleteObject(BorderBrush);   //释放画笔
      DeleteObject(EnterBrush);
      DeleteObject(OuterBrush);
    end;
    
    end.
    

    参考:
    http://blog.csdn.net/iseekcode/article/details/4698412
    http://www.delphixe.net/thread-5339-1-1.html

  • 相关阅读:
    EMES信息化制造系统的概念
    正则表达式校验日期、时间
    c#怎么string转化成ascii码
    C#实现将一个字符串进行翻转显示的6种方法,数组的 Reverse()反转方法
    把一个十六进制的字符串(包含0x或0X)转化成对应的数值 ASCII码
    为什么0-9转化成字符是+0x30,11转化成A是+0x37?
    oracle修改数据库字段长度
    表添加字段的SQL语句写法
    在数据表中添加一个字段的SQL语句怎么写-百度
    oracle创建表增加字段sql脚本,字段说明注释
  • 原文地址:https://www.cnblogs.com/findumars/p/4177195.html
Copyright © 2011-2022 走看看