当前位置: 首页 > news >正文

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

文章目录

  • 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.cppstrutils.cpp strutils.hdmutil.cpp dmutil.hmymainwindow.cpp mymainwindow.h mymainwindow.uiMyMainWorker.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_NAMESPACEclass MyMainWindow : public QMainWindow {
Q_OBJECTQThread 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 ViewssetFixedSize(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 Listenerauto 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();
}

相关文章:

  • 使用vue2写一个太极图,并且点击旋转
  • postman测试导入文件
  • 多协议转换网关BL120ML实现Modbus、楼宇自控、电力协议转Modbus
  • html + css + js简单的项目
  • 项目工程下载与XML配置文件下载:EtherCAT超高速实时运动控制卡XPCIE1032H上位机C#开发(十)
  • python元类为类的全部方法添加装饰器
  • 2017年认证杯SPSSPRO杯数学建模B题(第二阶段)岁月的印记全过程文档及程序
  • #《AI中文版》V3 第 1 章 概述
  • linux之安装配置VM+CentOS7+换源
  • 如何通过系统命令排查账号安全?
  • 智慧文旅运营综合平台:重塑文化旅游产业的新引擎
  • LeetCode349. 两个数组的交集
  • 【Linux】第三十二站:命名管道
  • Qt5.12.0 与 VS2017 在 .pro文件转.vcxproj文件
  • easyui渲染隐藏域<input type=“hidden“ />为textbox可作为分割条使用
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • Hibernate最全面试题
  • Lsb图片隐写
  • Mac转Windows的拯救指南
  • nginx 配置多 域名 + 多 https
  • Promise面试题,控制异步流程
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 老板让我十分钟上手nx-admin
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 使用putty远程连接linux
  • 详解NodeJs流之一
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • ​低代码平台的核心价值与优势
  • #android不同版本废弃api,新api。
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (Git) gitignore基础使用
  • (分享)自己整理的一些简单awk实用语句
  • (三分钟)速览传统边缘检测算子
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • (转)原始图像数据和PDF中的图像数据
  • .htaccess配置重写url引擎
  • .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)...
  • .net 按比例显示图片的缩略图
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .Net下的签名与混淆
  • @Builder用法
  • @PreAuthorize注解
  • @property @synthesize @dynamic 及相关属性作用探究
  • @RequestBody与@ModelAttribute
  • [ C++ ] STL---仿函数与priority_queue
  • [ Linux ] Linux信号概述 信号的产生
  • [ACL2022] Text Smoothing: 一种在文本分类任务上的数据增强方法
  • [Android] 修改设备访问权限