Delphi的Hint(2)

2016-02-19 21:31 24 1 收藏

下面是个简单易学的Delphi的Hint(2)教程,图老师小编详细图解介绍包你轻松学会,喜欢的朋友赶紧get起来吧!

【 tulaoshi.com - 编程语言 】

上一篇介绍了Hint的简单应用,这一篇将给出一个定制Hint窗口的例子。这个自定义Hint窗口的效果不错,以玻璃为边框,并且有阴影的效果。

  不过这之前,我们必须介绍一个如何定制,Hint的父类为THintWindow,在Controls单元中定义。我们看看几个虚拟方法,CreateParams设定窗口的风格,我们要覆盖掉它,使其没有边框。NCPaint画窗口的边框,我们也要覆盖它,因为我们不需要边框吗。Paint比较重要,为画Hint窗口客户区内容,当然要覆盖。不过最重要的当属ActivateHint,它会设定好窗口的大小,并显示它,我们就在这里定制一个类玻璃的窗口效果。下面给出该类的实现:

  unit wdHintWnd;

  

  interface

  uses

    Windows, Classes, Controls, Graphics, Forms, SysUtils, ExtCtrls;

   

  type

    TwdHintWnd = class(THintWindow)

    private

      FWndBmp: TBitmap;   //窗口位图

      FHintBmp: TBitmap;  //提示信息位图

    protected

      procedure CreateParams(var Params: TCreateParams); override;

      procedure Paint; override;

      procedure NCPaint(DC: HDC); override;

      {画提示的图象}

      procedure DrawHintImg(Bmp:TBitmap; AHint: string);

      {取得提示窗口对应的桌面区域的图象}

      procedure GetDesktopImg(Bmp: TBitmap; R: TRect);

      {对桌面区域图象作处理,使其看起来像一块玻璃且带有一点阴影}

      procedure EffectHandle(WndBmp, HintBmp: TBitmap);

    public

      constructor Create(Aowner: TComponent); override;

      destructor Destroy; override;

      procedure ActivateHint(Rect: TRect; const AHint: string); override;

    end;

   

  implementation

   

  { TwdHintWnd }

   

  procedure TwdHintWnd.ActivateHint(Rect: TRect; const AHint: string);

  var

    P: TPoint;

  begin

    //在这里取得一个适当的尺寸显示文字

    FHintBmp.Width := Rect.Right - Rect.Left;

    FHintBmp.Height := Rect.Bottom - Rect.Top + 4;

    DrawHintImg(FHintBmp, AHint);

    FWndBmp.Width := Rect.Right - Rect.Left + 23;

    FWndBmp.Height := Rect.Bottom - Rect.Top + 27;

    Inc(Rect.Right, 23);

    Inc(Rect.Bottom, 27);

    BoundsRect := Rect;

    if Left Screen.DesktopLeft then

       Left := Screen.DesktopLeft;

    if Top Screen.DesktopTop then

      Top := Screen.DesktopTop;

    if Left + Width Screen.DesktopWidth then

      Left := Screen.DesktopWidth - Width;

    if Top + Height Screen.DesktopHeight then

      Top := Screen.DesktopHeight - Height;

    GetDesktopImg(FWndBmp, BoundsRect);

    EffectHandle(FWndBmp, FHintBmp);

    P := ClientToScreen(Point(0, 0));

    SetWindowPos(Handle, HWND_TOPMOST, P.X, P.Y, 0, 0,

      SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOSIZE);

  end;

   

  constructor TwdHintWnd.Create(Aowner: TComponent);

  begin

    inherited;

    FWndBmp := TBitmap.Create;

    FWndBmp.PixelFormat := pf24bit;

    FHintBmp := TBitmap.Create;

  end;

   

  procedure TwdHintWnd.CreateParams(var Params: TCreateParams);

  begin

    inherited;

    //去掉窗口边框

    Params.Style := Params.Style and not WS_BORDER;

  end;

   

  destructor TwdHintWnd.Destroy;

  begin

    FWndBmp.Free;

    FHintBmp.Free;

    inherited;

  end;

   

  procedure TwdHintWnd.GetDesktopImg(Bmp: TBitmap; R: TRect);

  var

    C: TCanvas;

  begin

    C:= TCanvas.Create;

    try

      C.Handle := GetDC(0);

      Bmp.Canvas.CopyRect(Rect(0, 0, Bmp.Width, Bmp.Height), C, R);

    finally

      C.Free;

    end;

  end;

   

  procedure TwdHintWnd.EffectHandle(WndBmp, HintBmp: TBitmap);

  var

    R: TRect;

    i, j: Integer;

    P: PByteArray;

    Transt, TranstAngle: Integer;

  begin

    R := Rect(0, 0, WndBmp.Width - 4, WndBmp.Height - 4);

    Frame3D(WndBmp.Canvas, R, clMedGray, clBtnShadow, 1);

    //作窗口底下的阴影效果

    Transt := 60;

    for j:= WndBmp.Height - 4 to WndBmp.Height - 1 do

    begin

      P := WndBmp.ScanLine[j];

      TranstAngle := Transt;

      for i:= 3 to WndBmp.Width - 1 do

      begin

        //如果正处于右下角

        if i WndBmp.Width - 5  then

        begin

          P[3*i] := P[3*i] * TranstAngle div 100;

          P[3*i + 1] := P[3*i + 1] * TranstAngle div 100;

          P[3*i + 2] := P[3*i + 2] * TranstAngle div 100;

          TranstAngle := TranstAngle + 10;

          if TranstAngle 90 then TranstAngle := 90;

        end

        else begin

          P[3*i] := P[3*i] * Transt div 100;

          P[3*i + 1] := P[3*i + 1] * Transt div 100;

          P[3*i + 2] := P[3*i + 2] * Transt div 100;

        end;

      end;

      Transt := Transt + 10;

    end;

    //作窗口右边的阴影效果

    for j := 3 to WndBmp.Height - 5 do

    begin

      P := WndBmp.ScanLine[j];

      Transt := 60;

      for i:= WndBmp.Width - 4 to WndBmp.Width -1 do

      begin

        P[3*i] := P[3*i] * Transt div 100;

        P[3*i + 1] := P[3*i + 1] * Transt div 100;

        P[3*i + 2] := P[3*i + 2] * Transt div 100;

        Transt := Transt + 10;

      end;

    end;

    WndBmp.Canvas.Draw(10, 10, HintBmp);

  end;

   

  procedure TwdHintWnd.NCPaint;

  begin

    //重载不让画边框

  end;

   

  procedure TwdHintWnd.Paint;

  begin

    Canvas.CopyRect(ClientRect, FWndBmp.Canvas, ClientRect);

  end;

   

  procedure TwdHintWnd.DrawHintImg(Bmp: TBitmap; AHint: string);

  var

    R: TRect;

  begin

    Bmp.Canvas.Brush.Color := Application.HintColor;

    Bmp.Canvas.Pen.Color := Application.HintColor;

    Bmp.Canvas.Rectangle(0, 0, Bmp.Width, Bmp.Height);

    Bmp.Canvas.Font.Color := Screen.HintFont.Color;

    R := Rect(0, 0, Bmp.Width, Bmp.Height);

    Inc(R.Left, 2);

    Inc(R.Top, 2);

    DrawText(Bmp.Canvas.Handle, PChar(AHint), -1, R, DT_LEFT or DT_NOPREFIX or

      DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);

  end;

   

  initialization

    Application.ShowHint := False;

    HintWindowClass := TwdHintWnd;

    Application.ShowHint := True;

   

  end.

  只需将该单元加入你的工程当中,然后运行程序,便可看到效果了,试试看,漂亮吧。

  程序中重要部分已经作了注释,这里只说明几个重要的地方,首先是initialization

  部分,这里将Application的ShowHint设为False,看一下VCL源码,知道Application将一个HintWindow给消毁了,而HintWindowClass定义如下:

  THintWindowClass = class of THintWindow;它是THintWindow的类引用,在Forms单元中它初始化为THintWindow:

  HintWindowClass: THintWindowClass = THintWindow;

  在这里我们将其替换为TwdHintWnd,最后将ShowHint设为True,Application便用HintWindowClass创建一个Hint窗口,此时创建的便是我们定制的类了,以后的提示窗口就将用我们上面的窗口来显示。

  在ActivateHint方法,我们将作效果的处理,原理是取得提示窗口在桌面上的位置对应的位图,然后画到提示窗口上,再将提示信息的位置拷贝到提示窗口中间,这样就有了透明的效果了。其次画出玻璃的边,最后在窗口右边和下边作阴影效果。

  关于阴影效果的实现,用到的是图像的Alpha技术,可以到网上找一找,这里就不多说了,只给出图像透明度的公式:

  Dst.Red    = Src.Red   * alpha + (1-alpha) * Dst.Red;

  Dst.Green  = Src.Green * alpha + (1-alpha) * Dst.Green;

  Dst.Blue   = Src.Blue  * alpha + (1-alpha) * Dst.Blue;

  Alpha的值为0到1之间,为1时表示完全不透明,不过我们将用于混合的颜色为黑色,即0,所以上面代码看到的是如下的样子:

  P[3*i] := P[3*i] * TranstAngle div 100;

  玻璃提示窗口的原理大概如此,当然其透明效果是一个假象,遇到后有动的物体就暴露无疑了。不过作为一个提示窗口,我想已经足够了。

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  
   

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

来源:https://www.tulaoshi.com/n/20160219/1626377.html

延伸阅读
标签: Delphi
  Delphi让你发送Flash电子邮件完整源代码: {******Unit1.pas源代码内容如下******} unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Psock, NMsmtp; type TForm1 = class(TForm) Label1: TLabel; txtTo: TEdit; Label2: TLabel; txtFrom: TEdit; La...
(续Delphi背后---初学者参考之二(1) )2 Windows API API(Application Programming Interface)应用编程接口,所有的计算机语言都要用到它。API是什么?API是程序使用操作系统提供的服务的一个途径,我们大多数的编程都不直接操作硬件,而是调用这些API,再由操作系统直接操作硬件,这样的好处是我们编程时不必考滤与硬件兼容的问题,更重...
在Delphi中实现将Font.Style写入INI文件 前不久我编写一个小程序在INI文件中记录字体的属性(颜色值/color,大小/size,字体名/name,样式/style),其中color值和size值可以用数值方式写入INI文件,name是用字符方式写入,但Font.style不是数值型、字符型,也不是布尔型,而是TfontStyles类,无法直接写入INI文件中去,我找了好多相关书...
Calling conventions(调用约定)    在声明过程或函数时,你可以使用下面的指示字之一来指明调用约定:register、pascal、cdecl、stdcall以及safecall。比如, function MyFunction(X, Y: Real): Real; cdecl; ...       调用约定决定了参数被传递给例程的顺序,...
1.规范简介?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 本规范主要规定Delphi源程序在书写过程中所应遵循的规则及注意事项。编写该规范的目的是使公司软件开发人员的源代码书写习惯保持一致。这样做可以使每一个组员都可以理解其它组员的代码,以便于源代码的二次开发记忆系统的维护。   ...

经验教程

706

收藏

73
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部