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

这篇具有很好参考价值的文章主要介绍了CMake+QT+大漠插件的桌面应用开发(QThread)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

简介

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

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

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

  • 在这里,我们将会用到QThread,调整后的QT主线程与子线程交互逻辑图如下:
    CMake+QT+大漠插件的桌面应用开发(QThread),C++,qt,c++,CMake,大漠插件,QThread

  • 交互逻辑描述文章来源地址https://www.toymoban.com/news/detail-801412.html

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

环境

版本/规范 备注
平台 win32 操作系统为Windows10
CMake 3.27.8 CLion自带
C++ 17
Toolchain VisualStudio 2022 只用其工具链,记得先安装好
QT 5.12.12 安装时选择msvc2017,不要64位的
DM 7.2353
CLion 2023.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();
}

到了这里,关于CMake+QT+大漠插件的桌面应用开发(QThread)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • vue开发桌面exe应用

    Electron-vue Electron-vue搭建vue全家桶+Element UI客户端(一) 如何使用Vue.js构建桌面应用程序

    2024年02月10日
    浏览(9)
  • Python桌面应用开发之PyQt

    Python桌面应用开发之PyQt

    Tkinter:优势是免安装、相对简单,缺点是功能少,无界面设计工具。 PyQT:使用率高,功能最为强大,代码可维护性和易读性高。 WxPython:介于Tkinter和PyQT之间,相当于压缩版QT。 总结:三种框架各有优劣,有时间可以全部学习,并不复杂。如果只选一种,这里推荐使用最主

    2024年02月13日
    浏览(11)
  • 如何使用Python进行桌面应用开发?

    Python提供了多个库和框架来进行桌面应用开发。以下是使用Python进行桌面应用开发的常用方法之一: PyQt:PyQt是一个用于开发跨平台桌面应用的Python库,它提供了丰富的GUI组件和工具。以下是使用PyQt创建桌面应用的基本步骤: a. 安装PyQt库:使用pip命令安装PyQt库,例如: p

    2024年02月17日
    浏览(11)
  • 桌面应用程序开发攻略(初步了解)

            桌面应用开发 是指为桌面计算机或其他类似设备(如服务器)开发软件应用程序的过程。桌面应用通常是独立于浏览器运行的,并且可以在操作系统的桌面或应用程序菜单中找到。桌面应用可以使用各种编程语言开发,包括C++、Java、C#和Python等。桌面应用的开发

    2024年02月09日
    浏览(8)
  • springboot开发PC端桌面应用

    springboot开发PC端桌面应用

     一、需求描述: 1、要求桌面能在window、Linux和macos系统上运行 2、用户自定义数据筛选策略,策略可通过excel导入导出 3、选择多个excel文件通过策略过滤生成新的excel 二、技术选型及集成环境配置: 1、PC端跨平台直接选用javafx来作为桌面开发 2、动态数据规则使用drools以及内

    2024年02月11日
    浏览(43)
  • electron桌面应用开发——快速入门教程

    electron桌面应用开发——快速入门教程

    本文将介绍electron基本使用和构建electron+vite+vue3脚手架开发项目,带你快速入门。 Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用的框架。 通过将 Chromium 和 Node.js 嵌入到其二进制文件中,Electron 允许你维护一个 JavaScript 代码库并创建可在 Windows、macOS 和 Linux 上运行的跨平

    2024年01月17日
    浏览(12)
  • SpringBoot整合JavaFX进行桌面应用开发

    SpringBoot整合JavaFX进行桌面应用开发

    目录 一、创建一个spring boot工程 二、导入JavaFX依赖 三、创建fxml文件以及controller类文件 3.1 创建一个fxml文件 3.2 创建对应的controller文件 四、Scene Builder的使用 4.1 下载安装 4.2 运行 4.3 界面编辑 五、 修改主启动类 六、测试运行 七、Jfoenix 学习参考: 第一步,我们直接使用Sp

    2024年02月06日
    浏览(9)
  • Electron 桌面应用开发从基础到进阶

    Electron 是一个基于 Node.js 和 Chromium 的桌面应用程序开发框架,它使开发人员能够使用 Web 技术(HTML、CSS 和 JavaScript)构建跨平台的桌面应用程序。它已经被众多知名公司使用,例如 GitHub、Slack、Microsoft 等等。本文将介绍如何使用 Electron 开发桌面应用程序。 安装 Electron 在开

    2024年02月03日
    浏览(7)
  • 跨端开发方案之桌面应用小程序

    跨端开发方案之桌面应用小程序

    小程序容器技术的未来是充满希望的,它为我们开辟了一个全新的数字世界,连接了桌面操作系统和移动生态系统之间的界限。正如技术不断演进,我们可以期待着更多的创新和发展,为用户带来更加便捷和多样化的应用体验。这一技术的推广和应用将继续推动数字科技的发

    2024年02月07日
    浏览(12)
  • 如何使用Java进行桌面应用的开发?

    使用Java进行桌面应用的开发可以借助JavaFX或Swing框架。下面为你提供一些基本的步骤: 安装Java开发工具包(JDK):首先,确保你已经安装了Java开发工具包(JDK),并正确配置了环境变量。 选择GUI框架:Java提供了两个主要的桌面GUI框架:JavaFX和Swing。JavaFX是Oracle推荐的最新的

    2024年02月09日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包