定時顯示提示信息(TToolTip)

{
    修改者:ghs
    日期:20071218
    功能:在原版本的基礎上增長。
          RegisterControl:註冊須要提示的控件。
          BeginHelp:設置光標狀態爲幫助crHelp;
          鼠標彈起後,顯示註冊的提示信息,同時光標進行還原。
          
   原版本
   做者:thaoqi
   出處:http://www.2ccc.com/article.asp?articleid=4389
   功能:首先謝謝xsherry大大,來盒子很長一段時間了,總是下東西,沒有爲盒子作什麼貢獻。
        前段時間xsherry大大拋磚引玉的文章,給我啓發很大,最近一個項目提出要求人
        機交互界面更加有好,儘可能少用MessageBox,因此在他的基礎上,我試圖模仿XP
        登陸時候的那個ToolTip提示功能,用API摸索出一個符合要求的ToolTip提示框出
        來,最後我把實現的函數封裝成了一個VCL的控件,但願你們能多提意見!
}
unit TooltipUtil;

interface

uses Messages, Windows, SysUtils, Classes, Contnrs, Controls, CommCtrl,
  StdCtrls, ExtCtrls, Consts, Forms, Dialogs, AppEvnts;

type
  TTipTool_ICON = (ttNoneIcon, ttInformationIcon, ttWarningIcon, ttStopIcon);
  TTipAlignment = (taLeft, taCenter, taRight);

  PTipInfo = ^TTipInfo;
  
  TTipInfo = packed record
    WinControl: TWinControl;
    Handle: THandle;
    Caption: string;
    Msg: string;
    TipICON: TTipTool_ICON;
    TipAlg: TTipAlignment;
    Cursor: TCursor;
  end;
  
  TToolTip = class(TComponent)
  private
    fTitle: string;
    fText: string;
    fEnabled: Boolean;
    fWindowHandle: HWND;
    fTipHandle: HWND;
    fInterval: Cardinal;
    fToolInfo: TToolInfo;
    fAlignment: TTipAlignment;
    fTipIcon: TTipTool_ICON;
    fControl: TWinControl;
    //
    Flist: TList;
    ApplicationEvents: TApplicationEvents;
    FLastHandle: THandle;
    
    procedure SetText(AText: string); //設置氣泡提示信息
    procedure SetTitle(ATitle: string); //設置氣泡提示的標題

    procedure UpdateTime; //更新計時器狀態
    procedure WndProc(var Msg: TMessage); //接收windows消息
  protected
    //攔截消息=處理左鍵彈起
    procedure ApplicationEvents1Message(var Msg: tagMSG;
      var Handled: Boolean);
    //結束幫助=設置光標爲控件原本狀態  
    procedure EndHelp;  
  public
    constructor Create(AOwner: TComponent); override; //構造函數,建立實例
    destructor Destroy; override; //析構函數,銷燬實例
    //註冊控件信息
    procedure RegisterControl(WinControl: TWinControl; aCaption, aMsg: string;
      TipICON: TTipTool_ICON = ttInformationIcon; TipAlignment: TTipAlignment = taLeft);
    //開始幫助=設置光標狀態
    procedure BeginHelp;
    procedure Popup(Handle: HWND); overload; //在指定的句柄中彈出氣泡(重載)
    procedure Popup(Handle: HWND; IconType: TTipTool_ICON; Title,
      Text: string); overload; //在指定的句柄中彈出氣泡(重載)
      
  published
      //氣泡窗體的窗體句柄
    property Handle: HWND read fTipHandle;
      //氣泡窗體的提示信息
    property Text: string read fText write SetText;
      //氣泡窗體的標題信息
    property Title: string read fTitle write SetTitle;
      //氣泡窗體的信息圖標
    property ICON: TTipTool_ICON read fTipIcon write fTipIcon;
      //氣泡窗體彈出時對齊位置
    property Alignment: TTipAlignment read fAlignment write fAlignment default taLeft;
      //氣泡窗體的顯示時間
    property Interval: Cardinal read fInterval write fInterval default 1000;
  end;

procedure Register;

implementation

const
  TTS_BALLOON = $0040; //ToolTip提示窗口的外形,指定爲氣球型
  TTS_CLOSE = $0080; //關閉按鈕
  TTF_PARSELINKS = $1000; //可以使用超連接
  TTM_SETTITLE = WM_USER + 32; //社這提示標題信息的消息

constructor TToolTip.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  if not (AOwner is TWinControl) then
  begin
    raise exception.Create('TToolTip''s owner must be a ''TWinControl'' type.');
    Destroy;
  end;

  fWindowHandle := Classes.AllocateHWnd(WndProc);

  fEnabled := False;
  fInterval := 1000;

  //建立氣泡提示窗口
  fTipHandle := CreateWindow(TOOLTIPS_CLASS, nil,
    WS_POPUP or TTS_NOPREFIX or
    TTS_BALLOON or TTS_ALWAYSTIP, // or TTS_CLOSE,
    0, 0, 0, 0, fWindowHandle,
    0, HInstance, nil);

  if fTipHandle <> 0 then
  begin
    //設置ToolInfo的大小
    fToolInfo.cbSize := SizeOf(fToolInfo);
    //設置基本風格
    fToolInfo.uFlags := TTF_PARSELINKS or TTF_IDISHWND or TTF_TRACK;
    //設置全部者的句柄
    fToolInfo.uId := fWindowHandle;
  end;
  Flist := TList.Create;
  ApplicationEvents := TApplicationEvents.Create(nil);
  ApplicationEvents.OnMessage := ApplicationEvents1Message;
end;

destructor TToolTip.Destroy;
var
  I: Integer;
  tmpTipInfo: PTipInfo;
begin
  if fTipHandle <> 0 then
    CloseWindow(fTipHandle);
  for I := Flist.Count - 1 downto 0 do    // Iterate
  begin
    tmpTipInfo := PTipInfo(FList.Items[i]);
    Dispose(tmpTipInfo);
  end;    // for
  Flist.Free;
  ApplicationEvents.Free;
  inherited Destroy;
end;

procedure TToolTip.SetText(AText: string);
begin
  fText := AText;

  if fTipHandle <> 0 then
  begin
    //設置標題信息
    fToolInfo.lpszText := PAnsiChar(fText);
    //向氣泡窗體發送消息,將ToolInfo的信息設置到氣泡窗體中
    SendMessage(fTipHandle, TTM_ADDTOOL, 0, Integer(@fToolInfo));
    SendMessage(fTipHandle, TTM_SETTOOLINFO, 0, Integer(@fToolInfo));
  end;
end;

procedure TToolTip.SetTitle(ATitle: string);
begin
  fTitle := ATitle;

  if fTipHandle <> 0 then
    //設置氣泡窗體的提示圖標和標題信息
    SendMessage(fTipHandle, TTM_SETTITLE, Integer(fTipIcon), Integer(fTitle));
end;

procedure TToolTip.Popup(Handle: HWND);
var
  tmpRect: TRect;
  x, y: word;
begin
  x := 0;

  fControl := FindControl(Handle);
  if fControl.Hint <> '' then
    fControl.ShowHint := False;

  //獲得須要顯示窗體所在的屏幕區域
  GetWindowRect(Handle, tmpRect);

  //計算顯示區域位置的座標
  with tmpRect do
  begin
    y := (Bottom - Top) div 2 + Top;

    case fAlignment of
      taLeft: x := Left;
      taCenter: x := (Right - Left) div 2 + Left;
      taRight: x := Right;
    end;
  end;

  //設置氣泡窗體彈出的座標
  SendMessage(fTipHandle, TTM_TRACKPOSITION, 0, MAKELONG(x, y));
  //激活氣泡窗體,並顯示出來
  SendMessage(fTipHandle, TTM_TRACKACTIVATE, Integer(True), Integer(@fToolInfo));

  fEnabled := True;
  //更新計時器狀態
  UpdateTime;
end;

procedure TToolTip.WndProc(var Msg: TMessage);
begin
  fEnabled := False;

  with Msg do
  begin
    case Msg of
      WM_TIMER:
      try
        SendMessage(fTipHandle, TTM_TRACKACTIVATE,
          Integer(False), Integer(@fToolInfo));
        if fControl.Hint <> '' then
          fControl.ShowHint := True;
      except
        Application.HandleException(Self);
      end;
    else
      Result := DefWindowProc(fWindowHandle, Msg, wParam, lParam);
    end;  
  end;
  //更新計時器狀態
  UpdateTime;
end;

procedure TToolTip.Popup(Handle: HWND; IconType: TTipTool_ICON;
  Title: string; Text: string);
begin
  fTipIcon := IconType;

  SetTitle(Title);
  SetText(Text);

  Popup(Handle);
end;

procedure TToolTip.UpdateTime;
begin
  KillTimer(fWindowHandle, 1);
  if (FInterval <> 0) and FEnabled then
    if SetTimer(fWindowHandle, 1, FInterval, nil) = 0 then
      raise EOutOfResources.Create(SNoTimers);
end;

procedure Register;
begin
  RegisterComponents('ToolTip', [TToolTip]);
end;

procedure TToolTip.RegisterControl(WinControl: TWinControl; aCaption, aMsg: string;
  TipICON: TTipTool_ICON = ttInformationIcon; TipAlignment: TTipAlignment = taLeft);
var
  TipInfo: PTipInfo;  
begin
  New(TipInfo);
  TipInfo.WinControl := WinControl;
  TipInfo.Handle := WinControl.Handle;
  TipInfo.Caption := aCaption;
  Tipinfo.Msg := aMsg;
  TipInfo.TipICON := TipICON;
  TIpInfo.TipAlg := TipAlignment;
  TipInfo.Cursor := WinControl.Cursor;
  
  Flist.Add(TipInfo);
end;

procedure TToolTip.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  I: Integer;
  tmpTipInfo: PTipInfo;
  tmpPoint: TPoint;
  tmpHandle: THandle;
begin
  if Msg.message = WM_LBUTTONUP then
  begin
    GetCurSorPos(tmpPoint);
    tmpHandle := WindowFromPoint(tmpPoint);
    if FLastHandle <> tmpHandle then //防止不停觸發
    begin
      FLastHandle := tmpHandle;
      for I := 0 to FList.Count - 1 do    // Iterate
      begin
        tmpTipInfo := PTipInfo(FList.Items[i]);
        //只有調用了BeginHelp,纔會彈出提示窗口
        if (tmpTipInfo.Handle = tmpHandle) and (tmpTipInfo.WinControl.Cursor = crHelp) then
        begin
          Popup(tmpHandle, tmpTipInfo.TipICON, tmpTipInfo.Caption, tmpTipInfo.Msg);
          break;
        end;
      end;    // for
      EndHelp;
      DefWindowProc(Msg.hwnd, Msg.message, Msg.wParam, Msg.lParam);  
    end;
  end;

end;

procedure TToolTip.BeginHelp;
var
  i: Integer;
  tmpTipInfo: PTipInfo;
begin
  for I := 0 to FList.Count - 1 do    // Iterate
  begin
    tmpTipInfo := PTipInfo(FList.Items[i]);
    tmpTipInfo.WinControl.Cursor := crHelp;
  end;    // for
end;

procedure TToolTip.EndHelp;
var
  i: Integer;
  tmpTipInfo: PTipInfo;
begin
  for I := 0 to FList.Count - 1 do    // Iterate
  begin
    tmpTipInfo := PTipInfo(FList.Items[i]);
    tmpTipInfo.WinControl.Cursor := tmpTipInfo.Cursor;
  end;    // for
end;

end.


調用一:

if edt3.Text='' then
  begin
    tltp1.Popup(TWinControl(edt3).Handle, ttStopIcon,'提示','請輸入產地');
    Exit;
  end;

調用二:

ToolTip1.RegisterControl(LabeledEdit1, '提示', '請輸入用戶名');
ToolTip1.BeginHelp;
相關文章
相關標籤/搜索