Qt显示Linux desktop natification气泡提示框
在现代linux桌面环境上我们时常可以看到类似的消息框:
这些消息框常用在如下场景:
- 即时聊天软件的新消息
- 闹钟定时提示
- 电池电量提示
- 邮件消息
- 长耗时操作的完成提示
在freedesktop.org的规范中这种消息框被称为desktop notification
,中文名我们形象得称其为“气泡框”。通过调用d-bus服务org.freedesktop.notifications
提供的接口即可显示在桌面上。
所以我们先了解一下这个d-bus服务。
org.freedesktop.notifications概览
一个气泡框消息通常会包含如下的属性:
名称 | 说明 |
---|---|
application name | 标示发送消息的程序,最好使用程序全名 |
replaces id | 可选的消息id,服务器通过id控制消息框的渲染,通常不用关注 |
icon | 显示在气泡框上的图标 |
summary | 标题,只能显示一行,叫title应该更合适 |
body | 消息体,支持部分html标签;<b></b> ;<i></i> ;<u></u> ;<a></a> ;<img src=... alt=...>
|
actions | 显示一些按钮或者菜单(qaction),不过这一功能通常未被实现 |
hints | 为消息体提供的额外数据,比如显示在屏幕的位置(x,y坐标) |
expiration timeout | 气泡框显示的时长,单位毫秒;指定为-1时行为取决于实现;为0时气泡框将一直显示在桌面上直到用户点击 |
其中icon
和hints中的image_path
必须为本地绝对路径或者file://
开头的文件url。另外使用桌面环境预定义图标的名字也是可以的。
气泡框还有三个紧急程度可供选择:
名称 | 值 | 说明 |
---|---|---|
low | 0 | 默认值,可以设置如何显示,应该设置一个合理的显示时间以便气泡框可以隐藏退出 |
normal | 1 | 同low |
critical | 2 | 代表重要通知,不应该自动过期隐藏 |
所有的气泡框消息请求都是异步的,通常构造请求并发送后用户就可以不再关心后续的信息,如果有特殊需要则可以自定义处理org.freedesktop.notifications
发送的信号。
得益于freedesktop.org的标准规范,包括kde,gnome,xfce4在内的许多桌面环境都提供了对desktop notification
的支持,虽然外观上可能存在一些差异但是创建气泡框的方法是一样的。
不过不用担心,我们不会直接去使用d-bus,因为已经有简化的现成方案可供选择了。下面就让我们一起看看这些方案。
方案一:调用外部命令
可能你已经知道了,我要介绍的命令就是notify-send
。
notify-send
几乎被所有的桌面环境和发行版支持,它依赖于后面会介绍的libnotify和glib,如果你的系统上没有安装可以使用如下命令进行安装:
debian/ubuntu:
sudo apt install libnotify-bin
arch linux:
sudo pacman -s libnotify
安装后可以用如下命令显示气泡框:
# notify-send title body [options] notify-send test 'this is a desktop notification test.' -t 10000
-t
参数设置超时时间。效果如下:
具体的参数可以参考这里:
方案二:通过编程方式实现
在qt代码中调用外部命令就可以显示气泡框,然而这种方式不够灵活,所以我们需要使用前面提到的libnotify在我们的代码里生成并显示气泡框。
libnotify对各个语言都提供了binding,可以参考这里。
这里我们选择使用golang的binding:
package main import ("github.com/mqu/go-notify") func main() { notify.init("hello world") hello := notify.notificationnew("hello world!", "this is an example notification.","dialog-information") hello.settimeout(5000) hello.show() }
上面的代码将会显示一个可以在桌面停留5s的气泡框:
不过如果每次都要使用一大串代码才能显示消息的话必然是低效的,而且需要换算时间至毫秒,所以我写了一个帮助函数在:
// shownotification 显示org.freedesktop.notifications气泡消息框 // duration == -1时使用默认delay // duration == 0表示不设置超时,desktop notification将会一直显示 func shownotification(title, text, image string, delay time.duration) { var notifydelay int32 if delay == -1 { notifydelay = duration2millisecond(defaultnotifydelay) } else { notifydelay = duration2millisecond(delay) // 不合法值(包括duration不足1ms),使用默认值进行替换 if notifydelay == -1 { notifydelay = duration2millisecond(defaultnotifydelay) } } libnotify.init(applicationname) notify := libnotify.notificationnew(title, text, image) if notify == nil { fmt.fprintf(os.stderr, "unable to create a new notification\n") return } notify.settimeout(notifydelay) notify.show() } // duration2millisecond 将time.duration转换成millisecond // duration不足1ms将返回-1 func duration2millisecond(duration time.duration) int32 { res := int32(duration / time.millisecond) if res < 0 { return -1 } return res }
首先将时间值转换成毫秒数,如果太小或者不合法就使用默认的停留时间。applicationname是程序的完整名称。
因为气泡框消息是异步的,所以在调用了show()
之后函数就会返回,后续操作xwindows都会帮我们处理,所以这个函数调用之后是立刻返回的,不会阻塞qt的gui事件循环,可以放心的使用:
// download something success shownotification("下载", "文件下载完成", "dialog-information", 5*time.second)
这样我们也可以轻松地在我们的qt程序中使用气泡消息框了。
参考:
上一篇: Win11预览版更新!带你围观Win11全新内置功能
下一篇: 我不想要小孩