开始

脚本位置点这

在实际使用ahk时,常常要使用tooltip提示程序的运行结果。
比如:

  • 增加屏幕亮度后显示当前亮度;
  • 锁定鼠标后提示鼠标已锁定;
  • 提示Run的运行结果;
  • ……

在最后需要使用SetTimer 指定几秒种后使用Tooltip ,,, [weight] 关闭tooltip。

这部分工作包括显示tooltip显然是可以封装的。

脚本

脚本方法设计为自动与手动两种方式:

  • 静态方法ShowTip -> 显示指定文本并在指定时间后移除。
  • 构造方法 -> 返回封装的对象,手动控制显示与销毁。

对于静态方法ShowTip有reuse参数,表示是否始终使用同一个Weight(20),即是否允许多个ToolTip。

使用

; 使用静态方法
Tip.ShowTip('hello')  ; 默认4s后隐藏
; 使用静态方法返回值
clear := Tip.ShowTip('hello') ; clear方法仅在reuse为ture时返回
Sleep(1000), clear()  ; 1s后手动销毁

; ---

; 使用构造方法
_t := Tip('hello')
_t.Display() ; 显示
Sleep 1000
_t.Recycle() ; 销毁

通过此脚本可以不再烦恼Tip的显示问题。

代码

此脚本位于仓库ahk-lib/Tip.ahk
仓库:https://gitee.com/dkwd/ahk-lib.git

#Requires AutoHotkey v2.0

#Include extend\Set.ahk

CoordMode 'ToolTip', 'Screen'

class Tip {
  static pool := Set()

  __New(text, weight := 1, x := unset, y := unset) {
    MouseGetPos(&mx, &my)
    IsSet(x) || x := mx, IsSet(y) || y := my
    if weight < 1 or weight >= 20
      throw Error('invalid weight')
    if Tip.pool.Has(weight)
      weight := this.GetAvailable()
    if !weight
      throw Error('no available')
    this.text := text, this.x := x, this.y := y, this.weight := weight
    Tip.pool.Add(weight)
  }

  GetAvailable() {
    index := 1
    while Tip.pool.Has(index)
      index++
    return index >= 20 ? 0 : index
  }

  Display() {
    ToolTip this.text, this.x, this.y, this.weight
    return this
  }

  Recycle() => (Tip.pool.Delete(this.weight), ToolTip(, , , this.weight))

  static ShowTip(text, x := 100, y := 50, duration := 4000, reuse := true) {
    return reuse
      ? _setTimerRemoveSingleToolTip(text, x, y, duration)
      : _setTimerRemoveMultiToolTip(text, x, y, duration)

    _setTimerRemoveSingleToolTip(text, x, y, time) {
      static clear := (*) => ToolTip(, , , 20)
      if !text
        return clear()
      ToolTip text, x, y, 20
      if !time
        return clear
      SetTimer clear, -time
    }

    _setTimerRemoveMultiToolTip(text, x, y, time) {
      if !text
        return
      t := Tip(text, , x, y), t.Display(), later := (*) => t.Recycle()
      SetTimer later, -time
    }
  }
}

补充

下面是引入的外部脚本Set.ahk,实际上直接使用Map就行。

#Requires AutoHotkey v2.0

#Include _Array.ahk

class Set extends Map {
  __new(value*) {
    kv := []
    value.foreach(v => kv.Push(v, 0))
    super.__New(kv*)
  }

  Add(e*) {
    for v in e {
      if this.Has(v)
        return false
      super.Set(v, 0)
    }
    return true
  }

  Count => super.Count
  Has(e) => super.Has(e)
  Clear() => super.Clear()
  Delete(e) => super.Delete(e)
}

UI版本

最近,我实现的使用ui的版本,相比于原生的api,自定义性更多了。
api与上面的完全一致。
效果如下:

image

(下面的是进度条)

脚本也在仓库中,具体代码如下:

; Tip.ahk 的ui版本
#Requires AutoHotkey v2.0

#Include Theme.ahk
#Include util\Animation.ahk

/*
; ======== 使用静态方法
DCon TipUI.ShowTip('halo'), &x, &y, &w, &h ; 可以解构出x,y,w,h,duration
TipUI.ShowTip('xcatp', , y + h + 10)
; ======== 自己new
t := TipUI('meow', 100, 100, 1000, Noop)
t.Start() ; 开始
t.Stop() ; 内部使用的方法,调用后就停止了(无法恢复)
t.Destroy() ; 销毁
*/
class TipUI extends Gui {

  __New(text, x, y, duration, onRClick) {
    if duration <= 100
      throw Error('必须大于100')
    super.__New('+AlwaysOnTop +ToolWindow -Caption +Border')
    this.SetFont('s13', 'consolas')
    this.AddText('Section x16 y5', text).GetPos(, , &w)
    this.AddText('xs y25 Backgroundffd500 h1 w' w)
    this.OnEvent('ContextMenu', onRClick)

    Theme.Dark(this), this.Show('hide'), this.GetPos(, , &w, &h)
    this.p := this.AddText('x0 y' h - 4 ' Backgroundff2323 h3 w' w)
    this.data := [x, y, w, h, duration]
  }

  Start() {
    DCon(this.data, &x, &y, &w, , &time), this.Show('NA x' x ' y' y)
    t := 100, i := 0, _w := w / t, _d := time / t
    SetTimer(d, _d), this.Stop := (*) => SetTimer(d, 0)
    return this.data

    d() {
      this.p.Move(, , w - _w * i), i++
      if i >= t
        Animation.FadeOut(this)
    }
  }

  Destroy() => (this.Stop(), super.Destroy())

  static ShowTip(text, x := 100, y := 50, duration := 4000, onRClick := Noop)
    => TipUI(text, x, y, duration, onRClick).Start()
}
posted on 2023-08-17 16:21  落寞的雪  阅读(774)  评论(2编辑  收藏  举报