├── Lib ├── BTT.ahk ├── Gdip_all.ahk └── NonNull.ahk ├── README.md ├── benchmark.ahk ├── example 1.ahk ├── example 2.ahk ├── example 3.ahk ├── example 4.ahk ├── example 5.ahk ├── example 6.ahk ├── example 7.ahk ├── example 8.ahk ├── img ├── 1.png ├── 10.png ├── 11.png ├── 2.gif ├── 3.gif ├── 4.gif ├── 5.gif ├── 6.gif ├── 7.gif ├── 8.gif └── 9.gif └── unit test ├── test1.ahk ├── test2.ahk ├── test3.ahk └── test4.ahk /Lib/BTT.ahk: -------------------------------------------------------------------------------- 1 | /* 2 | https://github.com/telppa/BeautifulToolTip 3 | 4 | If you want to add your own style to the built-in style, you can add it directly in btt(). 5 | 6 | version: 7 | 2021.10.03 8 | 9 | changelog: 10 | 2021.10.03 11 | 改变 Include 方式,降低库冲突的可能性。 12 | 2021.09.29 13 | 支持设置 TabStops 。 14 | 除 GDIP 库外所有函数内置到 Class 中,降低库冲突的可能性。 15 | 2021.04.30 16 | 修复 Win7 下不能运行的 bug 。(2021.04.20 引起) 17 | 2021.04.20 18 | 支持根据显示器 DPI 缩放比例自动缩放,与 ToolTip 特性保持一致。 19 | 支持直接使用未安装的本地字体。 20 | Options 增加 JustCalculateSize 参数,可在不绘制内容的前提下直接返回尺寸。 21 | 2021.03.07 22 | 增加 4 种渐变模式。 23 | 2021.03.05 24 | 删除渐变方向参数。 25 | 增加渐变角度参数,支持 360° 渐变。 26 | 增加渐变模式参数,支持 4 种模式。 27 | 2021.03.03 28 | 文本色支持渐变。 29 | 增加 Style8 。 30 | 增加 3 个渐变方向。 31 | 2021.03.02 32 | 细边框色支持渐变。 33 | 增加 Style7 。 34 | 增加 2 个渐变方向。 35 | 2021.03.01 36 | BTT 的总在最上级别现在跟 ToolTip 一样高了。 37 | 解决 BTT 被不明原因置底导致误以为没显示的问题。 38 | 增加 Style6 。 39 | 文字显示更加居中。 40 | 2021.02.22 41 | 增加返回值。 42 | Options 增加 Transparent 参数,可直接设置整体透明度。 43 | 44 | todo: 45 | 指定高宽 46 | 文字可获取 47 | 降低内存消耗 48 | 阴影 49 | ANSI版本的支持 50 | 文字太多导致没有显示完全的情况下给予明显提示(例如闪烁) 51 | 52 | 优势: 53 | *高性能 是内置 ToolTip 2-1000 倍性能(文本越大性能对比越大,多数普通应用场景2-5倍性能) 54 | *高兼容 兼容内置 ToolTip 的一切,包括语法、WhichToolTip、A_CoordModeToolTip、自动换行等等 55 | *简单易用 一行代码即使用 无需手动创建释放资源 56 | *多套内置风格 可通过模板快速实现自定义风格 57 | *可自定义风格 细边框(颜色、大小) 圆角 边距 文字(颜色、字体、字号、渲染方式、样式) 背景色 所有颜色支持360°渐变与透明 58 | *可自定义参数 贴附目标句柄 坐标模式 整体透明度 文本框永不被遮挡 跟随鼠标距离 不绘制内容直接返回尺寸 59 | *不闪烁不乱跳 60 | *多显示器支持 61 | *缩放显示支持 62 | *跟随鼠标不出界 63 | *可贴附指定目标 64 | */ 65 | btt(Text:="", X:="", Y:="", WhichToolTip:="", BulitInStyleOrStyles:="", BulitInOptionOrOptions:="") 66 | { 67 | static BTT 68 | ; You can customize your own style. 69 | ; All supported parameters are listed below. All parameters can be omitted. 70 | ; Please share your custom style and include a screenshot. It will help a lot of people. 71 | ; Attention: 72 | ; Color => ARGB => Alpha Red Green Blue => 0x ff aa bb cc => 0xffaabbcc 73 | , Style99 := {Border:20 ; If omitted, 1 will be used. Range 0-20. 74 | , Rounded:30 ; If omitted, 3 will be used. Range 0-30. 75 | , Margin:30 ; If omitted, 5 will be used. Range 0-30. 76 | , TabStops:[50, 80, 100] ; If omitted, [50] will be used. This value must be an array. 77 | , BorderColor:0xffaabbcc ; ARGB 78 | , BorderColorLinearGradientStart:0xff16a085 ; ARGB 79 | , BorderColorLinearGradientEnd:0xfff4d03f ; ARGB 80 | , BorderColorLinearGradientAngle:45 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 81 | , BorderColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 82 | , TextColor:0xff112233 ; ARGB 83 | , TextColorLinearGradientStart:0xff00416a ; ARGB 84 | , TextColorLinearGradientEnd:0xffe4e5e6 ; ARGB 85 | , TextColorLinearGradientAngle:90 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 86 | , TextColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 87 | , BackgroundColor:0xff778899 ; ARGB 88 | , BackgroundColorLinearGradientStart:0xff8DA5D3 ; ARGB 89 | , BackgroundColorLinearGradientEnd:0xffF4CFC9 ; ARGB 90 | , BackgroundColorLinearGradientAngle:135 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 91 | , BackgroundColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 92 | , Font:"Font Name" ; If omitted, ToolTip's Font will be used. Can specify the font file path. 93 | , FontSize:20 ; If omitted, 12 will be used. 94 | , FontRender:5 ; If omitted, 5 will be used. Range 0-5. 95 | , FontStyle:"Regular Bold Italic BoldItalic Underline Strikeout"} 96 | 97 | , Option99 := {TargetHWND:"" ; If omitted, active window will be used. 98 | , CoordMode:"Screen Relative Window Client" ; If omitted, A_CoordModeToolTip will be used. 99 | , Transparent:"" ; If omitted, 255 will be used. 100 | , MouseNeverCoverToolTip:"" ; If omitted, 1 will be used. 101 | , DistanceBetweenMouseXAndToolTip:"" ; If omitted, 16 will be used. This value can be negative. 102 | , DistanceBetweenMouseYAndToolTip:"" ; If omitted, 16 will be used. This value can be negative. 103 | , JustCalculateSize:""} ; Set to 1, no content will be displayed, just calculate size and return. 104 | 105 | , Style1 := {TextColor:0xffeef8f6 106 | , BackgroundColor:0xff1b8dff 107 | , FontSize:14} 108 | 109 | , Style2 := {Border:1 110 | , Rounded:8 111 | , TextColor:0xfff4f4f4 112 | , BackgroundColor:0xaa3e3d45 113 | , FontSize:14} 114 | 115 | , Style3 := {Border:2 116 | , Rounded:0 117 | , TextColor:0xffF15839 118 | , BackgroundColor:0xffFCEDE6 119 | , FontSize:14} 120 | 121 | , Style4 := {Border:10 122 | , Rounded:20 123 | , BorderColor:0xff604a78 124 | , TextColor:0xffF3AE00 125 | , BackgroundColor:0xff6A537F 126 | , FontSize:20 127 | , FontStyle:"Bold Italic"} 128 | 129 | , Style5 := {Border:0 130 | , Rounded:5 131 | , TextColor:0xffeeeeee 132 | , BackgroundColorLinearGradientStart:0xff134E5E 133 | , BackgroundColorLinearGradientEnd:0xff326f69 134 | , BackgroundColorLinearGradientAngle:0 135 | , BackgroundColorLinearGradientMode:1} 136 | 137 | , Style6 := {Border:2 138 | , Rounded:5 139 | , TextColor:0xffCAE682 140 | , BackgroundColor:0xff434343 141 | , FontSize:14} 142 | 143 | , Style7 := {Border:20 144 | , Rounded:30 145 | , Margin:30 146 | , BorderColor:0xffaabbcc 147 | , TextColor:0xff112233 148 | , BackgroundColorLinearGradientStart:0xffF4CFC9 149 | , BackgroundColorLinearGradientEnd:0xff8DA5D3 150 | , BackgroundColorLinearGradientAngle:0 151 | , BackgroundColorLinearGradientMode:1 152 | , FontStyle:"BoldItalic"} 153 | 154 | , Style8 := {Border:3 155 | , Rounded:30 156 | , Margin:30 157 | , BorderColorLinearGradientStart:0xffb7407c 158 | , BorderColorLinearGradientEnd:0xff3881a7 159 | , BorderColorLinearGradientAngle:45 160 | , BorderColorLinearGradientMode:1 161 | , TextColor:0xffd9d9db 162 | , BackgroundColor:0xff26293a} 163 | 164 | ; 直接在 static 中初始化 BTT 会报错,所以只能这样写 165 | if (BTT="") 166 | BTT := new BeautifulToolTip() 167 | 168 | return, BTT.ToolTip(Text, X, Y, WhichToolTip 169 | ; 如果 Style 是一个内置预设的名称,则使用对应内置预设的值,否则使用 Styles 本身的值。 Options 同理。 170 | , %BulitInStyleOrStyles%="" ? BulitInStyleOrStyles : %BulitInStyleOrStyles% 171 | , %BulitInOptionOrOptions%="" ? BulitInOptionOrOptions : %BulitInOptionOrOptions%) 172 | } 173 | 174 | Class BeautifulToolTip 175 | { 176 | ; 以下这些是类中静态变量。末尾带数字1的,表明最多存在1-20这样的变体。例如 _BTT1 就有 _BTT1 ... _BTT20 共20个类似变量。 177 | ; pToken, Monitors, ToolTipFontName, DIBWidth, DIBHeight 178 | ; MouseNeverCoverToolTip, DistanceBetweenMouseXAndToolTip, DistanceBetweenMouseYAndToolTip 179 | ; hBTT1(GUI句柄), hbm1, hdc1, obm1, G1 180 | ; SavedText1, SavedOptions1, SavedX1, SavedY1, SavedW1, SavedH1, SavedCoordMode1, SavedTargetHWND1 181 | static DebugMode:=0 182 | 183 | __New() 184 | { 185 | if (!this.pToken) 186 | { 187 | ; 加速 188 | SavedBatchLines:=A_BatchLines 189 | SetBatchLines, -1 190 | 191 | ; 多实例启动 gdi+ 。避免有些人修改内部代码时与他自己的 gdi+ 冲突。 192 | this.pToken := Gdip_Startup(1) 193 | if (!this.pToken) 194 | { 195 | MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system 196 | ExitApp 197 | } 198 | 199 | ; 多显示器支持 200 | this.Monitors := MDMF_Enum() 201 | ; 获取多显示器各自 DPI 缩放比例 202 | for hMonitor, v in this.Monitors.Clone() 203 | { 204 | if (hMonitor="TotalCount" or hMonitor="Primary") 205 | continue 206 | ; https://github.com/Ixiko/AHK-libs-and-classes-collection/blob/e421acb801867edb659a54b7473e6e617f2b267b/libs/g-n/Monitor.ahk 207 | ; ahk 源码里 A_ScreenDPI 就是只获取了 dpiX ,所以这里保持一致 208 | osv := StrSplit(A_OSVersion, ".") ; https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ns-wdm-_osversioninfoexw 209 | if (osv[1] < 6 || (osv[1] == 6 && osv[2] < 3)) ; WIN_8- 。Win7 必须用这种方式,否则会出错 210 | { 211 | hDC := DllCall("Gdi32.dll\CreateDC", "Str", hMonitor.name, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr") 212 | dpiX := DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", hDC, "Int", 88) ; LOGPIXELSX = 88 213 | DllCall("Gdi32.dll\DeleteDC", "Ptr", hDC) 214 | } 215 | else 216 | DllCall("Shcore.dll\GetDpiForMonitor", "Ptr", hMonitor, "Int", Type, "UIntP", dpiX, "UIntP", dpiY, "UInt") 217 | this.Monitors[hMonitor].DPIScale := this.NonNull_Ret(dpiX, A_ScreenDPI)/96 218 | } 219 | 220 | ; 获取整个桌面的分辨率,即使跨显示器 221 | SysGet, VirtualWidth, 78 222 | SysGet, VirtualHeight, 79 223 | this.DIBWidth := VirtualWidth 224 | this.DIBHeight := VirtualHeight 225 | 226 | ; 获取 ToolTip 的默认字体 227 | this.ToolTipFontName := this.Fnt_GetTooltipFontName() 228 | 229 | ; create 20 guis for gdi+ 230 | ; 最多20个 ToolTip ,与原版对应。 231 | loop, 20 232 | { 233 | ; _BTT1(GUI 名称) 与 _hBTT1(GUI 句柄) 都是临时变量,后者被储存了。 234 | Gui, _BTT%A_Index%: +E0x80000 -Caption +ToolWindow +LastFound +AlwaysOnTop +Hwnd_hBTT%A_Index% 235 | Gui, _BTT%A_Index%: Show, NA 236 | 237 | this["hBTT" A_Index] := _hBTT%A_Index% 238 | , this["hbm" A_Index] := CreateDIBSection(this.DIBWidth, this.DIBHeight) 239 | , this["hdc" A_Index] := CreateCompatibleDC() 240 | , this["obm" A_Index] := SelectObject(this["hdc" A_Index], this["hbm" A_Index]) 241 | , this["G" A_Index] := Gdip_GraphicsFromHDC(this["hdc" A_Index]) 242 | , Gdip_SetSmoothingMode(this["G" A_Index], 4) 243 | , Gdip_SetPixelOffsetMode(this["G" A_Index], 2) ; 此参数是画出完美圆角矩形的关键 244 | } 245 | SetBatchLines, %SavedBatchLines% 246 | } 247 | else 248 | return 249 | } 250 | 251 | ; new 后得到的变量在销毁后会自动跳这里来运行,因此很适合做自动资源回收。 252 | __Delete() 253 | { 254 | loop, 20 255 | { 256 | Gdip_DeleteGraphics(this["G" A_Index]) 257 | , SelectObject(this["hdc" A_Index], this["obm" A_Index]) 258 | , DeleteObject(this["hbm" A_Index]) 259 | , DeleteDC(this["hdc" A_Index]) 260 | } 261 | Gdip_Shutdown(this.pToken) 262 | } 263 | 264 | ; 参数默认全部为空只是为了让清空 ToolTip 的语法简洁而已。 265 | ToolTip(Text:="", X:="", Y:="", WhichToolTip:="", Styles:="", Options:="") 266 | { 267 | ; 给出 WhichToolTip 的默认值1,并限制 WhichToolTip 的范围为 1-20 268 | this.NonNull(WhichToolTip, 1, 1, 20) 269 | ; 检查并解析 Styles 与 Options 。无论不传参、部分传参、完全传参,此函数均能正确返回所需参数。 270 | O:=this._CheckStylesAndOptions(Styles, Options) 271 | 272 | ; 判断显示内容是否发生变化。由于前面给了 Options 一个默认值,所以首次进来时下面的 O.Options!=SavedOptions 是必然成立的。 273 | FirstCallOrNeedToUpdate:=(Text != this["SavedText" WhichToolTip] 274 | or O.Checksum != this["SavedOptions" WhichToolTip]) 275 | 276 | if (Text="") 277 | { 278 | ; 清空 ToolTip 279 | Gdip_GraphicsClear(this["G" WhichToolTip]) 280 | UpdateLayeredWindow(this["hBTT" WhichToolTip], this["hdc" WhichToolTip]) 281 | ; 清空变量 282 | this["SavedText" WhichToolTip] := "" 283 | , this["SavedOptions" WhichToolTip] := "" 284 | , this["SavedX" WhichToolTip] := "" 285 | , this["SavedY" WhichToolTip] := "" 286 | , this["SavedW" WhichToolTip] := "" 287 | , this["SavedH" WhichToolTip] := "" 288 | , this["SavedTargetHWND" WhichToolTip] := "" 289 | , this["SavedCoordMode" WhichToolTip] := "" 290 | , this["SavedTransparent" WhichToolTip] := "" 291 | 292 | return 293 | } 294 | else if (FirstCallOrNeedToUpdate) ; First Call or NeedToUpdate 295 | { 296 | ; 加速 297 | SavedBatchLines:=A_BatchLines 298 | SetBatchLines, -1 299 | 300 | ; 获取目标尺寸,用于计算文本大小时加上宽高限制,否则目标为屏幕时,可能计算出超宽超高的大小,导致无法显示。 301 | TargetSize:=this._CalculateDisplayPosition(X, Y, "", "", O, GetTargetSize:=1) 302 | ; 使得 文字区域+边距+细边框 不会超过目标宽度。 303 | , MaxTextWidth:=TargetSize.W - O.Margin*2 - O.Border*2 304 | ; 使得 文字区域+边距+细边框 不会超过目标高度的90%。 305 | ; 之所以高度限制90%是因为两个原因,1是留出一些上下的空白,避免占满全屏,鼠标点不了其它地方,难以退出。 306 | ; 2是在计算文字区域时,即使已经给出了宽高度限制,且因为自动换行的原因,宽度的返回值通常在范围内,但高度的返回值偶尔还是会超过1行,所以提前留个余量。 307 | , MaxTextHeight:=(TargetSize.H*90)//100 - O.Margin*2 - O.Border*2 308 | ; 为 _TextToGraphics 计算区域提供高宽限制。 309 | , O.Width:=MaxTextWidth, O.Height:=MaxTextHeight 310 | ; 计算文字显示区域 TextArea = x|y|width|height|chars|lines 311 | , TextArea:=StrSplit(this._TextToGraphics(this["G" WhichToolTip], Text, O, Measure:=1), "|") 312 | ; 这里务必向上取整。 313 | ; 向上的原因是,例如 1.2 如果四舍五入为 1,那么最右边的字符可能会显示不全。 314 | ; 取整的原因是,不取整无法画出完美的圆角矩形。 315 | ; 当使用 AutoTrim 选项,即自动将超出范围的文字显示为 “...” 时,此时返回的宽高度值是不包含 “...” 的。 316 | ; 所以加上 “...” 的宽高度后,仍然可能超限。故需要再次检查并限制。 317 | ; 一旦宽高度超过了限制(CreateDIBSection() 时创建的大小),会导致 UpdateLayeredWindow() 画不出图像来。 318 | , TextWidth:=Min(Ceil(TextArea[3]), MaxTextWidth) 319 | , TextHeight:=Min(Ceil(TextArea[4]), MaxTextHeight) 320 | 321 | , RectWidth:=TextWidth+O.Margin*2 ; 文本+边距。 322 | , RectHeight:=TextHeight+O.Margin*2 323 | , RectWithBorderWidth:=RectWidth+O.Border*2 ; 文本+边距+细边框。 324 | , RectWithBorderHeight:=RectHeight+O.Border*2 325 | ; 圆角超过矩形宽或高的一半时,会画出畸形的圆,所以这里验证并限制一下。 326 | , R:=(O.Rounded>Min(RectWidth, RectHeight)//2) ? Min(RectWidth, RectHeight)//2 : O.Rounded 327 | 328 | if (O.JustCalculateSize!=1) 329 | { 330 | ; 画之前务必清空画布,否则会出现异常。 331 | Gdip_GraphicsClear(this["G" WhichToolTip]) 332 | 333 | ; 准备细边框画刷 334 | if (O.BCLGA!="" and O.BCLGM and O.BCLGS and O.BCLGE) ; 渐变画刷 画细边框 335 | pBrushBorder := this._CreateLinearGrBrush(O.BCLGA, O.BCLGM, O.BCLGS, O.BCLGE 336 | , 0, 0, RectWithBorderWidth, RectWithBorderHeight) 337 | else 338 | pBrushBorder := Gdip_BrushCreateSolid(O.BorderColor) ; 纯色画刷 画细边框 339 | 340 | if (O.Border>0) 341 | switch, R 342 | { 343 | ; 圆角为0则使用矩形画。不单独处理,会画出显示异常的图案。 344 | case, "0": Gdip_FillRectangle(this["G" WhichToolTip] ; 矩形细边框 345 | , pBrushBorder, 0, 0, RectWithBorderWidth, RectWithBorderHeight) 346 | Default : Gdip_FillRoundedRectanglePath(this["G" WhichToolTip] ; 圆角细边框 347 | , pBrushBorder, 0, 0, RectWithBorderWidth, RectWithBorderHeight, R) 348 | } 349 | 350 | ; 准备文本框画刷 351 | if (O.BGCLGA!="" and O.BGCLGM and O.BGCLGS and O.BGCLGE) ; 渐变画刷 画文本框 352 | pBrushBackground := this._CreateLinearGrBrush(O.BGCLGA, O.BGCLGM, O.BGCLGS, O.BGCLGE 353 | , O.Border, O.Border, RectWidth, RectHeight) 354 | else 355 | pBrushBackground := Gdip_BrushCreateSolid(O.BackgroundColor) ; 纯色画刷 画文本框 356 | 357 | switch, R 358 | { 359 | case, "0": Gdip_FillRectangle(this["G" WhichToolTip] ; 矩形文本框 360 | , pBrushBackground, O.Border, O.Border, RectWidth, RectHeight) 361 | Default : Gdip_FillRoundedRectanglePath(this["G" WhichToolTip] ; 圆角文本框 362 | , pBrushBackground, O.Border, O.Border, RectWidth, RectHeight 363 | , (R>O.Border) ? R-O.Border : R) ; 确保内外圆弧看起来同心 364 | } 365 | 366 | ; 清理画刷 367 | Gdip_DeleteBrush(pBrushBorder) 368 | Gdip_DeleteBrush(pBrushBackground) 369 | 370 | ; 计算居中显示坐标。由于 TextArea 返回的文字范围右边有很多空白,所以这里的居中坐标并不精确。 371 | O.X:=O.Border+O.Margin, O.Y:=O.Border+O.Margin, O.Width:=TextWidth, O.Height:=TextHeight 372 | 373 | ; 如果显示区域过小,文字无法完全显示,则将待显示文本最后4个字符替换为4个英文省略号,表示显示不完全。 374 | ; 虽然有 GdipSetStringFormatTrimming 函数可以设置末尾显示省略号,但它偶尔需要增加额外的宽度才能显示出来。 375 | ; 由于难以判断是否需要增加额外宽度,以及需要增加多少等等问题,所以直接用这种方式自己实现省略号的显示。 376 | ; 之所以选择替换最后4个字符,是因为一般替换掉最后2个字符,才能确保至少一个省略号显示出来。 377 | ; 为了应对意外情况,以及让省略号更加明显一点,所以选择替换最后4个。 378 | ; 原始的 Text 需要用于显示前的比对,所以不能改原始值,必须用 TempText 。 379 | if (TextArea[5]4 ? SubStr(Text, 1 ,TextArea[5]-4) "…………" : SubStr(Text, 1 ,1) "…………" 381 | else 382 | TempText:=Text 383 | 384 | ; 写字到框上。这个函数使用 O 中的 X,Y 去调整文字的位置。 385 | this._TextToGraphics(this["G" WhichToolTip], TempText, O) 386 | 387 | ; 调试用,可显示计算得到的文字范围。 388 | if (this.DebugMode) 389 | { 390 | pBrush := Gdip_BrushCreateSolid(0x20ff0000) 391 | Gdip_FillRectangle(this["G" WhichToolTip], pBrush, O.Border+O.Margin, O.Border+O.Margin, TextWidth, TextHeight) 392 | Gdip_DeleteBrush(pBrush) 393 | } 394 | 395 | ; 返回文本框不超出目标范围(比如屏幕范围)的最佳坐标。 396 | this._CalculateDisplayPosition(X, Y, RectWithBorderWidth, RectWithBorderHeight, O) 397 | 398 | ; 显示 399 | UpdateLayeredWindow(this["hBTT" WhichToolTip], this["hdc" WhichToolTip] 400 | , X, Y, RectWithBorderWidth, RectWithBorderHeight, O.Transparent) 401 | 402 | ; 因为 BTT 总会在使用一段时间后,被不明原因的置底,导致显示内容被其它窗口遮挡,以为没有正常显示,所以这里提升Z序到最上面! 403 | ; 已测试过,此方法效率极高,远超 WinSet, Top 命令。 404 | ; hWndInsertAfter 405 | ; HWND_TOPMOST:=-1 406 | ; uFlags 407 | ; SWP_NOSIZE:=0x0001 408 | ; SWP_NOMOVE:=0x0002 409 | ; SWP_NOREDRAW:=0x0008 410 | ; SWP_NOACTIVATE:=0x0010 411 | ; SWP_NOOWNERZORDER:=0x0200 412 | ; SWP_NOSENDCHANGING:=0x0400 413 | ; SWP_DEFERERASE:=0x2000 414 | ; SWP_ASYNCWINDOWPOS:=0x4000 415 | DllCall("SetWindowPos", "ptr", this["hBTT" WhichToolTip], "ptr", -1, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 26139) 416 | } 417 | 418 | ; 保存参数值,以便之后比对参数值是否改变 419 | this["SavedText" WhichToolTip] := Text 420 | , this["SavedOptions" WhichToolTip] := O.Checksum 421 | , this["SavedX" WhichToolTip] := X ; 这里的 X,Y 是经过 _CalculateDisplayPosition() 计算后的新 X,Y 422 | , this["SavedY" WhichToolTip] := Y 423 | , this["SavedW" WhichToolTip] := RectWithBorderWidth 424 | , this["SavedH" WhichToolTip] := RectWithBorderHeight 425 | , this["SavedTargetHWND" WhichToolTip] := O.TargetHWND 426 | , this["SavedCoordMode" WhichToolTip] := O.CoordMode 427 | , this["SavedTransparent" WhichToolTip] := O.Transparent 428 | 429 | SetBatchLines, %SavedBatchLines% 430 | } 431 | ; x,y 任意一个跟随鼠标位置 或 使用窗口或客户区模式(窗口大小可能发生改变或者窗口发生移动) 432 | ; 或 目标窗口发生变化 或 坐标模式发生变化 433 | ; 或 整体透明度发生变化 这5种情况可能需要移动位置,需要进行坐标计算。 434 | else if ((X="" or Y="") or O.CoordMode!="Screen" 435 | or O.TargetHWND!=this.SavedTargetHWND or O.CoordMode!=this.SavedCoordMode 436 | or O.Transparent!=this.SavedTransparent) 437 | { 438 | ; 返回文本框不超出目标范围(比如屏幕范围)的最佳坐标。 439 | this._CalculateDisplayPosition(X, Y, this["SavedW" WhichToolTip], this["SavedH" WhichToolTip], O) 440 | ; 判断文本框 显示位置 441 | ; 或 显示透明度 是否发生改变 442 | if (X!=this["SavedX" WhichToolTip] or Y!=this["SavedY" WhichToolTip] 443 | or O.Transparent!=this.SavedTransparent) 444 | { 445 | ; 显示 446 | UpdateLayeredWindow(this["hBTT" WhichToolTip], this["hdc" WhichToolTip] 447 | , X, Y, this["SavedW" WhichToolTip], this["SavedH" WhichToolTip], O.Transparent) 448 | 449 | ; 保存新的位置 450 | this["SavedX" WhichToolTip] := X 451 | , this["SavedY" WhichToolTip] := Y 452 | , this["SavedTargetHWND" WhichToolTip] := O.TargetHWND 453 | , this["SavedCoordMode" WhichToolTip] := O.CoordMode 454 | , this["SavedTransparent" WhichToolTip] := O.Transparent 455 | } 456 | } 457 | 458 | ret:={Hwnd : this["hBTT" WhichToolTip] 459 | , X : X 460 | , Y : Y 461 | , W : this["SavedW" WhichToolTip] 462 | , H : this["SavedH" WhichToolTip]} 463 | return, ret 464 | } 465 | 466 | ; 为了统一参数的传输,以及特殊模式的设置,修改了 gdip 库的 Gdip_TextToGraphics() 函数。 467 | _TextToGraphics(pGraphics, Text, Options, Measure:=0) 468 | { 469 | static Styles := "Regular|Bold|Italic|BoldItalic|Underline|Strikeout" 470 | 471 | ; 设置字体样式 472 | Style := 0 473 | for eachStyle, valStyle in StrSplit(Styles, "|") 474 | { 475 | if InStr(Options.FontStyle, valStyle) 476 | Style |= (valStyle != "StrikeOut") ? (A_Index-1) : 8 477 | } 478 | 479 | if (FileExist(Options.Font)) ; 加载未安装的本地字体 480 | { 481 | hFontCollection := Gdip_NewPrivateFontCollection() 482 | hFontFamily := Gdip_CreateFontFamilyFromFile(Options.Font, hFontCollection) 483 | } 484 | if !hFontFamily ; 加载已安装的字体 485 | hFontFamily := Gdip_FontFamilyCreate(Options.Font) 486 | if !hFontFamily ; 加载默认字体 487 | hFontFamily := Gdip_FontFamilyCreateGeneric(1) 488 | ; 根据 DPI 缩放比例自动调整字号 489 | hFont := Gdip_FontCreate(hFontFamily, Options.FontSize * Options.DPIScale, Style, Unit:=0) 490 | 491 | ; 设置文字格式化样式,LineLimit = 0x00002000 只显示完整的行。 492 | ; 比如最后一行,因为布局高度有限,只能显示出一半,此时就会让它完全不显示。 493 | ; 直接使用 Gdip_StringFormatGetGeneric(1) 包含 LineLimit 设置,同时可以实现左右空白区域最小化。 494 | ; 但这样有个副作用,那就是无法精确的设置文本框的宽度了,同时最右边文字的间距会被压缩。 495 | ; 例如指定宽度800,可能返回的宽度是793,因为右边没有用空白补上。 496 | ; 好处是右边几乎没有空白区域,左边也没有,所以接近完美的实现文字居中了。 497 | ; hStringFormat := Gdip_StringFormatCreate(0x00002000) 498 | ; if !hStringFormat 499 | hStringFormat := Gdip_StringFormatGetGeneric(1) 500 | 501 | ; 准备文本画刷 502 | if (Options.TCLGA!="" and Options.TCLGM and Options.TCLGS and Options.TCLGE 503 | and Options.Width and Options.Height) ; 渐变画刷 504 | { 505 | pBrush := this._CreateLinearGrBrush(Options.TCLGA, Options.TCLGM, Options.TCLGS, Options.TCLGE 506 | , this.NonNull_Ret(Options.X, 0), this.NonNull_Ret(Options.Y, 0) 507 | , Options.Width, Options.Height) 508 | } 509 | else 510 | pBrush := Gdip_BrushCreateSolid(Options.TextColor) ; 纯色画刷 511 | 512 | ; 检查参数是否齐全 513 | if !(hFontFamily && hFont && hStringFormat && pBrush && pGraphics) 514 | { 515 | E := !pGraphics ? -2 : !hFontFamily ? -3 : !hFont ? -4 : !hStringFormat ? -5 : !pBrush ? -6 : 0 516 | if pBrush 517 | Gdip_DeleteBrush(pBrush) 518 | if hStringFormat 519 | Gdip_DeleteStringFormat(hStringFormat) 520 | if hFont 521 | Gdip_DeleteFont(hFont) 522 | if hFontFamily 523 | Gdip_DeleteFontFamily(hFontFamily) 524 | if hFontCollection 525 | Gdip_DeletePrivateFontCollection(hFontCollection) 526 | return E 527 | } 528 | 529 | TabStops := [] 530 | for k, v in Options.TabStops 531 | TabStops.Push(v * Options.DPIScale) 532 | Gdip_SetStringFormatTabStops(hStringFormat, TabStops) ; 设置 TabStops 533 | Gdip_SetStringFormatAlign(hStringFormat, Align:=0) ; 设置左对齐 534 | Gdip_SetTextRenderingHint(pGraphics, Options.FontRender) ; 设置渲染模式 535 | CreateRectF(RC 536 | , this.NonNull_Ret(Options.X, 0) ; x,y 需要至少为0 537 | , this.NonNull_Ret(Options.Y, 0) 538 | , Options.Width, Options.Height) ; 宽高可以为空 539 | returnRC := Gdip_MeasureString(pGraphics, Text, hFont, hStringFormat, RC) ; 计算大小 540 | 541 | if !Measure 542 | _E := Gdip_DrawString(pGraphics, Text, hFont, hStringFormat, pBrush, RC) 543 | 544 | Gdip_DeleteBrush(pBrush) 545 | Gdip_DeleteFont(hFont) 546 | Gdip_DeleteStringFormat(hStringFormat) 547 | Gdip_DeleteFontFamily(hFontFamily) 548 | if hFontCollection 549 | Gdip_DeletePrivateFontCollection(hFontCollection) 550 | return _E ? _E : returnRC 551 | } 552 | 553 | _CreateLinearGrBrush(Angle, Mode, StartColor, EndColor, x, y, w, h) 554 | { 555 | ; Mode=8 Angle 0=左到右 90=上到下 180=右到左 270=下到上 556 | ; Mode=3 Angle 0=左到右 90=近似上到下 557 | ; Mode=4 Angle 0=左到右 90=下到上 558 | switch, Mode 559 | { 560 | case, 1,3,5,7:pBrush:=Gdip_CreateLinearGrBrush(x, y, x+w, y, StartColor, EndColor) 561 | case, 2,4,6,8:pBrush:=Gdip_CreateLinearGrBrush(x, y+h//2, x+w, y+h//2, StartColor, EndColor) 562 | } 563 | switch, Mode 564 | { 565 | case, 1,2: Gdip_RotateLinearGrBrushTransform(pBrush, Angle, 0) ; 性能比模式3、4高10倍左右 566 | case, 3,4: Gdip_RotateLinearGrBrushTransform(pBrush, Angle, 1) 567 | case, 5,6: Gdip_RotateLinearGrBrushAtCenter(pBrush, Angle, 0) 568 | case, 7,8: Gdip_RotateLinearGrBrushAtCenter(pBrush, Angle, 1) ; 可绕中心旋转 569 | } 570 | return, pBrush 571 | } 572 | 573 | ; 此函数确保传入空值或者错误值均可返回正确值。 574 | _CheckStylesAndOptions(Styles, Options) 575 | { 576 | O := {} 577 | , O.Border := this.NonNull_Ret(Styles.Border , 1 , 0 , 20) ; 细边框 默认1 0-20 578 | , O.Rounded := this.NonNull_Ret(Styles.Rounded , 3 , 0 , 30) ; 圆角 默认3 0-30 579 | , O.Margin := this.NonNull_Ret(Styles.Margin , 5 , 0 , 30) ; 边距 默认5 0-30 580 | , O.TabStops := this.NonNull_Ret(Styles.TabStops , [50] , "", "") ; 制表符宽 默认[50] 581 | , O.TextColor := this.NonNull_Ret(Styles.TextColor , 0xff575757 , "", "") ; 文本色 默认0xff575757 582 | , O.BackgroundColor := this.NonNull_Ret(Styles.BackgroundColor, 0xffffffff , "", "") ; 背景色 默认0xffffffff 583 | , O.Font := this.NonNull_Ret(Styles.Font , this.ToolTipFontName, "", "") ; 字体 默认与 ToolTip 一致 584 | , O.FontSize := this.NonNull_Ret(Styles.FontSize , 12 , "", "") ; 字号 默认12 585 | , O.FontRender := this.NonNull_Ret(Styles.FontRender , 5 , 0 , 5 ) ; 渲染模式 默认5 0-5 586 | , O.FontStyle := Styles.FontStyle ; 字体样式 默认无 587 | 588 | ; 名字太长,建个缩写副本。 589 | , O.BCLGS := Styles.BorderColorLinearGradientStart ; 细边框渐变色 默认无 590 | , O.BCLGE := Styles.BorderColorLinearGradientEnd ; 细边框渐变色 默认无 591 | , O.BCLGA := Styles.BorderColorLinearGradientAngle ; 细边框渐变角度 默认无 592 | , O.BCLGM := this.NonNull_Ret(Styles.BorderColorLinearGradientMode, "", 1, 8) ; 细边框渐变模式 默认无 1-8 593 | 594 | ; 名字太长,建个缩写副本。 595 | , O.TCLGS := Styles.TextColorLinearGradientStart ; 文本渐变色 默认无 596 | , O.TCLGE := Styles.TextColorLinearGradientEnd ; 文本渐变色 默认无 597 | , O.TCLGA := Styles.TextColorLinearGradientAngle ; 文本渐变角度 默认无 598 | , O.TCLGM := this.NonNull_Ret(Styles.TextColorLinearGradientMode, "", 1, 8) ; 文本渐变模式 默认无 1-8 599 | 600 | ; 名字太长,建个缩写副本。 601 | , O.BGCLGS := Styles.BackgroundColorLinearGradientStart ; 背景渐变色 默认无 602 | , O.BGCLGE := Styles.BackgroundColorLinearGradientEnd ; 背景渐变色 默认无 603 | , O.BGCLGA := Styles.BackgroundColorLinearGradientAngle ; 背景渐变角度 默认无 604 | , O.BGCLGM := this.NonNull_Ret(Styles.BackgroundColorLinearGradientMode, "", 1, 8) ; 背景渐变模式 默认无 1-8 605 | 606 | ; a:=0xaabbccdd 下面是运算规则 607 | ; a>>16 = 0xaabb 608 | ; a>>24 = 0xaa 609 | ; a&0xffff = 0xccdd 610 | ; a&0xff = 0xdd 611 | ; 0x88<<16 = 0x880000 612 | ; 0x880000+0xbbcc = 0x88bbcc 613 | , BlendedColor2 := (O.TCLGS and O.TCLGE and O.TCLGD) ? O.TCLGS : O.TextColor ; 使用文本渐变色替换文本色用于混合 614 | , BlendedColor := ((O.BackgroundColor>>24)<<24) + (BlendedColor2&0xffffff) ; 混合色 背景色的透明度与文本色混合 615 | , O.BorderColor := this.NonNull_Ret(Styles.BorderColor , BlendedColor , "", "") ; 细边框色 默认混合色 616 | 617 | , O.TargetHWND := this.NonNull_Ret(Options.TargetHWND , WinExist("A") , "", "") ; 目标句柄 默认活动窗口 618 | , O.CoordMode := this.NonNull_Ret(Options.CoordMode , A_CoordModeToolTip, "", "") ; 坐标模式 默认与 ToolTip 一致 619 | , O.Transparent := this.NonNull_Ret(Options.Transparent, 255 , 0 , 255) ; 整体透明度 默认255 620 | , O.MouseNeverCoverToolTip := this.NonNull_Ret(Options.MouseNeverCoverToolTip , 1 , 0 , 1 ) ; 鼠标永不遮挡文本框 621 | , O.DistanceBetweenMouseXAndToolTip := this.NonNull_Ret(Options.DistanceBetweenMouseXAndToolTip, 16, "", "") ; 鼠标与文本框的X距离 622 | , O.DistanceBetweenMouseYAndToolTip := this.NonNull_Ret(Options.DistanceBetweenMouseYAndToolTip, 16, "", "") ; 鼠标与文本框的Y距离 623 | , O.JustCalculateSize := Options.JustCalculateSize ; 仅计算显示尺寸并返回 624 | 625 | ; 难以比对两个对象是否一致,所以造一个变量比对。 626 | ; 这里的校验因素,必须是那些改变后会使画面内容也产生变化的因素。 627 | ; 所以没有 TargetHWND 和 CoordMode 和 Transparent ,因为这三个因素只影响位置。 628 | for k, v in O.TabStops 629 | TabStops .= v "," 630 | O.Checksum := O.Border "|" O.Rounded "|" O.Margin "|" TabStops "|" 631 | . O.BorderColor "|" O.BCLGS "|" O.BCLGE "|" O.BCLGA "|" O.BCLGM "|" 632 | . O.TextColor "|" O.TCLGS "|" O.TCLGE "|" O.TCLGA "|" O.TCLGM "|" 633 | . O.BackgroundColor "|" O.BGCLGS "|" O.BGCLGE "|" O.BGCLGA "|" O.BGCLGM "|" 634 | . O.Font "|" O.FontSize "|" O.FontRender "|" O.FontStyle 635 | return, O 636 | } 637 | 638 | ; 此函数确保文本框显示位置不会超出目标范围。 639 | ; 使用 ByRef X, ByRef Y 返回不超限的位置。 640 | _CalculateDisplayPosition(ByRef X, ByRef Y, W, H, Options, GetTargetSize:=0) 641 | { 642 | VarSetCapacity(Point, 8, 0) 643 | ; 获取鼠标位置 644 | , DllCall("GetCursorPos", "Ptr", &Point) 645 | , MouseX := NumGet(Point, 0, "Int"), MouseY := NumGet(Point, 4, "Int") 646 | 647 | ; x,y 即 ToolTip 显示的位置。 648 | ; x,y 同时为空表明完全跟随鼠标。 649 | ; x,y 单个为空表明只跟随鼠标横向或纵向移动。 650 | ; x,y 都有值,则说明被钉在屏幕或窗口或客户区的某个位置。 651 | ; MouseX,MouseY 是鼠标的屏幕坐标。 652 | ; DisplayX,DisplayY 是 x,y 经过转换后的屏幕坐标。 653 | ; 以下过程 x,y 不发生变化, DisplayX,DisplayY 储存转换好的屏幕坐标。 654 | ; 不要尝试合并分支 (X="" and Y="") 与 (A_CoordModeToolTip = "Screen")。 655 | ; 因为存在把坐标模式设为 Window 或 Client 但又同时不给出 x,y 的情况!!!!!! 656 | if (X="" and Y="") 657 | { ; 没有给出 x,y 则使用鼠标坐标 658 | DisplayX := MouseX 659 | , DisplayY := MouseY 660 | ; 根据坐标判断在第几个屏幕里,并获得对应屏幕边界。 661 | ; 使用 MONITOR_DEFAULTTONEAREST 设置,可以在给出的点不在任何显示器内时,返回距离最近的显示器。 662 | ; 这样可以修正使用 1920,1080 这种错误的坐标,导致返回空值,导致画图失败的问题。 663 | ; 为什么 1920,1080 是错误的呢?因为 1920 是宽度,而坐标起点是0,所以最右边坐标值是 1919,最下面是 1079。 664 | , hMonitor := MDMF_FromPoint(DisplayX, DisplayY, MONITOR_DEFAULTTONEAREST:=2) 665 | , TargetLeft := this.Monitors[hMonitor].Left 666 | , TargetTop := this.Monitors[hMonitor].Top 667 | , TargetRight := this.Monitors[hMonitor].Right 668 | , TargetBottom := this.Monitors[hMonitor].Bottom 669 | , TargetWidth := TargetRight-TargetLeft 670 | , TargetHeight := TargetBottom-TargetTop 671 | ; 将对应屏幕的 DPIScale 存入 Options 中。 672 | , Options.DPIScale := this.Monitors[hMonitor].DPIScale 673 | } 674 | ; 已给出 x和y 或x 或y,都会走到下面3个分支去。 675 | else if (Options.CoordMode = "Window" or Options.CoordMode = "Relative") 676 | { ; 已给出 x或y 且使用窗口坐标 677 | WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " Options.TargetHWND 678 | 679 | XInScreen := WinX+X 680 | , YInScreen := WinY+Y 681 | , TargetLeft := WinX 682 | , TargetTop := WinY 683 | , TargetWidth := WinW 684 | , TargetHeight := WinH 685 | , TargetRight := TargetLeft+TargetWidth 686 | , TargetBottom := TargetTop+TargetHeight 687 | , DisplayX := (X="") ? MouseX : XInScreen 688 | , DisplayY := (Y="") ? MouseY : YInScreen 689 | , hMonitor := MDMF_FromPoint(DisplayX, DisplayY, MONITOR_DEFAULTTONEAREST:=2) 690 | , Options.DPIScale := this.Monitors[hMonitor].DPIScale 691 | } 692 | else if (Options.CoordMode = "Client") 693 | { ; 已给出 x或y 且使用客户区坐标 694 | VarSetCapacity(ClientArea, 16, 0) 695 | , DllCall("GetClientRect", "Ptr", Options.TargetHWND, "Ptr", &ClientArea) 696 | , DllCall("ClientToScreen", "Ptr", Options.TargetHWND, "Ptr", &ClientArea) 697 | , ClientX := NumGet(ClientArea, 0, "Int") 698 | , ClientY := NumGet(ClientArea, 4, "Int") 699 | , ClientW := NumGet(ClientArea, 8, "Int") 700 | , ClientH := NumGet(ClientArea, 12, "Int") 701 | 702 | XInScreen := ClientX+X 703 | , YInScreen := ClientY+Y 704 | , TargetLeft := ClientX 705 | , TargetTop := ClientY 706 | , TargetWidth := ClientW 707 | , TargetHeight := ClientH 708 | , TargetRight := TargetLeft+TargetWidth 709 | , TargetBottom := TargetTop+TargetHeight 710 | , DisplayX := (X="") ? MouseX : XInScreen 711 | , DisplayY := (Y="") ? MouseY : YInScreen 712 | , hMonitor := MDMF_FromPoint(DisplayX, DisplayY, MONITOR_DEFAULTTONEAREST:=2) 713 | , Options.DPIScale := this.Monitors[hMonitor].DPIScale 714 | } 715 | else ; 这里必然 A_CoordModeToolTip = "Screen" 716 | { ; 已给出 x或y 且使用屏幕坐标 717 | DisplayX := (X="") ? MouseX : X 718 | , DisplayY := (Y="") ? MouseY : Y 719 | , hMonitor := MDMF_FromPoint(DisplayX, DisplayY, MONITOR_DEFAULTTONEAREST:=2) 720 | , TargetLeft := this.Monitors[hMonitor].Left 721 | , TargetTop := this.Monitors[hMonitor].Top 722 | , TargetRight := this.Monitors[hMonitor].Right 723 | , TargetBottom := this.Monitors[hMonitor].Bottom 724 | , TargetWidth := TargetRight-TargetLeft 725 | , TargetHeight := TargetBottom-TargetTop 726 | , Options.DPIScale := this.Monitors[hMonitor].DPIScale 727 | } 728 | 729 | if (GetTargetSize=1) 730 | { 731 | TargetSize := [] 732 | , TargetSize.X := TargetLeft 733 | , TargetSize.Y := TargetTop 734 | ; 一个窗口,有各种各样的方式可以让自己的高宽超过屏幕高宽。 735 | ; 例如最大化的时候,看起来刚好填满了屏幕,应该是1920*1080,但实际获取会发现是1936*1096。 736 | ; 还可以通过拖动窗口边缘调整大小的方式,让它变1924*1084。 737 | ; 还可以直接在创建窗口的时候,指定一个数值,例如3000*3000。 738 | ; 由于设计的时候, DIB 最大就是多个屏幕大小的总和。 739 | ; 当造出一个超过屏幕大小总和的窗口,又使用了 A_CoordModeToolTip = "Window" 之类的参数,同时待显示文本单行又超级长。 740 | ; 此时 (显示宽高 = 窗口宽高) > DIB宽高,会导致 UpdateLayeredWindow() 显示失败。 741 | ; 所以这里做一下限制。 742 | , TargetSize.W := Min(TargetWidth, this.DIBWidth) 743 | , TargetSize.H := Min(TargetHeight, this.DIBHeight) 744 | return, TargetSize 745 | } 746 | 747 | DPIScale := Options.DPIScale 748 | ; 为跟随鼠标显示的文本框增加一个距离,避免鼠标和文本框挤一起发生遮挡。 749 | ; 因为前面需要用到原始的 DisplayX 和 DisplayY 进行计算,所以在这里才增加距离。 750 | , DisplayX := (X="") ? DisplayX+Options.DistanceBetweenMouseXAndToolTip*DPIScale : DisplayX 751 | , DisplayY := (Y="") ? DisplayY+Options.DistanceBetweenMouseYAndToolTip*DPIScale : DisplayY 752 | 753 | ; 处理目标边缘(右和下)的情况,让文本框可以贴边显示,不会超出目标外。 754 | , DisplayX := (DisplayX+W>=TargetRight) ? TargetRight-W : DisplayX 755 | , DisplayY := (DisplayY+H>=TargetBottom) ? TargetBottom-H : DisplayY 756 | ; 处理目标边缘(左和上)的情况,让文本框可以贴边显示,不会超出目标外。 757 | ; 不建议合并代码,理解会变得困难。 758 | , DisplayX := (DisplayX=DisplayX and MouseY>=DisplayY and MouseX<=DisplayX+W and MouseY<=DisplayY+H) 769 | { 770 | ; MouseY-H-16 是往上弹,应对在左下角和右下角的情况。 771 | ; MouseY+H+16 是往下弹,应对在右上角和左上角的情况。 772 | ; 这里不要去用 Abs(Options.DistanceBetweenMouseYAndToolTip) 替代 16。因为当前者很大时,显示效果不好。 773 | ; 优先往上弹,如果不超限,则上弹。如果超限则往下弹,下弹超限,则不弹。 774 | DisplayY := MouseY-H-16>=TargetTop ? MouseY-H-16 : MouseY+H+16<=TargetBottom ? MouseY+16 : DisplayY 775 | } 776 | 777 | ; 使用 ByRef 变量特性返回计算得到的 X和Y 778 | X := DisplayX , Y := DisplayY 779 | } 780 | 781 | ; https://autohotkey.com/boards/viewtopic.php?f=6&t=4379 782 | ; jballi's Fnt Library 783 | Fnt_GetTooltipFontName() 784 | { 785 | static LF_FACESIZE:=32 ;-- In TCHARS 786 | return StrGet(this.Fnt_GetNonClientMetrics()+(A_IsUnicode ? 316:220)+28,LF_FACESIZE) 787 | } 788 | 789 | Fnt_GetNonClientMetrics() 790 | { 791 | static Dummy15105062 792 | ,SPI_GETNONCLIENTMETRICS:=0x29 793 | ,NONCLIENTMETRICS 794 | 795 | ;-- Set the size of NONCLIENTMETRICS structure 796 | cbSize:=A_IsUnicode ? 500:340 797 | if (((GV:=DllCall("GetVersion"))&0xFF . "." . GV>>8&0xFF)>=6.0) ;-- Vista+ 798 | cbSize+=4 799 | 800 | ;-- Create and initialize NONCLIENTMETRICS structure 801 | VarSetCapacity(NONCLIENTMETRICS,cbSize,0) 802 | NumPut(cbSize,NONCLIENTMETRICS,0,"UInt") 803 | 804 | ;-- Get nonclient metrics parameter 805 | if !DllCall("SystemParametersInfo" 806 | ,"UInt",SPI_GETNONCLIENTMETRICS 807 | ,"UInt",cbSize 808 | ,"Ptr",&NONCLIENTMETRICS 809 | ,"UInt",0) 810 | return false 811 | 812 | ;-- Return to sender 813 | return &NONCLIENTMETRICS 814 | } 815 | 816 | #IncludeAgain %A_LineFile%\..\NonNull.ahk 817 | } 818 | 819 | #Include %A_LineFile%\..\Gdip_All.ahk -------------------------------------------------------------------------------- /Lib/NonNull.ahk: -------------------------------------------------------------------------------- 1 | ; 变量为空,则使用默认值。变量不为空,则使用变量值。 2 | ; 同时可以检查变量是否超出最大最小范围。 3 | ; 注意,默认值不受最大最小范围的限制。 4 | ; 也就是说 5 | ; 当变量值为"",默认值为8,范围为2-5,此时变量值会是8。 6 | ; 当变量值为10,默认值为8,范围为2-5,此时变量值会是5。 7 | NonNull(ByRef var, DefaultValue, MinValue:="", MaxValue:="") ; 237ms 8 | { 9 | var:= var="" ? DefaultValue : MinValue="" ? (MaxValue="" ? var : Min(var, MaxValue)) : (MaxValue!="" ? Max(Min(var, MaxValue), MinValue) : Max(var, MinValue)) 10 | } 11 | 12 | ; 与 NonNull 一致,区别是通过 return 返回值,而不是 ByRef。 13 | NonNull_Ret(var, DefaultValue, MinValue:="", MaxValue:="") ; 237ms 14 | { 15 | return, var="" ? DefaultValue : MinValue="" ? (MaxValue="" ? var : Min(var, MaxValue)) : (MaxValue!="" ? Max(Min(var, MaxValue), MinValue) : Max(var, MinValue)) 16 | /* 17 | ; 下面的 if 版本与上面的三元版本是等价的 18 | ; 只是16w次循环的速度是 270ms,慢了13% 19 | if (var="") 20 | return, DefaultValue ; 变量为空,则返回默认值 21 | else 22 | { 23 | if (MinValue="") 24 | { 25 | if (MaxValue="") 26 | return, var ; 变量有值,且不检查最大最小范围,则直接返回变量值 27 | else 28 | return, Min(var, MaxValue) ; 变量有值,且只检查最大值,则返回不大于最大值的变量值 29 | } 30 | else 31 | { 32 | if (MaxValue!="") 33 | ; 三元的写法不会更快 34 | return, Max(Min(var, MaxValue), MinValue) ; 变量有值,且检查最大最小范围,则返回最大最小范围内的变量值 35 | else 36 | return, Max(var, MinValue) ; 变量有值,且只检查最小值,则返回不小于最小值的变量值 37 | } 38 | } 39 | */ 40 | } 41 | 42 | /* 单元测试 43 | 计时() 44 | loop,1000 45 | { 46 | gosub, UnitTest1 47 | gosub, UnitTest2 48 | } 49 | 计时() 50 | 51 | ; ByRef 版本的测试 52 | UnitTest1: 53 | v:="" 54 | NonNull(v, 8, 2, 10) 55 | if v!=8 56 | MsgBox, wrong 57 | v:="" 58 | NonNull(v, 8, "", "") 59 | if v!=8 60 | MsgBox, wrong 61 | v:="" 62 | NonNull(v, 8, 2, "") 63 | if v!=8 64 | MsgBox, wrong 65 | v:="" 66 | NonNull(v, 8, "", 10) 67 | if v!=8 68 | MsgBox, wrong 69 | 70 | v:=5 71 | NonNull(v, 8, 2, 10) 72 | if v!=5 73 | MsgBox, wrong 74 | v:=5 75 | NonNull(v, 8, "", "") 76 | if v!=5 77 | MsgBox, wrong 78 | v:=5 79 | NonNull(v, 8, 2, "") 80 | if v!=5 81 | MsgBox, wrong 82 | v:=5 83 | NonNull(v, 8, "", 10) 84 | if v!=5 85 | MsgBox, wrong 86 | 87 | v:=15 88 | NonNull(v, 8, 2, 10) 89 | if v!=10 90 | MsgBox, wrong 91 | v:=15 92 | NonNull(v, 8, "", "") 93 | if v!=15 94 | MsgBox, wrong 95 | v:=15 96 | NonNull(v, 8, 2, "") 97 | if v!=15 98 | MsgBox, wrong 99 | v:=15 100 | NonNull(v, 8, "", 10) 101 | if v!=10 102 | MsgBox, wrong 103 | 104 | v:=1 105 | NonNull(v, 8, 2, 10) 106 | if v!=2 107 | MsgBox, wrong 108 | v:=1 109 | NonNull(v, 8, "", "") 110 | if v!=1 111 | MsgBox, wrong 112 | v:=1 113 | NonNull(v, 8, 2, "") 114 | if v!=2 115 | MsgBox, wrong 116 | v:=1 117 | NonNull(v, 8, "", 10) 118 | if v!=1 119 | MsgBox, wrong 120 | return 121 | 122 | ; return 版本的测试 123 | UnitTest2: 124 | v:="" 125 | if NonNull_Ret(v, 8, 2, 10)!=8 126 | MsgBox, wrong 127 | v:="" 128 | if NonNull_Ret(v, 8, "", "")!=8 129 | MsgBox, wrong 130 | v:="" 131 | if NonNull_Ret(v, 8, 2, "")!=8 132 | MsgBox, wrong 133 | v:="" 134 | if NonNull_Ret(v, 8, "", 10)!=8 135 | MsgBox, wrong 136 | 137 | v:=5 138 | if NonNull_Ret(v, 8, 2, 10)!=5 139 | MsgBox, wrong 140 | v:=5 141 | if NonNull_Ret(v, 8, "", "")!=5 142 | MsgBox, wrong 143 | v:=5 144 | if NonNull_Ret(v, 8, 2, "")!=5 145 | MsgBox, wrong 146 | v:=5 147 | if NonNull_Ret(v, 8, "", 10)!=5 148 | MsgBox, wrong 149 | 150 | v:=15 151 | if NonNull_Ret(v, 8, 2, 10)!=10 152 | MsgBox, wrong 153 | v:=15 154 | if NonNull_Ret(v, 8, "", "")!=15 155 | MsgBox, wrong 156 | v:=15 157 | if NonNull_Ret(v, 8, 2, "")!=15 158 | MsgBox, wrong 159 | v:=15 160 | if NonNull_Ret(v, 8, "", 10)!=10 161 | MsgBox, wrong 162 | 163 | v:=1 164 | if NonNull_Ret(v, 8, 2, 10)!=2 165 | MsgBox, wrong 166 | v:=1 167 | if NonNull_Ret(v, 8, "", "")!=1 168 | MsgBox, wrong 169 | v:=1 170 | if NonNull_Ret(v, 8, 2, "")!=2 171 | MsgBox, wrong 172 | v:=1 173 | if NonNull_Ret(v, 8, "", 10)!=1 174 | MsgBox, wrong 175 | return 176 | */ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BeautifulToolTip 2 | 3 | A highly compatible, high-performance, easy to use, multi-style, customizable ToolTip. 4 | 5 | 高兼容 高性能 简单易用 自定义效果丰富的 ToolTip。 6 | 7 | ### [English Demo](https://www.autohotkey.com/boards/viewtopic.php?f=6&t=87139) 或 [中文演示](https://www.autoahk.com/archives/35015) 8 | 9 | ![效果图](https://raw.githubusercontent.com/telppa/BeautifulToolTip/main/img/1.png) 10 | ![效果图](https://raw.githubusercontent.com/telppa/BeautifulToolTip/main/img/8.gif) ![效果图](https://raw.githubusercontent.com/telppa/BeautifulToolTip/main/img/9.gif) 11 | ![效果图](https://raw.githubusercontent.com/telppa/BeautifulToolTip/main/img/10.png) 12 | 13 | --- 14 | 15 | ### Changelog 16 | #### 2021.10.03 17 | * Change the way of Include to reduce the possibility of library conflict. 18 | #### 2021.09.29 19 | * Add TabStops. 20 | * All functions except GDIP library are built into Class. 21 | #### 2021.04.30 22 | * Fixed a bug that can not run in win7. (introduced by 2021.04.20) 23 | #### 2021.04.20 24 | * Supports automatic scaling based on monitor DPI scaling, consistent with ToolTip features. 25 | * Support for using font file path directly. 26 | * Options adds JustCalculateSize parameter to return the size directly without drawing the content. 27 | #### 2021.03.07 28 | * Remove LinearGradientDirection parameter. 29 | * Add LinearGradientAngle parameter to support 360°. 30 | * Add LinearGradientMode parameter to support 8 modes. 31 | #### 2021.03.03 32 | * Support linear gradient for text color. 33 | * Add Style8. 34 | * Add 3 linear gradient directions. 35 | #### 2021.03.02 36 | * Support linear gradient for border color. 37 | * Add Style7. 38 | * Add 2 linear gradient directions. 39 | 40 | --- 41 | 42 | ### 更新日志 43 | #### 2021.10.03 44 | * 改变 Include 方式,降低库冲突的可能性。 45 | #### 2021.09.29 46 | * 支持设置 TabStops 。 47 | * 除 GDIP 库外所有函数内置到 Class 中,降低库冲突的可能性。 48 | #### 2021.04.30 49 | * 修复 Win7 下不能运行的 bug 。(2021.04.20 引起) 50 | #### 2021.04.20 51 | * 支持根据显示器 DPI 缩放比例自动缩放,与 ToolTip 特性保持一致。 52 | * 支持直接使用未安装的本地字体。 53 | * Options 增加 JustCalculateSize 参数,可在不绘制内容的前提下直接返回尺寸。 54 | #### 2021.03.07 55 | * 增加 4 种渐变模式。 56 | #### 2021.03.05 57 | * 删除渐变方向参数。 58 | * 增加渐变角度参数,支持 360° 渐变。 59 | * 增加渐变模式参数,支持 4 种模式。 60 | #### 2021.03.03 61 | * 文本色支持渐变。 62 | * 增加 Style8 。 63 | * 增加 3 个渐变方向。 64 | #### 2021.03.02 65 | * 细边框色支持渐变。 66 | * 增加 Style7 。 67 | * 增加 2 个渐变方向。 68 | #### 2021.03.01 69 | * BTT 的总在最上级别现在跟 ToolTip 一样高了。 70 | * 解决 BTT 被不明原因置底导致误以为没显示的问题。 71 | * 增加 Style6 。 72 | * 文字显示更加居中。 73 | #### 2021.02.22 74 | * 增加返回值。 75 | * Options 增加 Transparent 参数,可直接设置整体透明度。 76 | -------------------------------------------------------------------------------- /benchmark.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | CoordMode, ToolTip, Screen 3 | SetBatchLines, -1 4 | 5 | SmallText= 6 | ( 7 | 这是一个演示程序。 8 | this is a demo. 9 | 1234567890 10 | qwertyuiop[] 11 | asdfghjkl;' 12 | zxcvbnm,./ 13 | ) 14 | 15 | LargeText= 16 | ( 17 | The largest, most advanced rover NASA has sent to another world touched down on Mars Thursday, after a 203-day journey traversing 293 million miles (472 million kilometers). Confirmation of the successful touchdown was announced in mission control at NASA’s Jet Propulsion Laboratory in Southern California at 3:55 p.m. EST (12:55 p.m. PST). 18 | 19 | Packed with groundbreaking technology, the Mars 2020 mission launched July 30, 2020, from Cape Canaveral Space Force Station in Florida. The Perseverance rover mission marks an ambitious first step in the effort to collect Mars samples and return them to Earth. 20 | 21 | “This landing is one of those pivotal moments for NASA, the United States, and space exploration globally – when we know we are on the cusp of discovery and sharpening our pencils, so to speak, to rewrite the textbooks,” said acting NASA Administrator Steve Jurczyk. “The Mars 2020 Perseverance mission embodies our nation’s spirit of persevering even in the most challenging of situations, inspiring, and advancing science and exploration. The mission itself personifies the human ideal of persevering toward the future and will help us prepare for human exploration of the Red Planet.” 22 | 23 | About the size of a car, the 2,263-pound (1,026-kilogram) robotic geologist and astrobiologist will undergo several weeks of testing before it begins its two-year science investigation of Mars’ Jezero Crater. While the rover will investigate the rock and sediment of Jezero’s ancient lakebed and river delta to characterize the region’s geology and past climate, a fundamental part of its mission is astrobiology, including the search for signs of ancient microbial life. To that end, the Mars Sample Return campaign, being planned by NASA and ESA (European Space Agency), will allow scientists on Earth to study samples collected by Perseverance to search for definitive signs of past life using instruments too large and complex to send to the Red Planet. 24 | 25 | “Because of today’s exciting events, the first pristine samples from carefully documented locations on another planet are another step closer to being returned to Earth,” said Thomas Zurbuchen, associate administrator for science at NASA. “Perseverance is the first step in bringing back rock and regolith from Mars. We don’t know what these pristine samples from Mars will tell us. But what they could tell us is monumental – including that life might have once existed beyond Earth.” 26 | 27 | Some 28 miles (45 kilometers) wide, Jezero Crater sits on the western edge of Isidis Planitia, a giant impact basin just north of the Martian equator. Scientists have determined that 3.5 billion years ago the crater had its own river delta and was filled with water. 28 | 29 | The power system that provides electricity and heat for Perseverance through its exploration of Jezero Crater is a Multi-Mission Radioisotope Thermoelectric Generator, or MMRTG. The U.S. Department of Energy (DOE) provided it to NASA through an ongoing partnership to develop power systems for civil space applications. 30 | 31 | Equipped with seven primary science instruments, the most cameras ever sent to Mars, and its exquisitely complex sample caching system – the first of its kind sent into space – Perseverance will scour the Jezero region for fossilized remains of ancient microscopic Martian life, taking samples along the way. 32 | 33 | “Perseverance is the most sophisticated robotic geologist ever made, but verifying that microscopic life once existed carries an enormous burden of proof,” said Lori Glaze, director of NASA’s Planetary Science Division. “While we’ll learn a lot with the great instruments we have aboard the rover, it may very well require the far more capable laboratories and instruments back here on Earth to tell us whether our samples carry evidence that Mars once harbored life.” 34 | Paving the Way for Human Missions 35 | 36 | “Landing on Mars is always an incredibly difficult task and we are proud to continue building on our past success,” said JPL Director Michael Watkins. “But, while Perseverance advances that success, this rover is also blazing its own path and daring new challenges in the surface mission. We built the rover not just to land but to find and collect the best scientific samples for return to Earth, and its incredibly complex sampling system and autonomy not only enable that mission, they set the stage for future robotic and crewed missions.” 37 | 38 | The Mars Entry, Descent, and Landing Instrumentation 2 (MEDLI2) sensor suite collected data about Mars’ atmosphere during entry, and the Terrain-Relative Navigation system autonomously guided the spacecraft during final descent. The data from both are expected to help future human missions land on other worlds more safely and with larger payloads. 39 | 40 | On the surface of Mars, Perseverance’s science instruments will have an opportunity to scientifically shine. Mastcam-Z is a pair of zoomable science cameras on Perseverance’s remote sensing mast, or head, that creates high-resolution, color 3D panoramas of the Martian landscape. Also located on the mast, the SuperCam uses a pulsed laser to study the chemistry of rocks and sediment and has its own microphone to help scientists better understand the property of the rocks, including their hardness. 41 | 42 | Located on a turret at the end of the rover’s robotic arm, the Planetary Instrument for X-ray Lithochemistry (PIXL) and the Scanning Habitable Environments with Raman & Luminescence for Organics & Chemicals (SHERLOC) instruments will work together to collect data on Mars’ geology close-up. PIXL will use an X-ray beam and suite of sensors to delve into a rock’s elemental chemistry. SHERLOC’s ultraviolet laser and spectrometer, along with its Wide Angle Topographic Sensor for Operations and eNgineering (WATSON) imager, will study rock surfaces, mapping out the presence of certain minerals and organic molecules, which are the carbon-based building blocks of life on Earth. 43 | 44 | The rover chassis is home to three science instruments, as well. The Radar Imager for Mars’ Subsurface Experiment (RIMFAX) is the first ground-penetrating radar on the surface of Mars and will be used to determine how different layers of the Martian surface formed over time. The data could help pave the way for future sensors that hunt for subsurface water ice deposits. 45 | 46 | Also with an eye on future Red Planet explorations, the Mars Oxygen In-Situ Resource Utilization Experiment (MOXIE) technology demonstration will attempt to manufacture oxygen out of thin air – the Red Planet’s tenuous and mostly carbon dioxide atmosphere. The rover’s Mars Environmental Dynamics Analyzer (MEDA) instrument, which has sensors on the mast and chassis, will provide key information about present-day Mars weather, climate, and dust. 47 | 48 | Currently attached to the belly of Perseverance, the diminutive Ingenuity Mars Helicopter is a technology demonstration that will attempt the first powered, controlled flight on another planet. 49 | 50 | Project engineers and scientists will now put Perseverance through its paces, testing every instrument, subsystem, and subroutine over the next month or two. Only then will they deploy the helicopter to the surface for the flight test phase. If successful, Ingenuity could add an aerial dimension to exploration of the Red Planet in which such helicopters serve as a scouts or make deliveries for future astronauts away from their base. 51 | 52 | Once Ingenuity’s test flights are complete, the rover’s search for evidence of ancient microbial life will begin in earnest. 53 | 54 | “Perseverance is more than a rover, and more than this amazing collection of men and women that built it and got us here,” said John McNamee, project manager of the Mars 2020 Perseverance rover mission at JPL. “It is even more than the 10.9 million people who signed up to be part of our mission. This mission is about what humans can achieve when they persevere. We made it this far. Now, watch us go.” 55 | ) 56 | 57 | Text:=LargeText 58 | gosub, performance 59 | 60 | Text:=SmallText 61 | gosub, performance 62 | 63 | ExitApp 64 | 65 | performance: 66 | ; 显示位置更新+动态内容 67 | ; btt 2114.6、300 68 | ; btt 全局 SetWindowPos 2113.8、298.4 69 | ; btt 新建时 SetWindowPos 2125.6、309.8 70 | ; ToolTip 14864、634 71 | 计时() 72 | loop, 50 73 | { 74 | n++ 75 | ellipsis:="`n" 76 | loop, % Mod(n,20)+1 77 | ellipsis.="." 78 | btt(Text ellipsis, n, n) 79 | } 80 | btt() 81 | 计时() 82 | 83 | 计时() 84 | loop, 50 85 | { 86 | n++ 87 | ellipsis:="`n" 88 | loop, % Mod(n,20)+1 89 | ellipsis.="." 90 | ToolTip, %Text%%ellipsis%, %n%, %n% 91 | } 92 | ToolTip 93 | 计时() 94 | ; --------------------------------- 95 | 96 | 97 | ; 显示位置更新+静态内容 98 | ; btt 217.2、27.6 99 | ; btt 全局 SetWindowPos 213.6、33.2 100 | ; btt 新建时 SetWindowPos 212、31.6 101 | ; ToolTip 10956、549 102 | 计时() 103 | loop, 50 104 | { 105 | n++ 106 | btt(Text, n, n) 107 | } 108 | btt() 109 | 计时() 110 | 111 | 计时() 112 | loop, 50 113 | { 114 | n++ 115 | ToolTip, %Text%, %n%, %n% 116 | } 117 | ToolTip 118 | 计时() 119 | ; --------------------------------- 120 | 121 | 122 | ; 显示位置固定+静态内容 123 | ; btt 197.2、17.2 124 | ; btt 全局 SetWindowPos 211.2、20.6 125 | ; btt 新建时 SetWindowPos 205、19.8 126 | ; ToolTip 7892、270 127 | 计时() 128 | loop, 50 129 | { 130 | btt(Text,100,100) 131 | } 132 | btt() 133 | 计时() 134 | 135 | 计时() 136 | loop, 50 137 | { 138 | ToolTip, %Text%,100,100 139 | } 140 | ToolTip 141 | 计时() 142 | ; --------------------------------- 143 | return 144 | 145 | 计时() 146 | { 147 | Static 148 | if (CounterBefore="") 149 | { 150 | DllCall("QueryPerformanceFrequency", "Int64*", freq) 151 | , DllCall("QueryPerformanceCounter", "Int64*", CounterBefore) 152 | } 153 | else 154 | { 155 | DllCall("QueryPerformanceCounter", "Int64*", CounterAfter) 156 | , 耗时:=(CounterAfter - CounterBefore) / freq * 1000 157 | , CounterBefore:="" 158 | MsgBox, 4096, elapsed time, % Format("{1} ms`r`nOR`r`n{2} m {3} s", 耗时, Floor(耗时/1000/60), Round(Mod(耗时/1000,60))) 159 | } 160 | } -------------------------------------------------------------------------------- /example 1.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | 3 | btt("This is`tBeautifulToolTip") 4 | Sleep, 3000 5 | 6 | CoordMode, ToolTip, Screen 7 | btt("This is`tBeautifulToolTip`nCoordMode = Screen`nWhichToolTip = 2",500,500,2) 8 | Sleep, 5000 9 | 10 | btt() 11 | btt(,,,2) 12 | 13 | ExitApp -------------------------------------------------------------------------------- /example 2.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | SetBatchLines, -1 3 | CoordMode, ToolTip, Screen 4 | 5 | Text1= 6 | ( 7 | ToolTip`t会闪烁。 8 | ToolTip`twill blinking. 9 | 10 | 1234567890 11 | qwertyuiop[] 12 | asdfghjkl;' 13 | zxcvbnm,./ 14 | ) 15 | 16 | Text2= 17 | ( 18 | BeautifulToolTip`t不会闪烁。 19 | BeautifulToolTip`twill not blinking. 20 | 21 | 1234567890 22 | qwertyuiop[] 23 | asdfghjkl;' 24 | zxcvbnm,./ 25 | ) 26 | 27 | SetTimer, Show, 10 28 | Sleep, 10000 29 | ExitApp 30 | 31 | Show: 32 | ToolTip, %Text1%, 500, 200 33 | btt(Text2, 800, 200, 2) 34 | btt(Text2, 500, 350,, "Style1") 35 | return -------------------------------------------------------------------------------- /example 3.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | SetBatchLines, -1 3 | CoordMode, ToolTip, Screen 4 | 5 | Text= 6 | ( 7 | 指定靠近屏幕底部的坐标时,应该显示在屏幕底部,但 ToolTip 会出现在错误的位置。 8 | 9 | When specifying x,y near the bottom of the screen, it should be displayed at the bottom of the screen. 10 | But ToolTip will appear in the wrong place. 11 | 12 | 1234567890 13 | qwertyuiop[] 14 | asdfghjkl;' 15 | zxcvbnm,./ 16 | ) 17 | 18 | SetTimer, Show, 10 19 | Sleep, 10000 20 | ExitApp 21 | 22 | Show: 23 | ToolTip, %Text%,, A_ScreenHeight-1 24 | btt(Text,,A_ScreenHeight-1,,"Style2") 25 | return -------------------------------------------------------------------------------- /example 4.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | SetBatchLines, -1 3 | CoordMode, ToolTip, Client 4 | 5 | Text= 6 | ( 7 | 当坐标模式为 窗口 或 客户区 时,默认使用活动窗口作为目标,同时也能自行指定。 8 | 更多可设置的参数,自行查看 btt() 函数中的说明。 9 | 10 | When the CoordMode is window or client. 11 | By default, the active window is used as target. 12 | But you can also specify your own target. 13 | For more parameters that can be set, see the description in btt() function. 14 | ) 15 | 16 | Gui, +Hwndtarget ; get Hwnd 17 | Gui, Font, s60 18 | Gui, Add, Text, x0 y0 w800 h350 Center, 试试移动窗口。`n`nTry Move this window. 19 | Gui, Font, s20 20 | Gui, Add, Text, x0 y350 w800 h300, 此示例仅提供思路,你需要自行完善。`n`nThis example only provides ideas, you need to improve it by yourself. 21 | Gui, Show, w800 h600 x0 y0 NA 22 | 23 | SetTimer, Show, 10 24 | Sleep, 10000 25 | ExitApp 26 | 27 | Show: 28 | btt(Text,800-1,600-1,,"Style3",{TargetHWND:target}) 29 | return 30 | 31 | GuiClose: 32 | ExitApp 33 | return -------------------------------------------------------------------------------- /example 5.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | SetBatchLines, -1 3 | CoordMode, ToolTip, Screen 4 | 5 | Text= 6 | ( 7 | 使用模板可以轻松创建自己的风格。 8 | 欢迎分享,带张截图!!! 9 | 10 | Use template to easily create your own style. 11 | Please share your custom style and include a screenshot. 12 | It will help a lot of people. 13 | ) 14 | 15 | ; 照着模板改参数就可以创建自己的风格了。建好后可以添加到 btt() 函数里,就可以变内置风格了。 16 | ; You can put your own style in btt() function, then you can use your own style in anywhere. 17 | ; All supported parameters are listed below. All parameters can be omitted. 18 | ; Please share your custom style and include a screenshot. It will help a lot of people. 19 | ; Attention: 20 | ; Color => ARGB => Alpha Red Green Blue => 0x ff aa bb cc => 0xffaabbcc 21 | Template := {Border:20 ; If omitted, 1 will be used. Range 0-20. 22 | , Rounded:30 ; If omitted, 3 will be used. Range 0-30. 23 | , Margin:30 ; If omitted, 5 will be used. Range 0-30. 24 | , BorderColor:0xffaabbcc ; ARGB 25 | , BorderColorLinearGradientStart:0xff16a085 ; ARGB 26 | , BorderColorLinearGradientEnd:0xfff4d03f ; ARGB 27 | , BorderColorLinearGradientAngle:45 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 28 | , BorderColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 29 | , TextColor:0xff112233 ; ARGB 30 | , TextColorLinearGradientStart:0xff00416a ; ARGB 31 | , TextColorLinearGradientEnd:0xffe4e5e6 ; ARGB 32 | , TextColorLinearGradientAngle:90 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 33 | , TextColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 34 | , BackgroundColor:0xff778899 ; ARGB 35 | , BackgroundColorLinearGradientStart:0xff8DA5D3 ; ARGB 36 | , BackgroundColorLinearGradientEnd:0xffF4CFC9 ; ARGB 37 | , BackgroundColorLinearGradientAngle:135 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 38 | , BackgroundColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 39 | , Font:"Font Name" ; If omitted, ToolTip's Font will be used. Can specify the font file. 40 | , FontSize:20 ; If omitted, 12 will be used. 41 | , FontRender:5 ; If omitted, 5 will be used. Range 0-5. 42 | , FontStyle:"Regular Bold Italic BoldItalic Underline Strikeout"} 43 | 44 | ; Same as Style7 45 | OwnStyle1 := {Border:20 46 | , Rounded:30 47 | , Margin:30 48 | , BorderColor:0xffaabbcc 49 | , TextColor:0xff112233 50 | , BackgroundColorLinearGradientStart:0xffF4CFC9 51 | , BackgroundColorLinearGradientEnd:0xff8DA5D3 52 | , BackgroundColorLinearGradientAngle:0 53 | , BackgroundColorLinearGradientMode:8 54 | , FontStyle:"BoldItalic Underline"} 55 | 56 | ; Same as Style8 57 | OwnStyle2 := {Border:3 58 | , Rounded:30 59 | , Margin:30 60 | , BorderColorLinearGradientStart:0xffb7407c 61 | , BorderColorLinearGradientEnd:0xff3881a7 62 | , BorderColorLinearGradientAngle:45 63 | , BorderColorLinearGradientMode:6 64 | , TextColor:0xffd9d9db 65 | , BackgroundColor:0xff26293a} 66 | 67 | ; On white background, FontRender = 4 better than 5 68 | OwnStyle3 := {BorderColor:0x00ffffff 69 | , TextColorLinearGradientStart:0xff00b4db 70 | , TextColorLinearGradientEnd:0xff004360 71 | , TextColorLinearGradientAngle:0 72 | , TextColorLinearGradientMode:1 73 | , BackgroundColor:0x00ffffff 74 | , FontSize:16 75 | , FontRender:4 76 | , FontStyle:"Bold"} 77 | 78 | btt(Text,,200,1,OwnStyle1) 79 | btt(Text,,410,2,OwnStyle2) 80 | btt(Text,,580,3,OwnStyle3) 81 | Sleep,10000 82 | ExitApp -------------------------------------------------------------------------------- /example 6.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | SetBatchLines, -1 3 | 4 | Text= 5 | ( 6 | 淡入淡出。 7 | 8 | Fadein and Fadeout. 9 | ) 10 | 11 | ; fadein 12 | for k, v in [15,35,55,75,95,115,135,155,175,195,215,235,255] 13 | { 14 | btt(Text,,,,"Style4",{Transparent:v}) 15 | Sleep, 30 16 | } 17 | 18 | Sleep, 2000 19 | 20 | ; fadeout 21 | for k, v in [240,220,200,180,160,140,120,100,80,60,40,20,0] 22 | { 23 | btt(Text,,,,"Style4",{Transparent:v}) 24 | Sleep, 30 25 | } 26 | 27 | ExitApp -------------------------------------------------------------------------------- /example 7.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | SetBatchLines, -1 3 | CoordMode, ToolTip, Screen 4 | 5 | MsgBox, 这是一段动画效果演示。`nThis is an animated demo. 6 | 7 | Text= 8 | ( 9 | 使用模板可以轻松创建自己的风格。 10 | 欢迎分享,带张截图!!! 11 | 12 | Use template to easily create your own style. 13 | Please share your custom style and include a screenshot. 14 | It will help a lot of people. 15 | ) 16 | 17 | ; 照着模板改参数就可以创建自己的风格了。建好后可以添加到 btt() 函数里,就可以变内置风格了。 18 | ; You can put your own style in btt() function, then you can use your own style in anywhere. 19 | ; All supported parameters are listed below. All parameters can be omitted. 20 | ; Please share your custom style and include a screenshot. It will help a lot of people. 21 | ; Attention: 22 | ; Color => ARGB => Alpha Red Green Blue => 0x ff aa bb cc => 0xffaabbcc 23 | Template := {Border:20 ; If omitted, 1 will be used. Range 0-20. 24 | , Rounded:30 ; If omitted, 3 will be used. Range 0-30. 25 | , Margin:30 ; If omitted, 5 will be used. Range 0-30. 26 | , BorderColor:0xffaabbcc ; ARGB 27 | , BorderColorLinearGradientStart:0xff16a085 ; ARGB 28 | , BorderColorLinearGradientEnd:0xfff4d03f ; ARGB 29 | , BorderColorLinearGradientAngle:45 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 30 | , BorderColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 31 | , TextColor:0xff112233 ; ARGB 32 | , TextColorLinearGradientStart:0xff00416a ; ARGB 33 | , TextColorLinearGradientEnd:0xffe4e5e6 ; ARGB 34 | , TextColorLinearGradientAngle:90 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 35 | , TextColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 36 | , BackgroundColor:0xff778899 ; ARGB 37 | , BackgroundColorLinearGradientStart:0xff8DA5D3 ; ARGB 38 | , BackgroundColorLinearGradientEnd:0xffF4CFC9 ; ARGB 39 | , BackgroundColorLinearGradientAngle:135 ; Mode=8 Angle 0(L to R) 90(U to D) 180(R to L) 270(D to U) 40 | , BackgroundColorLinearGradientMode:1 ; Mode=4 Angle 0(L to R) 90(D to U), Range 1-8. 41 | , Font:"Font Name" ; If omitted, ToolTip's Font will be used. 42 | , FontSize:20 ; If omitted, 12 will be used. 43 | , FontRender:5 ; If omitted, 5 will be used. Range 0-5. 44 | , FontStyle:"Regular Bold Italic BoldItalic Underline Strikeout"} 45 | 46 | loop, 360 47 | { 48 | ; 通过变换渐变色的角度,可以很容易的实现动画效果。 49 | ; By changing the angle of the color gradient, a simple animation can be easy implement. 50 | Angle:=(A_Index-1)*3 51 | gosub, GetStyles 52 | btt(Text,700,200,1,OwnStyle1) 53 | btt(Text,700,410,2,OwnStyle2) 54 | btt(Text,700,580,3,OwnStyle3) 55 | Sleep, 10 56 | } 57 | ExitApp 58 | 59 | GetStyles: 60 | ; Same as Style7 61 | OwnStyle1 := {Border:20 62 | , Rounded:30 63 | , Margin:30 64 | , BorderColor:0xffaabbcc 65 | , TextColor:0xff112233 66 | , BackgroundColorLinearGradientStart:0xffF4CFC9 67 | , BackgroundColorLinearGradientEnd:0xff8DA5D3 68 | , BackgroundColorLinearGradientAngle:Angle 69 | , BackgroundColorLinearGradientMode:8 70 | , FontStyle:"BoldItalic Underline"} 71 | 72 | ; Same as Style8 73 | OwnStyle2 := {Border:3 74 | , Rounded:30 75 | , Margin:30 76 | , BorderColorLinearGradientStart:0xffb7407c 77 | , BorderColorLinearGradientEnd:0xff3881a7 78 | , BorderColorLinearGradientAngle:Angle+45 79 | , BorderColorLinearGradientMode:6 80 | , TextColor:0xffd9d9db 81 | , BackgroundColor:0xff26293a} 82 | 83 | ; On white background, FontRender = 4 better than 5 84 | OwnStyle3 := {BorderColor:0x00ffffff 85 | , TextColorLinearGradientStart:0xff00b4db 86 | , TextColorLinearGradientEnd:0xff004360 87 | , TextColorLinearGradientAngle:Angle 88 | , TextColorLinearGradientMode:1 89 | , BackgroundColor:0x00ffffff 90 | , FontSize:16 91 | , FontRender:4 92 | , FontStyle:"Bold"} 93 | return -------------------------------------------------------------------------------- /example 8.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | SetBatchLines, -1 3 | 4 | 5 | Text= 6 | ( 7 | btt 拥有返回值。将 JustCalculateSize 设为1,甚至可在不绘制内容的前提下直接返回尺寸。 8 | btt has return values. Set JustCalculateSize to 1, you can even directly get the size from return values without drawing the content. 9 | ) 10 | option:={JustCalculateSize:1} 11 | ret:=btt(Text,200,200,1,"Style5", option) ; btt1 12 | 13 | 14 | Text2= 15 | ( 16 | 我是 btt2,下面显示的是 btt1 的返回值。 17 | I am btt2, the following shows the return values of btt1. 18 | -------------------------------------------------------- 19 | ) 20 | for k, v in ret 21 | Text2.="`n" k "`t: " v 22 | btt(Text2,200,300,2,"Style6") ; btt2 23 | 24 | 25 | Sleep, 10000 26 | ExitApp -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/1.png -------------------------------------------------------------------------------- /img/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/10.png -------------------------------------------------------------------------------- /img/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/11.png -------------------------------------------------------------------------------- /img/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/2.gif -------------------------------------------------------------------------------- /img/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/3.gif -------------------------------------------------------------------------------- /img/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/4.gif -------------------------------------------------------------------------------- /img/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/5.gif -------------------------------------------------------------------------------- /img/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/6.gif -------------------------------------------------------------------------------- /img/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/7.gif -------------------------------------------------------------------------------- /img/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/8.gif -------------------------------------------------------------------------------- /img/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/telppa/BeautifulToolTip/2a174b4569dc25acc2aebb97d8f0515a7a8f2ded/img/9.gif -------------------------------------------------------------------------------- /unit test/test1.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | ; 普通显示 3 | 4 | Text= 5 | ( 6 | 这`t是`t一个`t演示程序。 7 | this`tis`ta`tdemo. 8 | 1234567890 9 | qwertyuiop[] 10 | asdfghjkl;' 11 | zxcvbnm,./ 12 | ) 13 | 14 | Gui, Font, s60 15 | Gui, Add, Text, x0 y0 w800 h600 Center vt, % "A_CoordModeToolTip:`n" A_CoordModeToolTip 16 | Gui, Show, w800 h600 17 | 18 | SetTimer, Show, 10 19 | Sleep, 20000 20 | 21 | ExitApp 22 | 23 | Show: 24 | n++ 25 | ellipsis:="`n" 26 | loop, % Mod(n,20)+1 27 | ellipsis.="." 28 | 29 | if (n>=100) 30 | { 31 | CoordMode, ToolTip, Client 32 | GuiControl, , t, % "A_CoordModeToolTip:`n" A_CoordModeToolTip 33 | } 34 | if (n>=200) 35 | { 36 | CoordMode, ToolTip, Screen 37 | GuiControl, , t, % "A_CoordModeToolTip:`n" A_CoordModeToolTip 38 | } 39 | 40 | btt(Text ellipsis) 41 | btt(Text, A_ScreenWidth, A_ScreenHeight, WhichToolTip:=2, "Style1") 42 | btt(Text, 0 , 0 , WhichToolTip:=3, "Style2") 43 | btt(Text, A_ScreenWidth, 0 , WhichToolTip:=4, "Style3") 44 | btt(Text, 0 , A_ScreenHeight, WhichToolTip:=5, "Style4") 45 | btt(Text, , 100 , WhichToolTip:=6, "Style5") 46 | btt(Text, 100 , , WhichToolTip:=7, "Style6") 47 | btt(Text, 300 , 220 , WhichToolTip:=8, "Style7") 48 | return -------------------------------------------------------------------------------- /unit test/test2.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | ; 超高文字显示 3 | ; CoordMode, ToolTip, Screen 4 | ; CoordMode, ToolTip, Client 5 | 6 | Text= 7 | ( 8 | F 9 | f 10 | 1 11 | 2 12 | 3 13 | 4 14 | 5 15 | 6 16 | 7 17 | 8 18 | 9 19 | 0 20 | a 21 | b 22 | c 23 | d 24 | e 25 | f 26 | g 27 | h 28 | i 29 | j 30 | k 31 | l 32 | m 33 | n 34 | o 35 | p 36 | q 37 | r 38 | s 39 | t 40 | u 41 | v 42 | w 43 | x 44 | y 45 | z 46 | A 47 | B 48 | C 49 | D 50 | E 51 | F 52 | G 53 | H 54 | I 55 | J 56 | K 57 | L 58 | M 59 | N 60 | O 61 | P 62 | Q 63 | R 64 | S 65 | T 66 | U 67 | V 68 | W 69 | X 70 | Y 71 | Z 72 | ) 73 | 74 | Gui, Show, w800 h600 75 | 76 | SetTimer, Show, 10 77 | Sleep, 10000 78 | ExitApp 79 | 80 | Show: 81 | n++ 82 | ellipsis:="`n" 83 | loop, % Mod(n,20)+1 84 | ellipsis.="." 85 | 86 | ; btt(Text) 87 | btt(Text,1000,1000,WhichToolTip:=2,"Style1") 88 | btt(Text ellipsis,0,0,WhichToolTip:=3,"Style2") 89 | btt(Text,,100,WhichToolTip:=4,"Style3") 90 | btt(Text,100,,WhichToolTip:=5,"Style4") 91 | btt(StrReplace(Text, "demo.", "linear gradient demo."),380,50,WhichToolTip:=6,"Style5") 92 | 93 | return -------------------------------------------------------------------------------- /unit test/test3.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | ; 超宽文字显示 3 | ; CoordMode, ToolTip, Screen 4 | ; CoordMode, ToolTip, Client 5 | 6 | Text= 7 | ( 8 | 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 9 | ) 10 | 11 | Text1= 12 | ( 13 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 14 | ) 15 | 16 | Gui, Show, w800 h300 17 | 18 | SetTimer, Show, 10 19 | Sleep, 10000 20 | ExitApp 21 | 22 | Show: 23 | n++ 24 | ellipsis:="`n" 25 | loop, % Mod(n,20)+1 26 | ellipsis.="." 27 | 28 | btt(Text) 29 | ; btt(Text,1000,1000,WhichToolTip:=2,"Style1") 30 | ; btt(Text ellipsis,0,0,WhichToolTip:=3,"Style2") 31 | ; btt(Text,,100,WhichToolTip:=4,"Style3") 32 | btt(Text,100,,WhichToolTip:=5,"Style4") 33 | btt(Text1,,100,WhichToolTip:=6) 34 | ; btt(StrReplace(Text, "demo.", "linear gradient demo."),300,300,WhichToolTip:=6,"Style5") 35 | 36 | return -------------------------------------------------------------------------------- /unit test/test4.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance Force 2 | ; 清空内容 3 | ; Style 切换 4 | ; CoordMode 切换 5 | ; Option 覆盖 6 | 7 | Text= 8 | ( 9 | 这`t是`t一个`t演示程序。 10 | this`tis`ta`tdemo. 11 | 1234567890 12 | qwertyuiop[] 13 | asdfghjkl;' 14 | zxcvbnm,./ 15 | ) 16 | 17 | Gui, Show, w800 h300 18 | 19 | CoordMode, ToolTip, Window 20 | gosub, Show 21 | 22 | CoordMode, ToolTip, Client 23 | gosub, Show 24 | 25 | CoordMode, ToolTip, Screen 26 | gosub, Show 27 | 28 | ExitApp 29 | 30 | Show: 31 | btt(Text,A_ScreenWidth,A_ScreenHeight,,"Style99","Option99") 32 | Sleep, 2000 33 | btt() 34 | Sleep, 1000 35 | btt(Text,A_ScreenWidth,A_ScreenHeight,,"Style2") 36 | Sleep, 2000 37 | return --------------------------------------------------------------------------------