(一个不错的HINT控件)<br>unit Danhint;<br><br>interface<br><br>uses<br><br>SysUtils, Windows, Messages, Classes, Graphics, Controls,<br><br>Forms, Dialogs;<br><br>type<br><br>THintDirection=(hdUpRight,hdUpLeft,hdDownRight,hdDownLeft);<br><br>TOnSelectHintDirection=procedure(HintControl:TControl;var HintDirection:THintDirection) of object;<br><br>TDanHint = class(TComponent)<br><br>private<br><br>{ Private declarations }<br><br>FHintDirection:THintDirection;<br><br>FHintColor:TColor;<br><br>FHintShadowColor:TColor;<br><br>FHintFont:TFont;<br><br>FHintPauseTime:Integer;<br><br>FOnSelectHintDirection:TOnSelectHintDirection;<br><br>procedure SetHintDirection(Value:THintDirection);<br><br>procedure SetHintColor(Value:TColor);<br><br>procedure SetHintShadowColor(Value:TColor);<br><br>procedure SetHintFont(Value:TFont);<br><br>procedure CMFontChanged(var Message:TMessage); message CM_FONTCHANGED;<br><br>procedure SetHintPauseTime(Value:Integer);<br><br>protected<br><br>{ Protected declarations }<br><br>public<br><br>{ Public declarations }<br><br>constructor Create(AOwner:TComponent);override;<br><br>destructor Destroy;override;<br><br>procedure Loaded;override;<br><br>procedure SetNewHintFont;<br><br>published<br><br>{ Published declarations }<br><br>property HintDirection:THintDirection read FHintDirection write SetHintDirection default hdUpRight;<br><br>property HintColor:TColor read FHintColor write SetHintColor default clYellow;<br><br>property HintShadowColor:TColor read FHintShadowColor write SetHintShadowColor default clPurple;<br><br>property HintFont:TFont read FHintFont write SetHintFont;<br><br>property HintPauseTime:Integer read FHintPauseTime write SetHintPauseTime default 600;<br><br>property OnSelectHintDirection:TOnSelectHintDirection read FOnSelectHintDirection write FOnSelectHintDirection;<br><br>end;<br><br>TNewHint = class(THintWindow)<br><br>private<br><br>{ Private declarations }<br><br>FDanHint:TDanHint;<br><br>FHintDirection:THintDirection;<br><br>procedure SelectProperHintDirection(ARect:TRect);<br><br>procedure CheckUpRight(Spot:TPoint);<br><br>procedure CheckUpLeft(Spot:TPoint);<br><br>procedure CheckDownRight(Spot:TPoint);<br><br>procedure CheckDownLeft(Spot:TPoint);<br><br>function FindDanHint:TDanHint;<br><br>function FindCursorControl:TControl;<br><br>protected<br><br>{ Protected declarations }<br><br>procedure Paint;override;<br><br>procedure CreateParams(var Params: TCreateParams);override;<br><br>public<br><br>{ Public declarations }<br><br>constructor Create(AOwner:TComponent);override;<br><br>destructor Destroy;override;<br><br>procedure ActivateHint(Rect: TRect; const AHint: string);override;<br><br>property HintDirection:THintDirection read FHintDirection write FHintDirection default hdUpRight;<br><br>published<br><br>{ Published declarations }<br><br>end;<br><br>procedure Register;<br><br>implementation<br><br>const<br><br>SHADOW_WIDTH=6;<br><br>N_PIXELS=5;<br><br>var<br><br>MemBmp:TBitmap;<br><br>UpRect,DownRect:TRect;<br><br>SelectHintDirection:THintDirection;<br><br>ShowPos:TPoint;<br><br>procedure Register;<br><br>begin<br><br>RegisterComponents('ActiveX', [TDanHint]);<br><br>end;<br><br>procedure TDanHint.SetNewHintFont;<br><br>var<br><br>I:Integer;<br><br>begin<br><br>for I:=0 to Application.ComponentCount-1 do<br><br>if Application.Components is TNewHint then<br><br>begin<br><br>TNewHint(Application.Components).Canvas.Font.Assign(FHintFont);<br><br>Exit;<br><br>end;<br><br>end;<br><br>constructor TDanHint.Create(AOwner:TComponent);<br><br>begin<br><br>inherited Create(AOwner);<br><br>FHintDirection:=hdUpRight;<br><br>FHintColor:=clYellow;<br><br>{ $0080FFFF is Delphi's original setting }<br><br>FHintShadowColor:=clPurple;<br><br>FHintPauseTime:=600;<br><br>Application.HintPause:=FHintPauseTime;<br><br>FHintFont:=TFont.Create;<br><br>FHintFont.Name:='MS Sans Serif';<br><br>FHintFont.Size:=12;<br><br>FHintFont.Color:=clBlue;<br><br>FHintFont.Pitch:=fpDefault;<br><br>FHintFont.Style:=FHintFont.Style+[fsBold,fsItalic];<br><br>if not (csDesigning in ComponentState) then<br><br>begin<br><br>HintWindowClass:=TNewHint;<br><br>Application.ShowHint:=not Application.ShowHint;<br><br>Application.ShowHint:=not Application.ShowHint;<br><br>{ in TApplication's SetShowHint, the private<br><br>FHintWindow is allocated according to<br><br>HintWindowClass, so here do so actions to<br><br>call SetShowHint and keep ShowHint property<br><br>the same value }<br><br>SetNewHintFont;<br><br>end;<br><br>end;<br><br>destructor TDanHint.Destroy;<br><br>begin<br><br>FHintFont.Free;<br><br>inherited Destroy;<br><br>end;<br><br>procedure TDanHint.Loaded;<br><br>begin<br><br>if not (csDesigning in ComponentState) then<br><br>begin<br><br>inherited Loaded;<br><br>HintWindowClass:=TNewHint;<br><br>Application.ShowHint:=not Application.ShowHint;<br><br>Application.ShowHint:=not Application.ShowHint;<br><br>{ to activate to allocate a new Hint Window }<br><br>SetNewHintFont;<br><br>end;<br><br>end;<br><br>procedure TDanHint.SetHintDirection(Value:THintDirection);<br><br>begin<br><br>FHintDirection:=Value;<br><br>end;<br><br>procedure TDanHint.SetHintColor(Value:TColor);<br><br>begin<br><br>FHintColor:=Value;<br><br>end;<br><br>procedure TDanHint.SetHintShadowColor(Value:TColor);<br><br>begin<br><br>FHintShadowColor:=Value;<br><br>end;<br><br>procedure TDanHint.SetHintFont(Value:TFont);<br><br>begin<br><br>FHintFont.Assign(Value);<br><br>Application.ShowHint:=not Application.ShowHint;<br><br>Application.ShowHint:=not Application.ShowHint;<br><br>{ to activate to allocate a new Hint Window }<br><br>SetNewHintFont;<br><br>end;<br><br>procedure TDanHint.CMFontChanged(var Message:TMessage);<br><br>begin<br><br>inherited;<br><br>Application.ShowHint:=not Application.ShowHint;<br><br>Application.ShowHint:=not Application.ShowHint;<br><br>{ to activate to allocate a new Hint Window }<br><br>SetNewHintFont;<br><br>end;<br><br>procedure TDanHint.SetHintPauseTime(Value:Integer);<br><br>begin<br><br>if (Value<>FHintPauseTime) then<br><br>begin<br><br>FHintPauseTime:=Value;<br><br>Application.HintPause:=Value;<br><br>end;<br><br>end;<br><br>function TNewHint.FindDanHint:TDanHint;<br><br>var<br><br>I:Integer;<br><br>begin<br><br>Result:=nil;<br><br>for I:=0 to Application.MainForm.ComponentCount-1 do<br><br>if Application.MainForm.Components is TDanHint then<br><br>begin<br><br>Result:=TDanHint(Application.MainForm.Components);<br><br>Exit;<br><br>end;<br><br>end;<br><br>constructor TNewHint.Create(AOwner:TComponent);<br><br>begin<br><br>inherited Create(AOwner);<br><br>{if (Application<>nil) and (Application.MainForm<>nil) then<br><br>FDanHint:=FindDanHint;}<br><br>ControlStyle:=ControlStyle-[csOpaque];<br><br>with Canvas do<br><br>begin<br><br>{ Font.Name:='MS Sans Serif';<br><br>Font.Size:=10;}<br><br>{if (FDanHint<>nil) then Font.Assign(FDanHint.HintFont);}<br><br>Brush.Style:=bsClear;<br><br>Brush.Color:=clBackground;<br><br>Application.HintColor:=clBackground;<br><br>end;<br><br>FHintDirection:=hdUpRight;<br><br>end;<br><br>destructor TNewHint.Destroy;<br><br>begin<br><br>inherited Destroy;<br><br>end;<br><br>procedure TNewHint.CreateParams(var Params: TCreateParams);<br><br>begin<br><br>inherited CreateParams(Params);<br><br>with Params do<br><br>begin<br><br>{Style := WS_POPUP or WS_BORDER or WS_DISABLED;}<br><br>Style := Style-WS_BORDER;<br><br>{ExStyle:=ExStyle or WS_EX_TRANSPARENT;}<br><br>{Add the above makes the beneath window overlap hint}<br><br>WindowClass.Style := WindowClass.Style or CS_SAVEBITS;<br><br>end;<br><br>end;<br><br>procedure TNewHint.Paint;<br><br>var<br><br>R: TRect;<br><br>CCaption: array[0..255] of Char;<br><br>FillRegion,ShadowRgn:HRgn;<br><br>AP:array[0..2] of TPoint; { Points of the Arrow }<br><br>SP:array[0..2] of TPoint; { Points of the Shadow }<br><br>X,Y:Integer;<br><br>AddNum:Integer; { Added num for hdDownXXX }<br><br>begin<br><br>R := ClientRect;<br><br>{ R is for Text output }<br><br>Inc(R.Left,5+3);<br><br>Inc(R.Top,3);<br><br>AddNum:=0;<br><br>if FHintDirection>=hdDownRight then AddNum:=15;<br><br>Inc(R.Top,AddNum);<br><br>case HintDirection of<br><br>hdUpRight:begin<br><br>AP[0]:=Point(10,Height-15);<br><br>AP[1]:=Point(20,Height-15);<br><br>AP[2]:=Point(0,Height);<br><br>SP[0]:=Point(12,Height-15);<br><br>SP[1]:=Point(25,Height-15);<br><br>SP[2]:=Point(12,Height);<br><br>end;<br><br>hdUpLeft:begin<br><br>AP[0]:=Point(Width-SHADOW_WIDTH-20,Height-15);<br><br>AP[1]:=Point(Width-SHADOW_WIDTH-10,Height-15);<br><br>AP[2]:=Point(Width-SHADOW_WIDTH,Height);<br><br>SP[0]:=Point(Width-SHADOW_WIDTH-27,Height-15);<br><br>SP[1]:=Point(Width-SHADOW_WIDTH-5,Height-15);<br><br>SP[2]:=Point(Width-SHADOW_WIDTH,Height);<br><br>end;<br><br>hdDownRight:begin<br><br>AP[0]:=Point(10,15);<br><br>AP[1]:=Point(20,15);<br><br>AP[2]:=Point(0,0);<br><br>{ for hdDownXXX, SP not used now }<br><br>SP[0]:=Point(12,Height-15);<br><br>SP[1]:=Point(25,Height-15);<br><br>SP[2]:=Point(12,Height);<br><br>end;<br><br>hdDownLeft:begin<br><br>AP[0]:=Point(Width-SHADOW_WIDTH-20,15);<br><br>AP[1]:=Point(Width-SHADOW_WIDTH-10,15);<br><br>AP[2]:=Point(Width-SHADOW_WIDTH,0);<br><br>{ for hdDownXXX, SP not used now }<br><br>SP[0]:=Point(12,Height-15);<br><br>SP[1]:=Point(25,Height-15);<br><br>SP[2]:=Point(12,Height);<br><br>end;<br><br>end;<br><br>{ Draw Shadow of the Hint Rect}<br><br>if (FHintDirection<=hdUpLeft) then<br><br>begin<br><br>ShadowRgn:=CreateRoundRectRgn(0+10,0+8,Width,Height-9,8,8);<br><br>{ 8 is for RoundRect's corner }<br><br>for X:=Width-SHADOW_WIDTH-8 to Width do<br><br>for Y:=8 to Height-14 do<br><br>begin<br><br>if (Odd(X)=Odd(Y)) and PtInRegion(ShadowRgn,X,Y) then<br><br>MemBmp.Canvas.Pixels[X,Y]:=FDanHint.HintShadowColor;<br><br>end;<br><br>for X:=10 to Width do<br><br>for Y:=Height-14 to Height-9 do<br><br>begin<br><br>if (Odd(X)=Odd(Y)) and PtInRegion(ShadowRgn,X,Y) then<br><br>MemBmp.Canvas.Pixels[X,Y]:=FDanHint.HintShadowColor;<br><br>end;<br><br>end<br><br>else { for hdDownXXX }<br><br>begin<br><br>ShadowRgn:=CreateRoundRectRgn(0+10,0+8+15,Width,Height-2,8,8);<br><br>for X:=Width-SHADOW_WIDTH-8 to Width do<br><br>for Y:=23 to Height-8 do<br><br>begin<br><br>if (Odd(X)=Odd(Y)) and PtInRegion(ShadowRgn,X,Y) then<br><br>MemBmp.Canvas.Pixels[X,Y]:=FDanHint.HintShadowColor;<br><br>end;<br><br>for X:=10 to Width do<br><br>for Y:=Height-8 to Height-2 do<br><br>begin<br><br>if (Odd(X)=Odd(Y)) and PtInRegion(ShadowRgn,X,Y) then<br><br>MemBmp.Canvas.Pixels[X,Y]:=FDanHint.HintShadowColor;<br><br>end;<br><br>end;<br><br>DeleteObject(ShadowRgn);<br><br>{ Draw the shadow of the arrow }<br><br>if (HintDirection<=hdUpLeft) then<br><br>begin<br><br>ShadowRgn:=CreatePolygonRgn(SP,3,WINDING);<br><br>for X:=SP[0].X to SP[1].X do<br><br>for Y:=SP[0].Y to SP[2].Y do<br><br>begin<br><br>if (Odd(X)=Odd(Y)) and PtInRegion(ShadowRgn,X,Y) then<br><br>MemBmp.Canvas.Pixels[X,Y]:=FDanHint.HintShadowColor;<br><br>end;<br><br>DeleteObject(ShadowRgn);<br><br>end;<br><br>{ Draw HintRect }<br><br>MemBmp.Canvas.Pen.Color:=clBlack;<br><br>MemBmp.Canvas.Pen.Style:=psSolid;<br><br>MemBmp.Canvas.Brush.Color:=FDanHint.HintColor;<br><br>MemBmp.Canvas.Brush.Style:=bsSolid;<br><br>if (FHintDirection<=hdUpLeft) then<br><br>MemBmp.Canvas.RoundRect(0,0,Width-SHADOW_WIDTH,Height-14,9,9)<br><br>else<br><br>MemBmp.Canvas.RoundRect(0,0+AddNum,Width-SHADOW_WIDTH,Height-14+6,9,9);<br><br>{ Draw Hint Arrow }<br><br>MemBmp.Canvas.Pen.Color:=FDanHint.HintColor;<br><br>MemBmp.Canvas.MoveTo(AP[0].X,AP[0].Y);<br><br>MemBmp.Canvas.LineTo(AP[1].X,AP[1].Y);<br><br>MemBmp.Canvas.Pen.Color:=clBlack;<br><br>FillRegion:=CreatePolygonRgn(AP,3,WINDING);<br><br>FillRgn(MemBmp.Canvas.Handle,FillRegion,MemBmp.Canvas.Brush.Handle);<br><br>DeleteObject(FillRegion);<br><br>MemBmp.Canvas.LineTo(AP[2].X,AP[2].Y);<br><br>MemBmp.Canvas.LineTo(AP[0].X,AP[0].Y);<br><br>{ SetBkMode makes DrawText's text be transparent }<br><br>SetBkMode(MemBmp.Canvas.Handle,TRANSPARENT);<br><br>MemBmp.Canvas.Font.Assign(FDanHint.HintFont);<br><br>DrawText(MemBmp.Canvas.Handle, StrPCopy(CCaption, Caption), -1, R,<br><br>DT_LEFT or DT_NOPREFIX or DT_WORDBREAK);<br><br>Canvas.CopyMode:=cmSrcCopy;<br><br>Canvas.CopyRect(ClientRect,MemBmp.Canvas,ClientRect);<br><br>MemBmp.Free;<br><br>end;<br><br>procedure TNewHint.CheckUpLeft(Spot:TPoint);<br><br>var<br><br>Width,Height:Integer;<br><br>begin<br><br>Dec(Spot.Y,N_PIXELS);<br><br>Width:=UpRect.Right-UpRect.Left;<br><br>Height:=UpRect.Bottom-UpRect.Top;<br><br>SelectHintDirection:=hdUpLeft;<br><br>if (Spot.X+SHADOW_WIDTH-Width)<0 then<br><br>begin<br><br>Inc(Spot.Y,N_PIXELS);{back tp original}<br><br>CheckUpRight(Spot);<br><br>Exit;<br><br>end;<br><br>if (Spot.Y-Height)<0 then<br><br>begin<br><br>Inc(Spot.Y,N_PIXELS);<br><br>CheckDownLeft(Spot);<br><br>Exit;<br><br>end;<br><br>ShowPos.X:=Spot.X+SHADOW_WIDTH-Width;<br><br>ShowPos.Y:=Spot.Y-Height;<br><br>end;<br><br>procedure TNewHint.CheckUpRight(Spot:TPoint);<br><br>var<br><br>Width,Height:Integer;<br><br>begin<br><br>Dec(Spot.Y,N_PIXELS);<br><br>Width:=UpRect.Right-UpRect.Left;<br><br>Height:=UpRect.Bottom-UpRect.Top;<br><br>SelectHintDirection:=hdUpRight;<br><br>if (Spot.X+Width)>Screen.Width then<br><br>begin<br><br>Inc(Spot.Y,N_PIXELS);<br><br>CheckUpLeft(Spot);<br><br>Exit;<br><br>end;<br><br>if (Spot.Y-Height)<0 then<br><br>begin<br><br>Inc(Spot.Y,N_PIXELS);<br><br>CheckDownRight(Spot);<br><br>Exit;<br><br>end;<br><br>ShowPos.X:=Spot.X;<br><br>ShowPos.Y:=Spot.Y-Height;<br><br>end;<br><br>procedure TNewHint.CheckDownRight(Spot:TPoint);<br><br>var<br><br>Width,Height:Integer;<br><br>begin<br><br>Inc(Spot.Y,N_PIXELS*3);<br><br>Width:=DownRect.Right-DownRect.Left;<br><br>Height:=DownRect.Bottom-DownRect.Top;<br><br>SelectHintDirection:=hdDownRight;<br><br>if (Spot.X+Width)>Screen.Width then<br><br>begin<br><br>Dec(Spot.Y,N_PIXELS*3);<br><br>CheckDownLeft(Spot);<br><br>Exit;<br><br>end;<br><br>if (Spot.Y+Height)>Screen.Height then<br><br>begin<br><br>Dec(Spot.Y,N_PIXELS*3);<br><br>CheckUpRight(Spot);<br><br>Exit;<br><br>end;<br><br>ShowPos.X:=Spot.X;<br><br>ShowPos.Y:=Spot.Y;<br><br>end;<br><br>procedure TNewHint.CheckDownLeft(Spot:TPoint);<br><br>var<br><br>Width,Height:Integer;<br><br>begin<br><br>Inc(Spot.Y,N_PIXELS*3);<br><br>Width:=DownRect.Right-DownRect.Left;<br><br>Height:=DownRect.Bottom-DownRect.Top;<br><br>SelectHintDirection:=hdDownLeft;<br><br>if (Spot.X+SHADOW_WIDTH-Width)<0 then<br><br>begin<br><br>Dec(Spot.Y,N_PIXELS*3);<br><br>CheckDownRight(Spot);<br><br>Exit;<br><br>end;<br><br>if (Spot.Y+Height)>Screen.Height then<br><br>begin<br><br>Dec(Spot.Y,N_PIXELS*3);<br><br>CheckUpLeft(Spot);<br><br>Exit;<br><br>end;<br><br>ShowPos.X:=Spot.X+SHADOW_WIDTH-Width;<br><br>ShowPos.Y:=Spot.Y;<br><br>end;<br><br>function TNewHint.FindCursorControl:TControl;<br><br>begin<br><br>{ControlAtPos}<br><br>end;<br><br>procedure TNewHint.SelectProperHintDirection(ARect:TRect);<br><br>var<br><br>Spot:TPoint;<br><br>OldHintDirection,SendHintDirection:THintDirection;<br><br>HintControl:TControl;<br><br>begin<br><br>GetCursorPos(Spot);<br><br>HintCOntrol:=FindDragTarget(Spot,True);<br><br>Inc(ARect.Right,10+SHADOW_WIDTH);<br><br>Inc(ARect.Bottom,20);<br><br>UpRect:=ARect;<br><br>Inc(ARect.Bottom,9);<br><br>DownRect:=ARect;<br><br>OldHintDirection:=FDanHint.HintDirection;<br><br>SendHintDirection:=FDanHint.HintDirection;<br><br>{ Tricky, why here can't use FDanHint.OnSe...? }<br><br>if Assigned(FDanHint.FOnSelectHintDirection) then<br><br>begin<br><br>FDanHint.FOnSelectHintDirection(HintControl,SendHintDirection);<br><br>FDanHint.HintDirection:=SendHintDirection;<br><br>end;<br><br>case FDanHint.HintDirection of<br><br>hdUpRight:CheckUpRight(Spot);<br><br>hdUpLeft:CheckUpLeft(Spot);<br><br>hdDownRight:CheckDownRight(Spot);<br><br>hdDownLeft:CheckDownLeft(Spot);<br><br>end;<br><br>FDanHint.HintDirection:=OldHintDirection;<br><br>end;<br><br>procedure TNewHint.ActivateHint(Rect: TRect; const AHint: string);<br><br>var<br><br>ScreenDC:HDC;<br><br>LeftTop:TPoint;<br><br>tmpWidth,tmpHeight:Integer;<br><br>begin<br><br>MemBmp:=TBitmap.Create;<br><br>Caption := AHint;<br><br>{ add by Dan from Here }<br><br>FDanHint:=FindDanHint;<br><br>SelectProperHintDirection(Rect);<br><br>HintDirection:=SelectHintDirection;<br><br>{ if the following changes, make sure to modify<br><br>SelectProperHintDirection also }<br><br>Inc(Rect.Right,10+SHADOW_WIDTH);<br><br>Inc(Rect.Bottom,20);<br><br>if (FHintDirection>=hdDownRight) then Inc(Rect.Bottom,9);<br><br>{ to expand the rect }<br><br>tmpWidth:=Rect.Right-Rect.Left;<br><br>tmpHeight:=Rect.Bottom-Rect.Top;<br><br>Rect.Left:=ShowPos.X;<br><br>Rect.Top:=ShowPos.Y;<br><br>Rect.Right:=Rect.Left+tmpWidth;<br><br>Rect.Bottom:=Rect.Top+tmpHeight;<br><br>BoundsRect := Rect;<br><br>MemBmp.Width:=Width;<br><br>MemBmp.Height:=Height;<br><br>ScreenDC:=CreateDC('DISPLAY',nil,nil,nil);<br><br>LeftTop.X:=0;<br><br>LeftTop.Y:=0;<br><br>LeftTop:=ClientToScreen(LeftTop);<br><br>{ use MemBmp to store the original bitmap<br><br>on screen }<br><br>BitBlt(MemBmp.Canvas.Handle,0,0,Width,Height,ScreenDC,<br><br>LeftTop.X,LeftTop.Y,SRCCOPY);<br><br>{ SetBkMode(Canvas.Handle,TRANSPARENT);}<br><br>SetWindowPos(Handle, HWND_TOPMOST, ShowPos.X, ShowPos.Y, 0,<br><br>0, SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOSIZE);<br><br>BitBlt(Canvas.Handle,0,0,Width,Height,MemBmp.Canvas.Handle,<br><br>0,0,SRCCOPY);<br><br>DeleteDC(ScreenDC);<br><br>end;<br><br>initialization<br><br>end.