七、Qt框架编写的多线程应用程序
一、大纲
学习内容:使用两个线程,分别点击两个按钮,触发两个不同的效果
所需控件:两个button、三个label
涉及知识点:多线程、Qt的connect机制、定时器、互斥锁
需求:
1,多线程定时计数:创建两个独立的线程,每个线程中运行一个定时器,定时器分别以不同的时间间隔触发,每次触发时更新界面上的标签,显示该线程定时器的调用次数。
2,按钮点击计数:界面上有两个按钮,每个按钮被点击时,更新相应的标签,显示该按钮的点击次数。
在工作中涉及到采用多线程读取PLC同一块内存,将核心思路进行了总结,并抽离了一下,用比较简单的demo进行演示,故此作为笔记,后续有利于复习
二、应用场景
1,工业自动化领域
通过多线程读取PLC的同一个DB块的内存数据
2,游戏开发领域
多线程定时计数功能可以实现游戏中的倒计时功能,比如限时任务的剩余时间、技能冷却时间等。
3,智能家居领域
多线程定时计数功能可以定时收集设备的能耗数据,通过统计一段时间内的能耗变化,分析设备的使用习惯和能耗规律。
三、创建Qt项目





目录结构

四、UI布局
在wdiget里面有俩button和三个label

五、代码
1,main.cpp
#include "qt_thread.h"
#include <QtWidgets/QApplication>
#include <QTextCodec>int main(int argc, char *argv[])
{QApplication a(argc, argv);beyondyanyu_study_qt_thread::QtThread w;w.show();return a.exec();
}
2,qt_thread.h
#pragma once#include <QtWidgets/QMainWindow>
#include <QMutex>
#include "ui_QtThread.h"namespace beyondyanyu_study_qt_thread {class QtThread : public QMainWindow{Q_OBJECTpublic:QtThread(QWidget* parent = nullptr);~QtThread();private slots:void PushButton1_clicked();void PushButton2_clicked();private:Ui::QtThreadClass ui;QThread* thread_1_;QThread* thread_2_;QTimer* timer_label_1_;QTimer* timer_label_2_;int counter_1_{0};int counter_2_{0};int counter_3_{0};int counter_4_{0};QMutex mutex_{ QMutex::Recursive };};
};// namespace beyondyanyu_study_qt_thread
成员变量
Ui::QtThreadClass ui;:这是用于存储 UI 界面元素的对象,一般由 Qt 的 UI 设计器生成。借助 ui 能访问并操作界面上的各类控件,例如按钮、标签等。
QThread* thread_1_; 和 QThread* thread_2_;:这两个指针分别指向两个不同的 QThread 对象,用来创建和管理两个独立的线程。每个线程都可并行执行任务,互不干扰。
QTimer* timer_label_1_; 和 QTimer* timer_label_2_;:这两个指针分别指向两个 QTimer 对象,用于定时触发特定操作。timer_label_1_ 和timer_label_2_能以不同的时间间隔触发超时信号。
int counter_1_{0};、int counter_2_{0};、int counter_3_{0}; 和 int counter_4_{0};:这些整型变量作为计数器使用。counter_1_ 和 counter_2_ 分别记录 timer_label_1_ 和 timer_label_2_ 定时器的超时次数;counter_3_ 和 counter_4_ 分别记录 ui.pushButton 和 ui.pushButton_2 按钮的点击次数。
QMutex mutex_{ QMutex::Recursive };:这是一个递归互斥锁对象,用于保证多线程环境下对共享资源(如 counter_1_ 和 counter_2_)的安全访问,防止数据竞争问题。
成员函数
QtThread(QWidget* parent = nullptr);:这是 QtThread 类的构造函数,用于初始化 QtThread 对象。在构造函数里会进行界面的初始化、线程的启动、定时器的设置以及信号与槽的连接等操作。
~QtThread();:这是 QtThread 类的析构函数,负责在对象销毁时释放相关资源,不过当前代码里该析构函数为空。
void PushButton1_clicked(); 和 void PushButton2_clicked();:这两个函数属于槽函数,会在 ui.pushButton 和 ui.pushButton_2 按钮被点击时分别触发,用于更新相应的计数器并修改界面上的标签显示。
3,qt_thread.cpp
#include "qt_thread.h"
#include <QThread>
#include <QTimer>namespace beyondyanyu_study_qt_thread {QtThread::QtThread(QWidget* parent): QMainWindow(parent){ui.setupUi(this);//按钮一//开启线程thread_1_ = new QThread();thread_1_->start();//开启一个定时器timer_label_1_ = new QTimer(this);timer_label_1_->setInterval(1000);timer_label_1_->start();//将改定时器移动到线程中timer_label_1_->moveToThread(thread_1_);connect(timer_label_1_, &QTimer::timeout, timer_label_1_, [this] {QMutexLocker locker(&mutex_);counter_1_++;ui.label_3->setText(QStringLiteral("线程1调用次数:") + QString::number(counter_1_));});//按钮二//开启线程thread_2_ = new QThread();thread_2_->start();//开启一个定时器timer_label_2_ = new QTimer(this);timer_label_2_->setInterval(900);timer_label_2_->start();//将改定时器移动到线程中timer_label_2_->moveToThread(thread_2_);connect(timer_label_2_, &QTimer::timeout, timer_label_2_, [this]{QMutexLocker locker(&mutex_);counter_2_++;ui.label_3->setText(QStringLiteral("线程2调用次数:") + QString::number(counter_2_));});connect(ui.pushButton, &QPushButton::clicked, this, &QtThread::PushButton1_clicked);connect(ui.pushButton_2, &QPushButton::clicked, this, &QtThread::PushButton2_clicked);}void QtThread::PushButton1_clicked(){counter_3_++;ui.label->setText(QStringLiteral("按钮1触发次数:") + QString::number(counter_3_));}void QtThread::PushButton2_clicked(){counter_4_++;ui.label_2->setText(QStringLiteral("按钮2触发次数:") + QString::number(counter_4_));}QtThread::~QtThread(){// 停止线程thread_1_->quit();thread_1_->wait();delete thread_1_;thread_2_->quit();thread_2_->wait();delete thread_2_;// 删除定时器delete timer_label_1_;delete timer_label_2_;}
} // namespace beyondyanyu_study_qt_thread;
构造函数 QtThread::QtThread(QWidget* parent)
ui.setupUi(this);:初始化 UI 界面,把 UI 设计器设计的界面元素加载到 QtThread 窗口中。
按钮一相关操作:
thread_1_ = new QThread(); 和 thread_1_->start();:创建并启动一个新线程 thread_1_。
timer_label_1_ = new QTimer(this);、timer_label_1_->setInterval(1000); 和 timer_label_1_->start();:创建一个定时器 timer_label_1_,设置其时间间隔为 1000 毫秒(即 1 秒),然后启动该定时器。
timer_label_1_->moveToThread(thread_1_);:将 timer_label_1_ 定时器移动到 thread_1_ 线程中运行。
connect(timer_label_1_, &QTimer::timeout, timer_label_1_, [this] {... });:把 timer_label_1_ 的 timeout 信号连接到一个 Lambda 表达式。当定时器超时时,会执行 Lambda 表达式中的代码,使用互斥锁保护 counter_1_ 计数器的更新操作,并更新界面上 ui.label_3 标签的显示内容。
按钮二相关操作:操作与按钮一类似,不同之处在于 timer_label_2_ 的时间间隔设置为 900 毫秒。
connect(ui.pushButton, &QPushButton::clicked, this, &QtThread::PushButton1_clicked); 和 connect(ui.pushButton_2, &QPushButton::clicked, this, &QtThread::PushButton2_clicked);:将 ui.pushButton 和 ui.pushButton_2 按钮的 clicked 信号分别连接到 PushButton1_clicked() 和 PushButton2_clicked() 槽函数。
槽函数 void QtThread::PushButton1_clicked() 和 void QtThread::PushButton2_clicked()
PushButton1_clicked():当 ui.pushButton 按钮被点击时,counter_3_ 计数器加 1,同时更新界面上 ui.label 标签的显示内容,显示按钮 1 的点击次数。
PushButton2_clicked():当 ui.pushButton_2 按钮被点击时,counter_4_ 计数器加 1,同时更新界面上 ui.label_2 标签的显示内容,显示按钮 2 的点击次数。
析构函数 QtThread::~QtThread()
当前析构函数为空,在实际应用中,需要释放 thread_1_、thread_2_、timer_label_1_ 和 timer_label_2_ 等动态分配的资源,避免内存泄漏。
四、效果演示


相关文章:
七、Qt框架编写的多线程应用程序
一、大纲 学习内容:使用两个线程,分别点击两个按钮,触发两个不同的效果 所需控件:两个button、三个label 涉及知识点:多线程、Qt的connect机制、定时器、互斥锁 需求: 1,多线程定时计数&#x…...
MATLAB求和∑怎么用?
MATLAB求和∑怎么用? 一:题目:求下列方程的和 二、代码如下 1.syms函数 (方法一) 代码如下(示例): 1. syms x 2. symsum((x.^22*x).^3,1,100) 3. 2.直接用循环 (方法二) 代码如下&am…...
项目二 使用miniedit创建拓扑
一、项目需求分析: 1. 在ubuntu的桌面环境中运行Mininet的图形化界面2. Mininet图形化界面中搭建拓扑并设置相关的设备和链路属性3. Floodlight中查看拓扑4. 完成Mininet的测试 二、项目实施步骤 1. 运行Mininet图形化界面 在“~/mininet/examples”目录下有一m…...
Docker 镜像 的常用命令介绍
拉取镜像 $ docker pull imageName[:tag][:tag] tag 不写时,拉取的 是 latest 的镜像查看镜像 查看所有本地镜像 docker images or docker images -a查看完整的镜像的数字签名 docker images --digests查看完整的镜像ID docker images --no-trunc只查看所有的…...
0x02.Redis 集群的实现原理是什么?
回答重点 Redis 集群(Redis cluster)是通过多个 Redis 实例组成的,每个主节点实例负责存储部分的数据,并且可以有一个或多个从节点作为备份。 具体是采用哈希槽(Hash Slot)机制来分配数据,将整…...
浏览器多开
使用浏览器的用户功能,创建多个用户即可完成浏览器多开的需求,插件等相对独立 需要命名 然后就可以通过多个用户切换来实现多开了,不同任务选择不同用户...
Python中NumPy的逻辑和比较
在数据科学和科学计算领域,NumPy是一个不可或缺的Python库。它提供了高效的多维数组对象以及丰富的数组操作函数,其中逻辑和比较操作是NumPy的核心功能之一。通过灵活运用这些操作,我们可以轻松实现数据筛选、条件判断和复杂的数据处理任务。…...
20250412_代码笔记_CVRProblemDef
文章目录 前言一、get_random_problems 函数分析二、augment_xy_data_by_8_fold 函数分析代码 前言 该笔记分析代码的功能是生成随机VRP问题的数据,包含仓库坐标、节点坐标和节点需求。 对该代码进行改进 20250412-代码改进-拟蒙特卡洛 一、get_random_problems 函…...
机器学习(3)——决策树
文章目录 1. 决策树基本原理1.1. 什么是决策树?1.2. 决策树的基本构成:1.3. 核心思想 2. 决策树的构建过程2.1. 特征选择2.1.1. 信息增益(ID3)2.1.2. 基尼不纯度(CART)2.1.3. 均方误差(MSE&…...
Redis常用数据结构和应用场景
一、前言 Redis提供了多种数据结构,每种结构对应不同的应用场景。本文对部分常用的核心数据结构和典型使用场景作出介绍。 二、String(字符串) 特点:二进制安全,可存储文本、数字、序列化对象等。场景: 缓…...
【转载翻译】使用Open3D和Python进行点云处理
转自个人博客:【转载翻译】使用Open3D和Python进行点云处理 转载自:Point Cloud Processing with Open3D and Python 本文由 Carlos Melo 发布于2024年2月12日 本文很适合初学者对三维处理、点云处理以及Open3D库进行初步了解 另外,本文是基于…...
用户登录不上linux服务器
一般出现这种问题,重新用root用户修改lsy用户的密码即可登录,但是当修改了还是登录不了的时候,去修改一个文件用root才能修改, 然后在最后添加上改用户的名字,例如 原本是只有user的,现在我加上了lsy了&a…...
SQL 全文检索原理
全文检索(Full-Text Search)是SQL中用于高效搜索文本数据的技术,与传统的LIKE操作或简单字符串比较相比,它能提供更强大、更灵活的文本搜索能力。 基本概念 全文检索的核心思想是将文本内容分解为可索引的单元(通常是词或词组),然后建立倒排…...
dcsdsds
我将为您在页面顶部添加欢迎内容,同时保持整体风格的一致性。以下是修改后的代码,主要修改了模板部分和对应的样式: vue 复制 <template><div class"main-wrapper"><!-- 新增欢迎部分 --><div class"…...
FISCO BCOS区块链Postman接口测试:高级应用与实战技巧 [特殊字符]
引言:为什么Postman是FISCO BCOS测试的利器? 在区块链开发领域,接口测试是确保系统稳定性和安全性的关键环节。作为国产领先的联盟链平台,FISCO BCOS在金融、政务、供应链等多个领域得到广泛应用。而Postman作为一款功能强大的API测试工具,凭借其直观的图形界面和丰富的测…...
KWDB创作者计划—KWDB场景化创新实践:多模态数据融合与边缘智能的突破性应用
引言:AIoT时代的数据库范式重构 在工业物联网设备数量突破千亿、边缘计算节点覆盖率达75%的2025年,传统数据库面临多模态数据处理效率低下、边缘端算力利用率不足、跨域数据协同困难等核心挑战。KWDB(KaiwuDB Community Edition)通…...
风暴之眼:在AI重构的数字世界重绘职业坐标系
硅谷的某个深夜,GitHub Copilot在程序员的注视下自动生成出完美代码,这个场景正在全球数百万开发者的屏幕上同步上演。当AI生成的代码通过图灵测试,当机器学习模型开始理解业务需求,一个根本性命题浮出水面:在人类亲手…...
主机协议端口安全
FTP RDP SSH Rsync 渗透基础 | 黑客常用端口利用总结 - ZM思 - 博客园 (cnblogs.com)...
matplotlib数据展示
目录 一、绘制直方图 1、简单直方图 2、绘制横向直方图 3、绘制堆叠直方图 4、对比直方图 二、折线图与散点图 三、绘制饼图 四、雷达图 1、简单雷达图 2、多层雷达图 五、总和 在前面的学习中,我们能够使用一些库进行数据的整合,收集&#x…...
MySQL 面经
1、什么是 MySQL? MySQL 是一个开源的关系型数据库,现在隶属于 Oracle 公司。是我们国内使用频率最高的一种数据库,我本地安装的是比较新的 8.0 版本。 1.1 怎么删除/创建一张表? 可以使用 DROP TABLE 来删除表,使用…...
vLLM实战:多机多卡大模型分布式推理部署全流程指南
1. 环境准备与基础配置 1.1 系统要求 依赖组件: # 基础工具安装 sudo apt-get install -y lsof git-lfs nvidia-cuda-toolkit1.2 虚拟环境配置 使用conda创建隔离环境,避免依赖冲突: conda create -n vllm python3.10 -y conda activate…...
贪心算法 day08(加油站+单调递增的数字+坏了的计算机)
目录 1.加油站 2.单调递增的数字 3.坏了的计算器 1.加油站 链接:. - 力扣(LeetCode) 思路: gas[index] - cost[index],ret 表示的是在i位置开始循环时剩余的油量 a到达的最大路径假设是f那么我们可以得出 a b …...
String类基本使用
文章目录 1. String类的理解和创建对象2. 创建String对象的两种方式3. 两种创建String对象的区别4. 测试5. 字符串的特性6. String 类的常见方法 1. String类的理解和创建对象 String 对象用于保存字符串,也就是一组字符序列字符串常量对象是用双引号括起的字符序列…...
华为机试—火车进站
题目 火车站一共有 n 辆火车需要入站,每辆火车有一个编号,编号为 1 到 n。 同时,也有火车需要出站,由于火车站进出共享一个轨道,所以后入站的火车需要先出站。换句话说,对于某一辆火车,只有在它…...
Python数组(array)学习之旅:数据结构的奇妙冒险
Python数组学习之旅:数据结构的奇妙冒险 第一天:初识数组的惊喜 阳光透过窗帘缝隙洒进李明的房间,照亮了他桌上摊开的笔记本和笔记本电脑。作为一名刚刚转行的金融分析师,李明已经坚持学习Python编程一个月了。他的眼睛因为昨晚熬夜编程而微微发红,但脸上却挂着期待的微…...
spark-core编程2
Key-Value类型: foldByKey 当分区内计算规则和分区间计算规则相同时,aggregateByKey 就可以简化为 foldByKey combineByKey 最通用的对 key-value 型 rdd 进行聚集操作的聚集函数(aggregation function)。类似于aggregate()&…...
AIDD-人工智能药物设计-大语言模型在医学领域的革命性应用
Nat. Rev. Bioeng. | 大语言模型在医学领域的革命性应用 大型语言模型(LLMs),如 ChatGPT,因其对人类语言的理解与生成能力而备受关注。尽管越来越多研究探索其在临床诊断辅助、医学教育等任务中的应用,但关于其发展、…...
Windows 系统中安装 Git 并配置 GitHub 账户
由于电脑重装系统,重新配置了git. 以下是在 Windows 系统中安装 Git 并配置 GitHub 账户的详细步骤: 1. 安装 Git 访问 Git 官网下载页面下载 Windows 版本的 Git 安装程序运行安装程序,使用默认选项即可 2. 配置 Git 用户信息 打开命令…...
QQ风格客服聊天窗口
QQ风格客服聊天窗口 展示引入方式 展示 引入方式 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&g…...
fastadmin后端添加页面,自主控制弹出框关闭,关闭父页面弹框
Form.api.bindevent($(“form[roleform]”), (data, ret) > { 重写绑定事件,返回false即可 注意:只有返回code1才能拦截,其他值不进行拦截 add: function () {//获取当前search里面的type值var type location.search.split(type)[1];Form.api.bindevent($("form[role…...
