栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Qt实现托盘

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Qt实现托盘

文章目录
    • 前言
    • 总体设计
    • 详细设计
    • Qt的一些小点

前言

我之前为了找工作,花了几天时间了解了下Qt。当时,练手文档在这里:QT小实验-翻金币小游戏 。

前段时间,修改了公司的托盘代码,原来的代码结构设计是很技巧性的。

最近,又看了另一个同事编写的托盘代码,他将界面和功能相分离,代码的质量总体还不错。

我手痒痒,所以空闲时间编写了一个Qt托盘demo。

完整代码见仓库:Qt/tray。该代码编写参考了:Qt官方的托盘代码示例、feiyangqingyun-QWidgetDemo-trayicon

运行结果如下图所示:


总体设计
  1. 托盘带有右键菜单。
  2. 托盘有图标。
  3. 托盘和一个界面相关联。

详细设计

有示例代码可以参考,剩下的是调用API,难度不大。重点代码见下方。

编写托盘可能是下面三个要点:

  1. 托盘本身的设置。包括图标切换,提示信息等。
  2. 右键菜单。
  3. 界面与托盘之间的代码结构关系。
// tray.h

class tray : public QDialog
{
    Q_OBJECT

private:
    std::shared_ptr trayIcon; // 菜单图标
    std::shared_ptr trayMenu; // 菜单上下文
    std::shared_ptr showAction; // 显示选项
    std::shared_ptr versionAction; // 菜单中版本选项
    std::shared_ptr quitAction; // 菜单中退出选项

    std::shared_ptr windowInterface; // 主窗口界面
    bool isShowVersion = false; // 当前正在展示版本界面

private slots:
    void show_version(void);
    void exit(void);

public:
    tray(QWidget *parent = nullptr);
    void createAction(void);
    void createIcon(void);
    ~tray();
};
// tray.cpp
#include "tray.h"

tray::tray(QWidget *parent)
    : QDialog(parent)
{
    QApplication::setQuitOnLastWindowClosed(false); // 程序别因为没有窗口显示而隐式退出,点击托盘中的退出选项才给退出

    // 避免connect的时候连接不到这个对象,先把第一层所有的对象创建出来
    windowInterface.reset(new mainWindow(this));

    createAction();
    createIcon();

    setVisible(false); // 由于继承了QDialog,如果没有这行,运行会弹出一个对话框

    trayIcon->show(); // 显示托盘图标
    windowInterface->show();
}


void tray::createAction()
{
    showAction.reset(new QAction(QString("显示界面"), this));
    connect(showAction.get(), &QAction::triggered, windowInterface.get(), &mainWindow::show);

    versionAction.reset(new QAction(QString("版本"), this));
    connect(versionAction.get(), &QAction::triggered, this, &tray::show_version);

    quitAction.reset(new QAction(QString("退出"),this));
    connect(quitAction.get(), &QAction::triggered, this, &tray::exit);
}


void tray::createIcon()
{
    trayMenu.reset(new QMenu(this));
    trayMenu->addAction(showAction.get());
    trayMenu->addAction(versionAction.get());
    trayMenu->addAction(quitAction.get());
    trayIcon.reset(new QSystemTrayIcon(this));

    trayIcon.reset(new QSystemTrayIcon(this));
    trayIcon->setIcon(QIcon(":/image/flow.ico"));
    trayIcon->setContextMenu(trayMenu.get());
}


void tray::show_version()
{
    if(isShowVersion) {
        return;
    }

    isShowVersion = true;
    QMessageBox versionInterface = QMessageBox(this);
    versionInterface.setText("Tray's version is 0.0.0");

    // 如果只有一个按钮,关闭和escap key也会默认使用这个按钮。所以我们再添加一个不显示的no按钮
    versionInterface.setStandardButtons(QMessageBox::Ok);
    versionInterface.button(QMessageBox::Ok)->setText("Qt版本");
    versionInterface.addButton(QMessageBox::No)->hide();

    int ret = versionInterface.exec(); // 使用模态对话框
    if(ret == QMessageBox::Ok) {
        QApplication::aboutQt();
    }
    isShowVersion = false;
}


void tray::exit()
{
    trayIcon->hide(); // QSystemTrayIcon没有close函数,调用hide
    QApplication::quit(); // 退出程序
}


tray::~tray()
{
}

Qt的一些小点

目前没有建立起对Qt的面的认识,用的时候去查下。

目前没有系统的去看Qt的书籍,似乎也没有必要。因为,我不关心某个对话框或者图标这样细枝末节的知识点,这些内容用的时候查下就好。我需要的是高屋建瓴式的对于Qt本身结构方面的介绍。(似乎也没有那个必要,工具能用就好。)

推荐资料:feiyangqingyun/QWidgetDemo

下面,我介绍点上面代码细节。

  1. 上面代码我使用了很多智能指针。在C++中,在堆上创建的对象,使用智能指针管理,是个好的习惯。但是在Qt中,似乎不必完全如此。我们可以多多的使用对象树 。
  2. 编写tray类的时候,我们让它继承了QDialog类。反过来想下,如果我们不继承QDialog类会怎么样?我们编写的是托盘代码,似乎不需要对话框的功能。确实我们不需要对话框的功能,但我们需要QObject的功能。可以参考QObject详解
  3. Q_OBJECT 宏必须出现在声明自己的信号和槽或使用 Qt 元对象系统提供的其他服务的类定义的私有部分中。如果使用cmake作为构建系统,我们会看到set(CMAKE_AUTOMOC ON)。我们到安装Qt的目录中也能找见moc.exe可执行程序。可以参考Qt 元对象系统
  4. QMessageBox中,我使用了exec方法,而没有使用show方法。这两个的区别是阻塞与非阻塞。可以参考: modal dialog。而关于 QMessageBox的使用,我不喜欢读英文,可以参考Qt QMessageBox用法详解
  5. 对于有托盘的程序,当最后一个页面关闭的时候,程序也不退出,需要设置setQuitOnLastWindowClosed为false。
  6. 当使用信号和槽函数的时候,我们需要确保槽函数的对象已经创建出来,否则默认为空指针。信号和槽函数的介绍,可以参考Signals & Slots
  7. 在设置QMessageBox按钮的时候,如果没有QMessageBox::No按钮的时候,建议添加一个隐藏的该按钮。这也是无奈的做法。因为,当没有设置QMessageBox::escapeButton函数的时候,按下esc键,如果此时仅仅设定了一个按钮,会默认使用这个这个按钮功能。关闭按钮,测试了下,也是如此。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/965576.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号