【QT常用技术讲解】任务栏图标+socket网络服务+开机自启动

news2024/11/14 6:45:07

前言

        首先看网络编程的定义:两个不同主机设备之间的进程通信。C/S(Client-Server)是早期非常典型的软件架构,C/S架构虽然简单,但却非常适用于桌面图形化的QT项目。

        本篇的QT项目是从真实的项目中简化出来,满足很多相似的场景:创建一个TCP服务,接收到消息后,通过多线程执行后台CMD命令行,并且自动把程序放到系统自启动目录中。

        覆盖到QT的知识点:任务栏托盘、右键菜单、TCP服务、多线程。

功能讲解

1、创建系统托盘

// 创建托盘图标
    QSystemTrayIcon *trayIcon = new QSystemTrayIcon();
    trayIcon->setIcon(QIcon(":/index/img/default.png")); // 设置托盘图标
// 创建上下文菜单
    QMenu *menu = new QMenu();
// 添加菜单项
    menu->addAction(exitAction);
    trayIcon->setContextMenu(menu);

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

2、托盘右键菜单

// 创建上下文菜单
    QMenu *menu = new QMenu();
    QAction *showAction = new QAction("执行后台命令", &app);//测试用
    // 连接信号与槽
    QObject::connect(showAction, &QAction::triggered, []() {
        //测试:打开谷歌浏览器
        QString cmd = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
        cmdrun act;
        act.Run(cmd);
    });

    QAction *exitAction = new QAction("退出", &app);
    QObject::connect(exitAction, &QAction::triggered, &app, &QApplication::quit);

    // 添加菜单项
    menu->addAction(showAction);
    menu->addAction(exitAction);
    trayIcon->setContextMenu(menu);

showAction事件只是用来测试点击右键之后,执行本地的CMD命令是否正常,适合用来调用第三方软件达到指定的目的(比如通过window的powershell脚本获取指定EXE执行程序的图标),调通之后就可以注释掉,用TCP创建的服务执行本地的CMD命令。

3、TCP服务

首先,需要在.pro文件中加上network,编译时才不会报错

QT       += core gui network

tcp服务头文件:

#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QObject>

//请求包结构
typedef struct  netPackQ
{
    char opCode[2];//暗号校验头--校验不对的直接丢弃
    char keyword[254];//交互的核心内容
    netPackQ(){
        memset(opCode,0,2);
        memset(keyword,0,254);
    }
} netPackQ;

class Mytcpserver: public QObject {
    Q_OBJECT

public:
    Mytcpserver(QObject *parent = nullptr);

    private slots:
        void onNewConnection();

    private:
        QTcpServer *server;
};

#endif // MYTCPSERVER_H

TCP主文件:

#include "mytcpserver.h"
#include "cmdrun.h"

Mytcpserver::Mytcpserver(QObject *parent) : QObject(parent) {
    // 创建 TCP 服务器
    server = new QTcpServer(this);

    // 连接新连接信号到槽函数
    connect(server, &QTcpServer::newConnection, this, &Mytcpserver::onNewConnection);

    // 绑定到 10086 端口
    if (!server->listen(QHostAddress::Any, 10086)) {
        qDebug() << "Server could not start!";
    } else {
        qDebug() << "Server started on port 10086.";
    }
}


void Mytcpserver::onNewConnection() {
    QTcpSocket *socket = server->nextPendingConnection();

    // 连接读取数据信号
    connect(socket, &QTcpSocket::readyRead, [socket]() {
        netPackQ packet;
        qint64 bytesReceived = socket->read(reinterpret_cast<char*>(&packet), sizeof(netPackQ));
        if (bytesReceived == sizeof(netPackQ)) {
            // 处理接收到的数据
            qDebug() << "Received date";
            if(packet.opCode[0] == 0x01 && packet.opCode[1]==9){//执行后台命令,打开指定应用。比如:C:\Windows\notepad.exe
                qDebug() << "Received keyword:" << packet.keyword;
                cmdrun act;
                act.Run(packet.keyword);//====处理核心内容=====
            }
            socket->write("Received sucess\n"); // 回复客户端
        } else {
            qDebug() << "Received incomplete data";
        }
    });

    // 连接断开信号
    connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
}

4、多线程执行后台CMD命令

直接用进程执行CMD命令会导致托盘卡顿,所以得用多线程来执行,cmdrun类很简单,如下:

//头文件:cmdrun.h
#ifndef CMDRUN_H
#define CMDRUN_H
#include<QString>
#include "threadCmd.h"
class cmdrun
{
public:
    cmdrun();
    ~cmdrun();
    int Run(QString cmd);
};

#endif // CMDRUN_H


//cpp文件:cmdrun.cpp
#include "cmdrun.h"
#include <QDebug>

cmdrun::cmdrun()
{

}

cmdrun::~cmdrun()
{

}

int cmdrun::Run(QString cmd){
    //qDebug() << __LINE__ << cmd;
    ThreadCmd *thread = new ThreadCmd(cmd);
    thread->start();

    return 1;
}

5、多进程执行CMD命令

//头文件:threadCmd.h
#ifndef THREADCMD_H
#define THREADCMD_H

#include <QThread>
#include <QString>

class ThreadCmd : public QThread
{
    Q_OBJECT
public:
    explicit ThreadCmd(const QString &param) ;

protected:
    void run() override;

private:
    QString m_param;
};

#endif // THREADCMD_H


//cpp文件:threadCmd.cpp
#ifndef THREADCMD_CPP
#define THREADCMD_CPP

#include "threadCmd.h"
#include <QDebug>
#include <QProcess>
#include <QTextCodec>

ThreadCmd::ThreadCmd(const QString &param) : m_param(param) {

}

void ThreadCmd::run(){
    QProcess process;
    // 执行命令
    QString cmd = "D:\\cmdexec.cmd \"" + m_param +"\"";
    //QString cmd = m_param;
    //qDebug() << __LINE__ << cmd;
    // 启动快捷方式
    if (QProcess::startDetached(cmd)) {
        qDebug() << "Application launched successfully.";
    } else {
        qDebug() << "Failed to launch application.";
    }
    // 进程使用完毕后,可以手动删除
    process.deleteLater();
}


#endif // THREADCMD_CPP

6、开机自启动

系统托盘通常都有开机自启动的需求,可以手动拷贝到启动目录,或者在程序中编写把应用程序的.lnk文件放到自启动目录中:

void addToStartup(const QString appPath) {
    QString startupPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/Startup/";

    //qDebug()<< __LINE__ << startupPath;
    // 创建启动文件夹(如果不存在)
    QDir dir(startupPath);
    if (!dir.exists()) {
        dir.mkpath(".");
    }

    // 创建快捷方式(Windows 特有)
    QString shortcutPath = startupPath + "cstsvr.lnk";

    if (!QFile::exists(shortcutPath)) {
        // 使用 PowerShell 创建快捷方式 (请根据实际情况调整)
        QString command = QString("powershell -command \"$ws = New-Object -ComObject WScript.Shell; $s = $ws.CreateShortcut('%1'); $s.TargetPath='%2'; $s.Save()\"").arg(shortcutPath).arg(appPath);
        QProcess::execute(command);
    }
}


int main(int argc, char *argv[]) {
    QApplication  app(argc, argv);
    // 获取当前应用程序的完整路径
    QString appPath = QCoreApplication::applicationFilePath();
    //qDebug()<< __LINE__ << appPath;
    addToStartup(appPath);// 添加自启动到启动文件夹
    .......
}

篇尾

        不同主机之间的进程间通信,通常需要设定一端为服务端进行侦听,当然也可以两端都设置为服务端,服务端≠服务器,服务端只代表某项服务的侦听端,比如本篇涉及的项目需求是,国产Linux系统需要获取window系统的所有应用程序的图标,并且取回到国产Linux系统的QT界面中展示,此时就需要在window系统上挂着【根据exe应用路径获取图片】的服务端,并把文件回传给Linux。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2238765.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++课程学习】:二叉搜索树

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C课程学习 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 二叉树搜索树的概念&#xff1a; 节点的结构&#xff1a; ⚽️结构&#xff1a; ⚽️ 构造函数&…

Axure是什么软件?全方位解读助力设计入门

在产品设计和开发领域&#xff0c;Axure是一款大名鼎鼎且功能强大的软件&#xff0c;它为专业人士和团队提供了卓越的设计支持&#xff0c;帮助他们将创意转化为实际可操作的产品原型。 一、Axure 的基本介绍 Axure是一款专业的原型设计工具&#xff0c;主要用于创建交互式的…

java里面使用groovy案例+详解

场景&#xff1a; 最近有一个计算商品运费的&#xff0c;如果商品的数量大于快递公司设置的数量 10 那么超出部分也需要计算额外运费&#xff0c;那么这些计算过程代码我能不能不在java里面写呢&#xff0c;用一种可配置化的方式来根据不同的传参计算出运费&#xff1f; 页面传…

单体架构 IM 系统之核心业务功能实现

在上一篇技术短文&#xff08;单体架构的 IM 系统设计&#xff09;中&#xff0c;我们讨论了在 “用户规模小、开发人员少、开发时间短” 的业务背景下&#xff0c;采取 “怎么简单怎么做&#xff0c;怎么快怎么来” 的研发策略&#xff0c;于是设计了 单体架构的IM系统&#x…

Linux部署nginx访问文件403

问题描述&#xff1a;在linux服务器上通过nginx部署&#xff0c;访问文件403 新配置了一个用户来部署服务&#xff0c;将部署文件更新到原有目录下&#xff0c;结果nginx访问403 原因&#xff1a;没有配置文件的读写权限&#xff0c;默认不可读写&#xff0c;nginx无法访问到文…

解决 C/C++ 中 “invalid use of incomplete type” 编译错误

解决 C/C++ 中 “invalid use of incomplete type” 编译错误 一、错误原因二、常见场景三、解决方法四、最佳实践五、总结在 C 和 C++ 编程中,invalid use of incomplete type 错误通常发生在尝试使用一个未完全定义的类型时。这个错误表明编译器在当前上下文中没有足够的信息…

使用 Python 实现高效网页爬虫——从获取链接到数据保存

前言 在这个时代,网络爬虫已成为数据分析与信息收集不可或缺的技术之一。本文将通过一个具体的Python项目来介绍如何构建一个简单的网络爬虫,它能够自动抓取指定网站的文章链接、标题、正文内容以及图片链接,并将这些信息保存为CSV文件。 目标网站 一、准备工作 在开始编…

C# 有趣的小程序—桌面精灵详细讲解

C# 桌面精灵详细讲解 最近写了一个简化版桌面精灵&#xff0c;效果如图所示&#xff0c;可以实现切换动画&#xff0c;说话、鼠标拖动&#xff0c;等功能。具体如何做&#xff0c;我发布了一个资源里面包含ppt详解、源代码以及动画素材。放心吧&#xff0c;免费的&#xff0c;…

微软日志丢失事件敲响安全警钟

NEWS | 事件回顾 最近&#xff0c;全球最大的软件公司之一——微软&#xff0c;遭遇了一场罕见的日志丢失危机。据报告&#xff0c;从9月2日至9月19日&#xff0c;持续长达两周的时间里&#xff0c;微软的多项核心云服务&#xff0c;包括身份验证平台Microsoft Entra、安全信息…

Mysql ERROR 1451 (23000) 外键处理异常

通过临时设置外键失效&#xff0c;来规避报错 第一步 # 临时设置外键失效 SET FOREIGN_KEY_CHECKS 0; 第二步&#xff1a;执行更新或者删除操作 第三步&#xff1a; # 操作结束后恢复外键 SET FOREIGN_KEY_CHECKS 1;

智慧社区可视化解决方案:科技引领社区服务与管理新篇章

随着社会的发展&#xff0c;智慧社区作为新型城镇化发展目标和社区服务体系建设的重要举措&#xff0c;正逐步改变着我们的生活方式。智慧社区通过综合运用现代科学技术&#xff0c;整合区域资源&#xff0c;提升社区治理和服务水平&#xff0c;为居民提供更为便捷、高效、安全…

基于redis实现API接口访问次数限制

一&#xff0c;概述 日常开发中会有一个常见的需求&#xff0c;需要限制接口在单位时间内的访问次数&#xff0c;比如说某个免费的接口限制单个IP一分钟内只能访问5次。该怎么实现呢&#xff0c;通常大家都会想到用redis&#xff0c;确实通过redis可以实现这个功能&#xff0c…

【go从零单排】Ticker

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 语言中&#xff0c;Ticker 是一个用于定期执行某些操作的工具。它属于 tim…

C++《stack与queue》

在之前的章节我们学习了C当中string、vector和list三种容器并且试着模拟实现这三种容器&#xff0c;那么接下来在本篇当中我们将STL当中的stack和queue&#xff0c;并且在学习stack和queue的使用之后和之前一样还会试着模拟实现stck和queue。由于stck和queue的模拟实现较为简单…

网页web无插件播放器EasyPlayer.js点播播放器遇到视频地址播放不了的现象及措施

在数字媒体时代&#xff0c;视频点播已成为用户获取信息和娱乐的重要方式。EasyPlayer.js作为一款流行的点播播放器&#xff0c;以其强大的功能和易用性受到广泛欢迎。然而&#xff0c;在使用过程中&#xff0c;用户可能会遇到视频地址无法播放的问题&#xff0c;这不仅影响用户…

【前端】HTML标签汇总

目录 展示用户信息的标签 1.文本标签 span 2.标题标签 h1~h6 3.竖着布局的标签 div 4.段落标签 p 5.超链接标签 a 5.1跳转至网上的资源 5.2锚点 6.列表标签 6.1有序列表 ol 6.2无序列表 ul 7.图片标签 img 7.1相对路径 7.1.1兄弟关系 7.1.2叔侄关系 7.1.3表兄弟…

xtu oj 加一

样例输入# 2 4 1 2 3 4 4 3 2 4 1样例输出# 3 5 解题思路&#xff1a;最小操作次数一定是把所有数变成数组中最大值max。 1、找最大值&#xff0c;一开始我把max初始值设为0&#xff0c;如果a[i]>max,maxa[i],WA了。又看了一遍题目&#xff0c;发现所有整数的绝对值小于…

Windows10/11开启卓越性能模式 windows开启卓越性能电源模式 工作电脑开启卓越性能模式 电脑开启性能模式

Windows10/11开启卓越性能模式 windows开启卓越性能电源模式 工作电脑开启卓越性能模式 电脑开启性能模式 1、所要用到的激活工具2、开启电脑卓越性能模式Windows11Windows10在电源模式中选择卓越性能模式 3、将系统版本切换为 工作站版本 1、所要用到的激活工具 KMS激活工具(…

人工智能、机器学习与深度学习:层层递进的技术解读

引言 在当今科技快速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为一个热门话题&#xff0c;几乎渗透到了我们生活的方方面面。从智能手机的语音助手&#xff0c;到自动驾驶汽车&#xff0c;再到医疗诊断中的图像识别&#xff0c;人工智能的应用正在改变我…

光流法(Optical Flow)

一、简介 光流法&#xff08;Optical Flow&#xff09;是一种用于检测图像序列中像素运动的计算机视觉技术。其基于以下假设&#xff1a; 1.亮度恒定性假设&#xff1a;物体在运动过程中&#xff0c;其像素值在不同帧中保持不变。 2.空间和时间上的连续性&#xff1a;相邻像素之…