Delphi的Hint(2)

一路向北19800

一路向北19800

2016-02-19 21:31

下面是个简单易学的Delphi的Hint(2)教程,图老师小编详细图解介绍包你轻松学会,喜欢的朋友赶紧get起来吧!
上一篇介绍了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;

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

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

  
   

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)
展开更多 50%)
分享

猜你喜欢

Delphi的Hint(2)

编程语言 网络编程
Delphi的Hint(2)

Delphi的Hint(1)

编程语言 网络编程
Delphi的Hint(1)

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

实现Hint的分行提示

编程语言 网络编程
实现Hint的分行提示

关于VisiBroker For Delphi的使用(2)

Delphi
关于VisiBroker For Delphi的使用(2)

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

Delphi控件 我们也可以(2)

Delphi
Delphi控件 我们也可以(2)

Delphi学习:2个不错的通配符比较函数

Delphi
Delphi学习:2个不错的通配符比较函数

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

通过重定义CSS实现网页内容完美打印输出

通过重定义CSS实现网页内容完美打印输出

DELPHI面向对象支持特点--保护级类成员的应用

DELPHI面向对象支持特点--保护级类成员的应用
下拉加载更多内容 ↓