zoukankan      html  css  js  c++  java
  • delphi 可以自定义边框的文本框TSkinNormalEdit思路(QQ2011风格)

    需求:

    QQ我的资料中基本资料窗体中的文本框:

    正常状态下,文本框只有一条看起来只有一个像素的边框,边框的颜色从上到下由深到浅的渐变,当鼠标定位到该文本框时,其边框会变粗,而且边框的颜色加亮显示

    如下图所示:

    实现思路:

    一、准备两个边框素材图片,

    一个是正常状态下的边框素材,

    比如:

    另一个是鼠标进入到文本框内的边框素材

    比如:

    二、需要的参数

    首先是边框素材的绘制边距,分为左边距,右边距,上边距,下边距

    边框素材根据边距的设置,使用九宫格缩放绘制到界面上

    其次是边框的边距,也为左边距,右边距,上边距,下边框

    代表的是文本框客户区(即输入区)的大小

    默认的,边框素材的绘制边距和边框的边距是一样的

    三、消息处理

    边框属于文本框的非客户区域,在文本框的WM_NCPAINT中绘制

    文本框的边框风格有两种:bsNone和bsSingle

    bsNone即为无边框样式,不需要绘制边框,而且文本框的大小就是客户区的大小

    bsSingle为单边框样式,默认边框为两个像素的宽

    如果需要自定义文本框的边框宽度,那么需要处理WM_NCCALCSIZE消息

    通过WM_NCCALCSIZE消息,使边框扩展为自己所设置的宽度

    例(边框扩展一个像表):

     procedure TSkinNormalEdit.WMNCCalcSize(varMessage: TWMNCCalcSize);  

     var  

      NCCalcSizeParams: PNCCalcSizeParams;  

     begin  

      Inherited;  

       if(BorderStyle=bsNone) then  

      begin  

       end  

      else  

      begin  

        NCCalcSizeParams:=Message.CalcSize_Params;  

        Inc(NCCalcSizeParams.rgrc0.Top,1);  

        Inc(NCCalcSizeParams.rgrc0.Left,1);  

        Dec(NCCalcSizeParams.rgrc0.Right,1);  

        Dec(NCCalcSizeParams.rgrc0.Bottom,1);  

      end;  

     end;  

    四、边框绘制时机

    边框有两种状态,鼠标进入到文本框中和鼠标离开文本框

    所以,要判断这两种状态

    像一般的从TCustomControl或TGraphicControl继承过来的控件,

    我们可以通过Delphi内部的管理消息CM_MOUSEENTER和CM_MOUSELEAVE消息处理

    但是文本框包含非客户区(边框)和客户区

    CM_MOUSEENTER和CM_MOUSELEAVE消息只是鼠标进入或是离开客户区才会响应

    所以接下来要处理如何判断鼠标在非客户区中

    非客户区的鼠标移动消息主要有三个

    WM_NCMOUSEMOVE:非客户区鼠标移动

    WM_NCHITTEST:非客户区鼠标移动在控件的哪个部位(标题栏?边框?边角?客户区等等)

    WM_NCMOUSELEAVE:鼠标离开非客户区(但是文本框不触发这个消息)

    综上,没有一个消息可以简单的标识鼠标是否在控件中

    CM_MOUSEENTER可以判断鼠标进入控件的客户区

    WM_NCHITTEST可以判断鼠标在控件的非客户区

    CM_MOUSELEAVE不能判断鼠标离开控件的客户区

    所以,用一个定时器加一个判断鼠标在客户区的过程组合

    WM_NCHITTEST消息中,判断当鼠标进入第一次非客户区时,响应鼠标进入消息,重绘边框,设置定时器,判断鼠标是否会在100毫秒内离开文本框

    CM_MOUSEENTER消息中,鼠标已经进入客户区了,重绘边框

    CM_MOUSELEAVE 消息中,只是表明了鼠标离开客户区,所以要启动定时器,每100毫秒判断鼠标是否在文本框中,如果检测到鼠标离开文本框,那么需要响应鼠标离开,重绘边框

    五、边框绘制

    边框为非客户区,在文本框的WM_NCPAINT消息中绘制

    比如:

        procedure TSkinNormalEdit.WMNCPaint(varMessage: TWMNCPaint);  

        var  

          tmpWindowDC:HDC;  

         tmpBorderImage:IGPBitmap;  

         tmpWindowCanvas:TCanvas;  

         tmpBitmapGraphics:IGPGraphics;  

        begin  

          ifSelf.BorderStyle=bsNone then  

         begin  

           Inherited;  

          end  

         else  

         begin  

           tmpWindowDC:=GetWindowDC(Handle);  

           Try  

             if tmpWindowDC<>0 then  

             begin  

               tmpWindowCanvas:=TCanvas.Create;  

               Try  

                 tmpWindowCanvas.Handle:=tmpWindowDC;  

                 FParentBackGroundBitmap.SetSize(Width,Height);  

                 if FIsBroderTransparent then  

                 begin  

                   //绘制文本框背景  

                   DrawParentImageDefault(Self,FParentBackGroundBitmap.Canvas.Handle);  

                 end;  

                 //边框为png素材,使用GDI+绘制,需要获取绘制接口,需要引用gdiplus和gdiplushelpers单元  

                 tmpBitmapGraphics:=FParentBackGroundBitmap.Canvas.ToGPGraphics;  

                 //根据鼠标状态判断边框图片  

                 if Self.MouseInClient or CursorInControl then  

                 begin  

                   tmpBorderImage:=Self.FHoverBorderBitmap;  

                 end  

                 else  

                 begin  

                   tmpBorderImage:=Self.FNormalBorderBitmap;  

                 end;  

                 //再绘制背景  

                 if tmpBorderImage<>nil then  

                 begin  

                   //九宫格绘制边框素材  

                   TSkinHelper.StretchDrawImageBorderInRectByMargins(tmpBitmapGraphics,  

                             tmpBorderImage,TGPRect.Create(0,0,Width,Height),  

                             Self.FBorderDrawMargins.Left,  

                             Self.FBorderDrawMargins.Top,  

                              Self.FBorderDrawMargins.Right,  

                             Self.FBorderDrawMargins.Bottom);  

                 end;  

                 //绘制最外的边框  

                 //左边框  

                 BitBlt( tmpWindowDC,0,0,Self.FBorderMargins.Left,Height,  

                          FParentBackGroundBitmap.Canvas.Handle,0,0,SRCCOPY  );  

                 //右边框  

                 BitBlt( tmpWindowDC,Width-Self.FBorderMargins.Right,0,Self.FBorderMargins.Right,Height,  

                          FParentBackGroundBitmap.Canvas.Handle,Width-Self.FBorderMargins.Right,0,SRCCOPY  );  

                 //上边框  

                 BitBlt( tmpWindowDC,0,0,Width,Self.FBorderMargins.Top,  

                          FParentBackGroundBitmap.Canvas.Handle,0,0,SRCCOPY  );  

                 //下边框  

                 BitBlt( tmpWindowDC,0,Height-Self.FBorderMargins.Bottom,Width,Self.FBorderMargins.Bottom,  

                          FParentBackGroundBitmap.Canvas.Handle,0,Height-Self.FBorderMargins.Bottom,SRCCOPY  );  

           

               Finally  

                 FreeAndNil(tmpWindowCanvas);  

               End;  

             end;  

           Finally  

             ReleaseDC(Handle,tmpWindowDC);  

           End;  

         end;  

        end;  

  • 相关阅读:
    lamp架构之升级php版本
    Linux常用命令大全
    Mysql表连接查询
    PHP练习题三
    PHP练习题二
    php 设计模式
    LAMP环境搭建教程
    Storm入门(四)WordCount示例
    Storm入门(三)HelloWorld示例
    Storm入门(一)原理介绍
  • 原文地址:https://www.cnblogs.com/blogpro/p/11426589.html
Copyright © 2011-2022 走看看