系统托盘图标示例

系统托盘图标示例展示了如何将带有菜单和弹出消息的图标添加到桌面环境的系统托盘中。

系统托盘图标的截图

现代操作系统通常在桌面上提供一个特殊区域,称为系统托盘或通知区域,而长时间运行的应用程序可以在其中显示图标和简短信息。

本例由一个单独的类Window组成,提供主要应用程序窗口(即系统托盘图标的编辑器)及相关图标。

编辑器允许用户选择首选图标,并设置气球消息的类型和持续时间。用户还可以编辑消息的标题和正文。最后,编辑器提供了一个复选框,控制图标是否在系统托盘中显示。

Window类定义

Window类继承自QWidget

class Window : public QDialog
{
    Q_OBJECT

public:
    Window();

    void setVisible(bool visible) override;

protected:
    void closeEvent(QCloseEvent *event) override;

private slots:
    void setIcon(int index);
    void iconActivated(QSystemTrayIcon::ActivationReason reason);
    void showMessage();
    void messageClicked();

private:
    void createIconGroupBox();
    void createMessageGroupBox();
    void createActions();
    void createTrayIcon();

    QGroupBox *iconGroupBox;
    QLabel *iconLabel;
    QComboBox *iconComboBox;
    QCheckBox *showIconCheckBox;

    QGroupBox *messageGroupBox;
    QLabel *typeLabel;
    QLabel *durationLabel;
    QLabel *durationWarningLabel;
    QLabel *titleLabel;
    QLabel *bodyLabel;
    QComboBox *typeComboBox;
    QSpinBox *durationSpinBox;
    QLineEdit *titleEdit;
    QTextEdit *bodyEdit;
    QPushButton *showMessageButton;

    QAction *minimizeAction;
    QAction *maximizeAction;
    QAction *restoreAction;
    QAction *quitAction;

    QSystemTrayIcon *trayIcon;
    QMenu *trayIconMenu;
};

我们实现了一些私有槽以响应用户交互。其他私有函数仅是为了简化构造函数提供的便利函数。

托盘图标是QSystemTrayIcon类的实例。要检查用户的桌面上是否提供系统托盘,请调用静态函数QSystemTrayIcon::isSystemTrayAvailable。与图标相关联,我们提供了一个包含典型最小化最大化还原退出操作的菜单。我们重新实现了QWidget::setVisible()函数,以便在编辑器外观变化时(例如最大化或最小化主应用程序窗口)更新托盘图标的菜单。

最后,我们重新实现了QWidgetcloseEvent()函数,以便在关闭编辑器窗口时通知用户(程序将保持在系统托盘运行,直到用户在图标的上下文菜单中选择退出项。)

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);
}

我们确保应用程序响应用户输入,通过将大多数编辑器输入小部件(包括系统托盘图标)连接到应用程序的私有槽。但请注意可见性复选框;它的toggled()信号连接到图标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() 设置了icon属性,该属性包含实际系统托盘图标。在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枚举来描述图标是如何被激活的。

在构造函数中,我们将图标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描述了在显示提示框消息时显示的图标。然后我们调用QSystemTrayIconshowMessage()函数以毫秒为单位显示消息,包括标题、正文和图标。

macOS用户注意:要显示消息,必须在QSystemTrayIcon::showMessage()中安装Growl通知系统。

QSystemTrayIcon 还有一个相应的,当showMessage()显示的消息被用户点击时发出的messageClicked()信号。

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?"));
}

在构造函数中,我们将messageClicked()信号连接到我们的自定义函数messageClicked()槽,该槽使用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 文件。

示例项目 @ code.qt.io

© 2024 Qt公司有限公司。本文档中包含的文档贡献属于各自的版权所有者。本文档许可条款遵照由自由软件基金会发布的GNU自由文档许可证版本1.3。Qt及其相应标志是芬兰及/或其他国家的Qt公司有限公司的商标。所有其他商标属于其各自的拥有者。