CMake+QT+大漠插件的桌面应用开发(QThread)

news2024/11/27 14:48:21

文章目录

  • CMake+QT+大漠插件的桌面应用开发(QThread)
    • 简介
    • 环境
    • 项目结构
    • 配置编译环境
    • 代码

CMake+QT+大漠插件的桌面应用开发(QThread)

简介

  • 在CMake+QT+大漠插件的桌面应用开发中已经给出了QT配合大漠插件开发桌面应用的样例

  • 不过由于主窗口的UI操作和大漠的调用是在一个线程里面的,所以当大漠调用时间过长时会出现UI界面卡顿的现象

  • 我们可以利用子线程处理耗时操作,处理完后再由主线程(UI线程)更新界面,这样界面就不会出现卡顿。

  • 在这里,我们将会用到QThread,调整后的QT主线程与子线程交互逻辑图如下:
    QT主线程与子线程的交互逻辑图

  • 交互逻辑描述

    • 当点击“注册”选项时,会发出regDM信号,子线程接收到该信号会执行MyMainWorker中的doRegDM方法,执行完成后会发出regDMReady信号,主线程接收到该信号会执行更新UI的操作
    • 当点击“搜索”按钮时,同理
    • 当点击“截图”按钮时,同理

环境

版本/规范备注
平台win32操作系统为Windows10
CMake3.27.8CLion自带
C++17
ToolchainVisualStudio 2022只用其工具链,记得先安装好
QT5.12.12安装时选择msvc2017,不要64位的
DM7.2353
CLion2023.3.2你也可以用其他IDE工具
  • 启动IDE时,记得以管理员模式启动

项目结构

  • 新建一个项目 qt_dm_demo_x_02
  • 目录同CMake+QT+大漠插件的桌面应用开发中一致,会多出MyMainWorker,用于处理子线程逻辑
qt_dm_demo_x_02					             # 项目目录
-- ......
--MyMainWorker.cpp
--MyMainWorker.h
-- ......

配置编译环境

  • 其他同CMake+QT+大漠插件的桌面应用开发中一致
  • CMakeLists.txt 文件中生成可执行文件时,会多出MyMainWorker.cppMyMainWorker.h
# 生成可执行文件
add_executable(${PROJECT_NAME} main.cpp
        strutils.cpp strutils.h
        dmutil.cpp dmutil.h
        mymainwindow.cpp mymainwindow.h mymainwindow.ui
        MyMainWorker.cpp MyMainWorker.h
)

代码

  • dmutil.h、dmutil.cpp、strutils.h、strutils.cpp、mymainwindow.ui、main.cpp同CMake+QT+大漠插件的桌面应用开发中一致
  • mymainwindow.h
#ifndef QT_DM_DEMO_X_MYMAINWINDOW_H
#define QT_DM_DEMO_X_MYMAINWINDOW_H

#include <QMainWindow>
#include <QTextEdit>
#include <QThread>

#include "dmutil.h"


QT_BEGIN_NAMESPACE
namespace Ui { class MyMainWindow; }
QT_END_NAMESPACE

class MyMainWindow : public QMainWindow {
Q_OBJECT
    QThread workerThread;
public:
    explicit MyMainWindow(QWidget *parent = nullptr);

    ~MyMainWindow() override;

public:
    void showInfo(const QString &message, const QString &title = "提示");

    void showWarn(const QString &message, const QString &title = "告警");

signals:
    void regDM(Idmsoft **pDm);

    void findWindow(Idmsoft *pDm, const QString &title);

    void captureWindow(Idmsoft *pDm, const long hwnd);

public slots:

    void showMessageBox(bool result, const QString &message);

    void showTable(bool result, const QString &msg, const vector<MyWindow> &windowVec);


private:
    Ui::MyMainWindow *ui;

    Idmsoft *pCommonDm = nullptr;
};


#endif //QT_DM_DEMO_X_MYMAINWINDOW_H
  • mymainwindow.cpp
// You may need to build the project (run Qt uic code generator) to get "ui_MyMainWindow.h" resolved

#include <QFont>
#include <QHeaderView>
#include <QMessageBox>
#include <QPushButton>
#include <QAction>
#include <QString>
#include <QTableWidgetItem>
#include <QObject>
#include <QVector>
#include <iostream>
#include "mymainwindow.h"
#include "ui_MyMainWindow.h"
#include "MyMainWorker.h"

using namespace std;

MyMainWindow::MyMainWindow(QWidget *parent) :
        QMainWindow(parent), ui(new Ui::MyMainWindow) {
    ui->setupUi(this);

    qRegisterMetaType<QVector<int>>("QVector<int>");
    qRegisterMetaType<vector<MyWindow>>("vector<MyWindow>");

    // Init Views
    setFixedSize(1280, 720);

    ui->tableWidget->setColumnCount(3);
    ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "进程ID" << "句柄" << "标题");
    ui->tableWidget->horizontalHeader()->setStretchLastSection(true); // 最后一列自动铺满表格
    // ui->tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
    ui->tableWidget->horizontalHeader()->setHighlightSections(false);
    ui->tableWidget->horizontalHeader()->setStyleSheet("QHeaderView::section{background:gray;}");
    ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
    QFont font = ui->tableWidget->horizontalHeader()->font();
    font.setBold(true);
    ui->tableWidget->horizontalHeader()->setFont(font);
    ui->tableWidget->setStyleSheet("QTableWidget::item:hover { background-color: lightblue; }");
    ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); // 禁止编辑
    ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); // 选中整行

    // Init Listener
    auto worker = new MyMainWorker;
    worker->moveToThread(&workerThread);
    connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
    // 注册大漠
    connect(ui->actionReg, &QAction::triggered, [this]() {
        ui->actionReg->setEnabled(false);
        emit this->regDM(&this->pCommonDm);
    });
    connect(this, &MyMainWindow::regDM, worker, &MyMainWorker::doRegDM);
    connect(worker, &MyMainWorker::regDMReady, this, &MyMainWindow::showMessageBox);
    // 查找窗口
    connect(ui->btnQuery, &QPushButton::clicked, [this]() {
        ui->btnQuery->setEnabled(false);
        emit this->findWindow(this->pCommonDm, ui->edtTitle->text());
    });
    connect(this, &MyMainWindow::findWindow, worker, &MyMainWorker::doFindWindow);
    connect(worker, &MyMainWorker::findWindowReady, this, &MyMainWindow::showTable);
    // 截图
    connect(ui->btnCapture, &QPushButton::clicked, [this]() {
        ui->btnCapture->setEnabled(false);
        // 获取选中行的句柄列的字段
        const QList<QTableWidgetItem *> &selectedItems = ui->tableWidget->selectedItems();
        if (selectedItems.size() >= 2) {
            QTableWidgetItem *item = selectedItems.at(1);
            const QString &hwnd = item->data(Qt::DisplayRole).toString();
            bool res = false;
            long hwndL = hwnd.toLong(&res, 0);
            cout << res << endl;
            if (res) {
                emit this->captureWindow(this->pCommonDm, hwndL);
            } else {
                ui->btnCapture->setEnabled(true);
                this->showWarn("选中行的窗口句柄解析异常!");
            }
        } else {
            ui->btnCapture->setEnabled(true);
            this->showWarn("请选中列表中的其中一行!");
        }
    });
    connect(this, &MyMainWindow::captureWindow, worker, &MyMainWorker::doCaptureWindow);
    connect(worker, &MyMainWorker::captureWindowReady, this, &MyMainWindow::showMessageBox);

    workerThread.start();
}

MyMainWindow::~MyMainWindow() {
    delete ui;
    workerThread.quit();
    workerThread.wait();
}

void MyMainWindow::showInfo(const QString &message, const QString &title) {
    QMessageBox::information(this, title, message);
}

void MyMainWindow::showWarn(const QString &message, const QString &title) {
    QMessageBox::critical(this, title, message);
}

void MyMainWindow::showMessageBox(const bool result, const QString& message) {
    ui->actionReg->setEnabled(true);
    ui->btnCapture->setEnabled(true);
    if (result) {
        this->showInfo(message);
    } else {
        this->showWarn(message);
    }
}

void MyMainWindow::showTable(const bool result, const QString &msg, const vector<MyWindow> &windowVec) {
    ui->btnQuery->setEnabled(true);
    if (result) {
        auto rowNum = windowVec.size();
        ui->tableWidget->setRowCount(rowNum);
        for (int i = 0; i < rowNum; ++i) {
            const MyWindow &item = windowVec[i];
            ui->tableWidget->setItem(i, 0, new QTableWidgetItem(QString::number(item.processId)));
            ui->tableWidget->setItem(i, 1, new QTableWidgetItem(QString::number(item.hwnd)));
            ui->tableWidget->setItem(i, 2, new QTableWidgetItem(QString::fromStdWString(item.title)));
        }
    } else {
        this->showWarn(msg);
    }
}
  • MyMainWorker.h
#ifndef QT_DM_DEMO_X_MYMAINWORKER_H
#define QT_DM_DEMO_X_MYMAINWORKER_H

#include <QObject>
#include "dmutil.h"

class MyMainWorker: public QObject {
Q_OBJECT
signals:

    void regDMReady(const bool result, const QString &msg);

    void findWindowReady(const bool result, const QString &msg, const vector <MyWindow> &windowVec);

    void captureWindowReady(const bool result, const QString &msg);

public slots:

    /**
     * 注册大漠
     * @param pDm 大漠插件,待赋值
     */
    void doRegDM(Idmsoft **pDm);

    /**
     * 查询匹配的窗口
     * @param pDm 大漠插件
     * @param title 窗口标题(模糊查询)
     */
    void doFindWindow(Idmsoft *pDm, const QString &title);

    /**
     * 对窗口截图
     * @param pDm 大漠插件
     * @param hwnd 窗口句柄
     */
    void doCaptureWindow(Idmsoft *pDm, long hwnd);
};


#endif //QT_DM_DEMO_X_MYMAINWORKER_H
  • MyMainWorker.cpp
#include <iostream>

#include "MyMainWorker.h"

using namespace std;

void MyMainWorker::doRegDM(Idmsoft **pDm) {
    cout << "========== Initial DM ............ ==========" << endl;
    *pDm = initialDMAndRegVIP();
    if (*pDm == nullptr) {
        cout << "========== Initial DM <Failed>     ==========" << endl;
        emit this->regDMReady(false, "DM 注册失败!");
        return;
    }
    cout << "========== Initial DM <Successful> ==========" << endl;
    cout << endl;
    emit this->regDMReady(true, "DM 注册完成!");
}

void MyMainWorker::doFindWindow(Idmsoft *pDm, const QString &title) {
    vector<MyWindow> windowVec;
    if (pDm == nullptr) {
        cout << "this->pCommonDm == nullptr" << endl;
        emit this->findWindowReady(false, "请先在菜单中完成注册!", windowVec);
        return;
    }

    // 找一下包含title的窗口
    getMatchedWindows(windowVec, pDm, title.toStdWString());
    if (windowVec.empty()) {
        cout << "can not find such window" << endl;
        emit this->findWindowReady(false, "没有找到包含该标题的窗口!", windowVec);
        return;
    }
    emit this->findWindowReady(true, "成功!", windowVec);
}

void MyMainWorker::doCaptureWindow(Idmsoft *pDm, long hwnd) {
    if (pDm == nullptr) {
        cout << "this->pCommonDm == nullptr" << endl;
        emit this->captureWindowReady(false, "请先在菜单中完成注册!");
        return;
    }

    // 绑定窗口句柄
    long dmBind = pDm->BindWindowEx(
            hwnd,
            "normal",
            "normal",
            "normal",
            "",
            0
    );
    if (dmBind == 1) {
        // 恢复并激活指定窗口,置顶窗口,
        pDm->SetWindowState(hwnd, 12);
        pDm->SetWindowState(hwnd, 8);
        pDm->delay(600);
        // 延迟一下截图,存到相对路径
        wstring filename = wstring(L"./capture_window_").append(std::to_wstring(hwnd)).append(L".bmp");
        long retCap = pDm->Capture(0, 0, 2000, 2000, filename.c_str());
        if (retCap != 1) {
            cout << "capture failed" << endl;
            emit this->captureWindowReady(false, "截图失败!");
        } else {
            cout << "capture success" << endl;
            emit this->captureWindowReady(true, QString::fromStdWString(L"截图成功,保存地址为: " + filename));
        }
        // 取消置顶窗口
        pDm->SetWindowState(hwnd, 9);
    } else {
        cout << "DM BindWindow failed" << endl;
        emit this->captureWindowReady(false, "绑定窗口异常!");
    }
    pDm->UnBindWindow();
}

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

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

相关文章

Android车载系统Car模块架构链路分析

一、模块主要成员 CarServiceHelperService SystemServer 中专门为 AAOS 设立的系统服务&#xff0c;用来管理车机的核心服务 CarService。该系统服务的具体实现在 CarServiceHelperServiceUpdatableImpl CarService Car模块核心服务APP&#xff0c;Android 13版本开始分为…

PXE和kickstart无人值守安装

PXE高效批量网络装机 引言 1.系统装机的引导方式 启动 操作 系统 1.硬盘 2.光驱&#xff08;u盘&#xff09; 3.网络启动 pxe 重装系统&#xff1f; 在已有操作系统 新到货了一台服务器&#xff0c; 装操作系统 系统镜像 u盘 光盘 pe&#xff1a; 小型的 操作系统 在操…

RocketMQ Dashboard 详解

RocketMQ Dashboard 是 RocketMQ 的管控利器&#xff0c;为用户提供客户端和应用程序的各种事件、性能的统计信息&#xff0c;支持以可视化工具代替 Topic 配置、Broker 管理等命令行操作。 一、介绍​ 功能概览​ 面板功能运维修改nameserver 地址; 选用 VIPChannel驾驶舱查…

【Docker】网络模式详解及容器间网络通信

目录 一、概述 二、默认网络 三、网络模式及应用 1. Bridge模式 2. Host模式 3. none网络模式 四、自定义网络应用 1. 网络相连 2. 自定义通讯 3. 自定义IP 每篇一获 一、概述 在 Docker 中&#xff0c;网络设置包括 IP 地址、子网掩码、网关、DNS 和端口号等关键组…

循环神经网络的变体模型-LSTM、GRU

一.LSTM&#xff08;长短时记忆网络&#xff09; 1.1基本介绍 长短时记忆网络&#xff08;Long Short-Term Memory&#xff0c;LSTM&#xff09;是一种深度学习模型&#xff0c;属于循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;的一种变体。…

数据结构学习之链式栈应用的案例(最小栈)

实例要求&#xff1a; 设计一个支持入栈、出栈、取栈顶元素等操作&#xff0c;并能在常数时间内检索到最小元素的栈&#xff1b; 实现 MinStack 类: MinStack* minStackCreate() 初始化堆栈对象&#xff0c;即建栈&#xff1b; void minStackPush(MinStack* obj, int val) …

springmvc上传与下载

文件上传 结构图 导入依赖 <dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId…

机器学习之常用激活函数

人工神经网络中最基本的单元叫神经元,又叫感知器,它是模拟人脑神经系统的神经元(分析和记忆)、树突(感知)、轴突(传导)的工作原理,借助计算机的快速计算和存储来实现。它的主体结构如下: 激活函数常用类型有:线性激活函数、符号激活函数、Sigmoid激活函数、tanh激活…

MySQL中根据出生日期计算年龄

创建student表 mysql> create table student( -> sid int primary key comment 学生号, -> sname varchar(20) comm…

mybatis----小细节

1、起别名 在MyBatis中&#xff0c;<typeAliases>元素用于定义类型别名&#xff0c;它可以将Java类名映射为一个更简短的别名&#xff0c;这样在映射文件中可以直接使用别名而不需要完整的类名。 下面是一个示例&#xff1a; 在mybatis核心配置文件中配置typeAliases标…

QT第二周周三

题目&#xff1a;使用图片绘制出仪表盘 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *paren…

社交媒体数据分析:解读Facebook用户行为

在当今数字化时代&#xff0c;社交媒体已经成为人们生活不可或缺的一部分&#xff0c;而Facebook作为这个领域的巨头&#xff0c;承载了数十亿用户的社交活动。这庞大的用户群体产生了海量的数据&#xff0c;通过深度数据分析&#xff0c;我们能够深入解读用户行为&#xff0c;…

用C++和Python分别实现归并排序(详细讲解!!!)

目录 一、归并排序的背景1. 分治算法2. 分治算法的解题步骤2.1 分解2.2 治理2.3 合并 2. 归并排序2.1 大致思路2.2 算法分析 二、C代码三、Python代码 一、归并排序的背景 1. 分治算法 归并排序&#xff0c;本质上就是分治算法的一种&#xff0c;那么什么是分治算法呢。在算法…

【Java】HttpServlet类简单方法和请求显示

1、HttpServlet类简介&#x1f340; Servlet类中常见的三个类有&#xff1a;☑️HttpServlet类&#xff0c;☑️HttpServletRequest类&#xff0c;☑️HttpResponse类 &#x1f42c;其中&#xff0c;HttpServlet首先必须读取Http请求的内容。Servlet容器负责创建HttpServlet对…

F. Sum of Progression

题面 输入 每个测试由几个测试用例组成。第一行包含一个整数 t&#xff08;1 ≤ t ≤ 1e4&#xff09;——测试用例的数量。接下来的几行包含测试用例的描述。 每个测试用例的第一行包含两个数字n&#xff0c;q&#xff08;1 ≤ n ≤ 1e5&#xff0c;1 ≤ q ≤ 2e5&#xff09;…

电子雨html代码

废话不多说下面是代码&#xff1a; <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><title>Code</title><style>body{margin: 0;overflow: hidden;}</style></head><body><c…

Demo: 实现PDF加水印以及自定义水印样式

实现PDF加水印以及自定义水印样式 <template><div><button click"previewHandle">预览</button><button click"downFileHandle">下载</button><el-input v-model"watermarkText" /><el-input v-mo…

【Java 设计模式】创建型之原型模式

文章目录 1. 定义2. 应用场景3. 代码实现4. 应用示例结语 在软件开发中&#xff0c;原型模式是一种创建型设计模式&#xff0c;它允许通过复制现有对象来创建新对象&#xff0c;而无需知道其具体实现。原型模式通常包含一个原型接口和多个实现了该接口的具体原型类。在本文中&a…

从0开始python学习-48.pytest框架之断言

目录 1. 响应进行断言 1.1 在yaml用例中写入断言内容 1.2 封装断言方法 1.3 在执行流程中加入断言判断内容 2. 数据库数据断言 2.1 在yaml用例中写入断言内容 2.2 连接数据库并封装执行sql的方法 2.3 封装后校验方法是否可执行 2.4 使用之前封装的断言方法&#xff0c…

RT-Thread 15. list_timer与软定时器

1. 代码 void rt_thread_usr1_entry(void *parameter) {/* set LED2 pin mode to output */rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT);while (1){rt_pin_write(LED2_PIN, PIN_HIGH);rt_thread_mdelay(2000);rt_pin_write(LED2_PIN, PIN_LOW);rt_thread_mdelay(3000);} }int ma…