「Qt Widget中文示例指南」如何实现一个系统托盘图标?(二)
Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。
System Tray Icon(系统托盘图标)示例展示了如何将带有菜单和弹出消息的图标添加到桌面环境的系统托盘中。
系统托盘图标的截图
点击获取Qt Widget组件下载
在上文中(点击这里回顾>>),我们为大家介绍了如何定义Window类,本文将继续介绍如何实现Window类。
Window类实现
在构建编辑器小部件时,创建实际的系统托盘图标之前,我们首先创建各种编辑器元素:
Window::Window()
{
createIconGroupBox();
createMessageGroupBox();
iconLabel->setMinimumWidth(durationLabel->sizeHint().width());
createActions();
createTrayIcon();
connect(showMessageButton, &QAbstractButton::clicked, this, &Window::showMessage);
connect(showIconCheckBox, &QAbstractButton::toggled, trayIcon, &QSystemTrayIcon::setVisible);
connect(iconComboBox, &QComboBox::currentIndexChanged,
this, &Window::setIcon);
connect(trayIcon, &QSystemTrayIcon::messageClicked, this, &Window::messageClicked);
connect(trayIcon, &QSystemTrayIcon::activated, this, &Window::iconActivated);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(iconGroupBox);
mainLayout->addWidget(messageGroupBox);
setLayout(mainLayout);
iconComboBox->setCurrentIndex(1);
trayIcon->show();
setWindowTitle(tr("Systray"));
resize(400, 300);
}
我们通过将大多数编辑器的输入小部件(包括系统托盘图标)连接到应用程序的专用槽来确保应用程序响应用户输入,但请注意可见性复选框,它的toggle()信号连接到图标的setVisible()函数。
void Window::setIcon(int index)
{
QIcon icon = iconComboBox->itemIcon(index);
trayIcon->setIcon(icon);
setWindowIcon(icon);
trayIcon->setToolTip(iconComboBox->itemText(index));
}
每当图标组合框中的当前索引发生变化时,也就是说,每当用户在编辑器中选择另一个图标时,就会触发setIcon()插槽。注意,当用户用鼠标左键激活托盘图标,触发图标的activated()信号时,也会调用该函数,我们稍后会回到这个信号。
QSystemTrayIcon::setIcon()函数设置保存实际系统托盘图标的图标属性,在Windows上,系统托盘图标的大小是16x16;在X11上,首选的尺寸是22x22,图标将根据需要缩放到适当的大小。
注意在X11上,由于系统托盘规范的限制,鼠标单击图标中的透明区域将传播到系统托盘。如果这种行为是不可接受的,我们建议使用一个没有透明度的图标。
void Window::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
switch (reason) {
case QSystemTrayIcon::Trigger:
case QSystemTrayIcon::DoubleClick:
iconComboBox->setCurrentIndex((iconComboBox->currentIndex() + 1) % iconComboBox->count());
break;
case QSystemTrayIcon::MiddleClick:
showMessage();
break;
default:
;
}
}
每当用户激活系统托盘图标时它都会发出activated()信号,传递触发原因作为参数,QSystemTrayIcon提供ActivationReason enum来描述图标是如何被激活的。
在构造函数中,我们将图标的activated()信号连接到自定义的iconActivated()槽:如果用户使用鼠标左键单击了图标,该函数通过增加图标组合框的当前索引来改变图标图像,触发如上所述的setIcon()槽。如果用户使用鼠标中键激活图标,则调用自定义showMessage()槽:
void Window::showMessage()
{
showIconCheckBox->setChecked(true);
int selectedIcon = typeComboBox->itemData(typeComboBox->currentIndex()).toInt();
QSystemTrayIcon::MessageIcon msgIcon = QSystemTrayIcon::MessageIcon(selectedIcon);
if (selectedIcon == -1) { // custom icon
QIcon icon(iconComboBox->itemIcon(iconComboBox->currentIndex()));
trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), icon,
durationSpinBox->value() * 1000);
} else {
trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), msgIcon,
durationSpinBox->value() * 1000);
}
}
当触发showMessage()槽时,我们首先根据当前选择的消息类型检索消息图标。QSystemTrayIcon::MessageIcon enum描述了当显示气球消息时显示的图标,然后调用 QSystemTrayIcon 的showMessage()函数,在指定的毫秒时间内显示带有标题、正文和图标的消息。
macOS用户注意:QSystemTrayIcon::showMessage()显示消息需要安装Growl通知系统。
QSystemTrayIcon也有相应的messageclick()信号,该信号在用户单击showMessage()显示的消息时发出。
void Window::messageClicked()
{
QMessageBox::information(nullptr, tr("Systray"),
tr("Sorry, I already gave what help I could.\n"
"Maybe you should try asking a human?"));
}
在构造函数中,我们将messageclick()信号连接到自定义messageclick()插槽,该插槽使用QMessageBox类简单地显示一条消息。
QMessageBox提供了一个模态对话框,其中包含一条短消息、一个图标和根据当前样式布局的按钮。它支持四个严重级别:“问题”、“信息”、“警告”和“紧急”。在Qt中弹出消息框最简单的方法是调用相关的静态函数之一,例如QMessageBox::information()。
正如我们前面提到的,重新实现了几个QWidget的虚函数:
void Window::setVisible(bool visible)
{
minimizeAction->setEnabled(visible);
maximizeAction->setEnabled(!isMaximized());
restoreAction->setEnabled(isMaximized() || !visible);
QDialog::setVisible(visible);
}
我们的QWidget::setVisible()函数重新实现在编辑器的外观发生变化时更新托盘图标的菜单,例如,在调用基类实现之前最大化或最小化主应用程序窗口。
void Window::closeEvent(QCloseEvent *event)
{
if (!event->spontaneous() || !isVisible())
return;
if (trayIcon->isVisible()) {
QMessageBox::information(this, tr("Systray"),
tr("The program will keep running in the "
"system tray. To terminate the program, "
"choose <b>Quit</b> in the context menu "
"of the system tray entry."));
hide();
event->ignore();
}
}
我们已经重新实现了QWidget::closeEvent()事件处理程序来接收小部件关闭事件,并在用户关闭编辑器窗口时向他们显示上述消息。我们需要避免在用户真正打算退出应用程序时显示消息并接受关闭事件:即当用户在菜单栏中触发“退出”时,或者在托盘图标的上下文菜单中,或者在macOS上按下Command+Q快捷键时。
除了上面讨论的函数和槽,我们还实现了几个方便的函数来简化构造函数:createIconGroupBox(), createMessageGroupBox(), createActions()和createTrayIcon(),具体请参见desktop/systray/window.cpp文件。
Qt Widget组件推荐
- QtitanRibbon - Ribbon UI组件:是一款遵循Microsoft Ribbon UI Paradigm for Qt技术的Ribbon UI组件,QtitanRibbon致力于为Windows、Linux和Mac OS X提供功能完整的Ribbon组件。
- QtitanChart - Qt类图表组件:是一个C ++库,代表一组控件,这些控件使您可以快速地为应用程序提供漂亮而丰富的图表。
- QtitanDataGrid - Qt网格组件:提供了一套完整的标准 QTableView 函数和传统组件无法实现的独特功能。使您能够将不同来源的各类数据加载到一个快速、灵活且功能强大的可编辑网格中,支持排序、分组、报告、创建带状列、拖放按钮和许多其他方便的功能。
- QtitanDocking:允许您像 Visual Studio 一样为您的伟大应用程序配备可停靠面板和可停靠工具栏。黑色、白色、蓝色调色板完全支持 Visual Studio 2019 主题!