【QT5】<总览五> QT多线程、TCP/UDP

文章目录

前言

一、QThread多线程

二、QT中的TCP编程

1. TCP简介

2. 服务端程序编写

3. 客户端程序编写

4. 服务端与客户端测试

三、QT中的UDP编程

1. UDP简介

2. UDP单播与广播程序


前言

承接【QT5】<总览四> QT常见绘图、图表及动画。若存在版权问题,请联系作者删除!


一、QThread多线程

1. 作用:创建多线程,防止应用程序界面卡顿。

2. 主要操作:

  • ①创建的类需要继承QThread类。
  • ②重写run函数,新建的线程会执行run函数。
  • ③线程开启:对象调用start方法,使线程执行run函数。
  • ④线程终止:对象调用terminate方法,使线程不再执行run函数。
  • ⑤线程销毁:动态申请new需要调用deleteLater方法销毁线程对象。(该函数可以放置于run函数内,当run函数执行完毕后就会销毁该线程对象,防止内存泄漏)注意:尽量少用静态申请栈空间的方式创建线程对象,因为很可能该对象销毁时线程仍在执行,就会报错。

3. 实例演示:创建两个按钮,一个按钮点击时创建新线程,另一个按钮点击时终止新线程。

【1】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QThread>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE//自定义的线程类
class MyThread : public QThread
{Q_OBJECTpublic:MyThread(QWidget *parent = nullptr){Q_UNUSED(parent)//防止编译器警告}~MyThread(){qDebug("线程销毁");}void run() override{qDebug("线程开始");sleep(5);//QThread里才有该方法qDebug("线程停止");deleteLater();//销毁线程}
};//Widget类
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();void on_pushButton_2_clicked();private:Ui::Widget *ui;MyThread *mythread;
};
#endif // WIDGET_H

【2】widget.cpp:

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}//“线程开始”按钮的槽函数
void Widget::on_pushButton_clicked()
{mythread = new MyThread;mythread->start();
}//“线程终止”按钮的槽函数
void Widget::on_pushButton_2_clicked()
{//若线程没有完成,则终止if (!mythread->isFinished())mythread->terminate();
}

【3】运行效果:

  • ①当我们点击“线程开始”按钮后,控制台打印“线程开始”,五秒后控制台打印“线程停止”和“线程销毁”。
  • ②当我们点击“线程开始”按钮后,控制台打印“线程开始”,当我们在五秒内点击“线程结束”按钮,控制台什么都没有打印。

二、QT中的TCP编程

1. TCP简介

  • TCP是面向连接的可靠的基于字节流的传输层通信协议。
  • TCP的服务端和客户端通信首先必须建立连接
  • 建立连接方式:服务端监听某个端口,当有客户端通过ip和port连接时,就会创建一个socket连接,之后就可以互发数据了。
  • QT中将socket视为输入输出流,数据的收发是通过read()write()来进行,而不是常见的send和recv。

----------------------------接下来,我们以一个实例来解析服务端和用户端程序编写-------------------------

2. 服务端程序编写

2.1 编写步骤:

【1】配置:①pro文件中添加network;②添加头文件<QTcpServer>和<QTcpSocket>。

【2】创建服务端对象:QTcpServer *tcpServer;(具体分配空间在构造函数中)

【3】服务端-客户端的信号槽连接:connect(tcpServer, SIGNAL(newConnection()), this, SLOT(mNewConnection()));

【4】编写【3】中的槽函数mNewConnection():

  • ①获取客户端对象:QTcpSocket *tmpTcpSocket = tcpServer->nextPendingConnection();
  • ②获取客户端信息:
    • 获取客户端ip:tmpTcpSocket->peerAddress().toString();
    • 获取客户端port:tmpTcpSocket->peerPort();
  • ③创建信号槽来处理客户端的连接状态:connect(tmpTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(mStateChanged(QAbstractSocket::SocketState)));
  • ④创建信号槽来接收客户端发送的信息:connect(tmpTcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));

【5】编写【4】中的槽函数mStateChanged(...):用switch-case结构来处理连接状态,当状态为断开连接时,删除当前调用的客户端对象。

【6】编写【4】中的槽函数receiveMessage():调用tmpTcpSocket->readAll()来获取客户端发送的信息。

【7】创建函数来给客户端发送数据:内部调用"客户端对象.write("写入的内容")"。

【8】开始监听:调用tcpServer->listen(QHostAddress("192.168.124.151"), 9999); 监听ip为192.168.124.151,port为9999。

2.2 编写代码:

【1】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void mNewConnection();void receiveMessage();void mStateChanged(QAbstractSocket::SocketState socketState);void on_pushButton_3_clicked();void on_pushButton_clicked();void on_pushButton_2_clicked();private:Ui::Widget *ui;QTcpServer *tcpServer;
};
#endif // WIDGET_H

【2】widget.cpp:

#include "widget.h"
#include "ui_widget.h"/************************************************************ @函数名:Widget* @功  能:构造函数---创建服务端对象,与客户端连接* @参  数:parent---父对象* @返回值:无*********************************************************/
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("服务端");//创建对象,与客户端连接tcpServer = new QTcpServer(this);connect(tcpServer, SIGNAL(newConnection()), this, SLOT(mNewConnection()));
}/************************************************************ @函数名:~Widget* @功  能:析构函数* @参  数:无* @返回值:无*********************************************************/
Widget::~Widget()
{delete ui;
}/************************************************************ @函数名:mNewConnection* @功  能:槽函数---若客户端发起连接,服务端连接客户端* @参  数:无* @返回值:无*********************************************************/
void Widget::mNewConnection()
{//获取客户端QTcpSocket *tmpTcpSocket = tcpServer->nextPendingConnection();//打印客户端的ip和portQString ipAddr = tmpTcpSocket->peerAddress().toString();quint16 port = tmpTcpSocket->peerPort();ui->textBrowser->append("客户端的ip地址:" + ipAddr);ui->textBrowser->append("客户端的端口:" + QString::number(port));//处理客户端连接状态,接收客户端发送的数据connect(tmpTcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));connect(tmpTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),this, SLOT(mStateChanged(QAbstractSocket::SocketState)));
}/************************************************************ @函数名:receiveMessage* @功  能:槽函数---服务端接收客户端发送的数据* @参  数:无* @返回值:无*********************************************************/
void Widget::receiveMessage()
{QTcpSocket *tmpTcpSocket = (QTcpSocket*)sender();ui->textBrowser->append("客户端:" + tmpTcpSocket->readAll());
}/************************************************************ @函数名:mStateChanged* @功  能:槽函数---服务端处理客户端的连接状态* @参  数:socketState---客户端连接状态* @返回值:无*********************************************************/
void Widget::mStateChanged(QAbstractSocket::SocketState socketState)
{QTcpSocket *tmpTcpSocket = (QTcpSocket*)sender();//处理状态,删除断开的QTcpSocket对象switch (socketState) {case QAbstractSocket::UnconnectedState://断开连接,删除对象ui->textBrowser->append("客户端断开连接");tmpTcpSocket->deleteLater();break;case QAbstractSocket::ConnectedState://已连接ui->textBrowser->append("客户端已连接");break;default:break;}
}/************************************************************ @函数名:on_pushButton_3_clicked* @功  能:按钮"发送消息"的槽函数,将文本信息发送给所有客户端* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_3_clicked()
{QList <QTcpSocket*> clients = tcpServer->findChildren<QTcpSocket*>();for (int i = 0; i < clients.length(); ++i) {clients[i]->write(ui->lineEdit->text().toUtf8());}
}/************************************************************ @函数名:on_pushButton_clicked* @功  能:按钮"开始监听"的槽函数,监听指定的ip和port* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_clicked()
{tcpServer->listen(QHostAddress("192.168.124.151"), 9999);
}/************************************************************ @函数名:on_pushButton_2_clicked* @功  能:按钮"停止监听"的槽函数* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_2_clicked()
{tcpServer->close();
}

3. 客户端程序编写

3.1 编写步骤:

【1】配置:①pro文件中添加network;②添加头文件<QTcpSocket>和<QHostAddress>。

【2】创建客户端对象:QTcpSocket *tcpSocket;(具体分配空间在构造函数中)

【3】创建信号槽来处理客户端的连接状态:connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(mStateChanged(QAbstractSocket::SocketState)));

【4】创建信号槽来接收客户端发送的信息:connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));

【5】编写【3】中的槽函数mStateChanged(...):switch-case处理。

【6】编写【4】中的槽函数receiveMessage(): 调用tcpSocket->readAll().

【7】创建函数来给服务端发送数据:内部调用"客户端对象.write("写入的内容")"。

【8】启动连接服务端:调用tcpSocket->connectToHost(QHostAddress("192.168.124.151"), 9999);

【9】断开连接服务端:调用tcpSocket->disconnectFromHost();

3.2 编写代码:

【1】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void receiveMessage();void mStateChanged(QAbstractSocket::SocketState socketstate);void on_pushButton_3_clicked();void on_pushButton_clicked();void on_pushButton_2_clicked();private:Ui::Widget *ui;QTcpSocket *tcpSocket;
};
#endif // WIDGET_H

【2】widget.cpp:

#include "widget.h"
#include "ui_widget.h"/************************************************************ @函数名:Widget* @功  能:构造函数---创建客户端对象,与服务端连接* @参  数:parent---父对象* @返回值:无*********************************************************/
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{//ui部分ui->setupUi(this);this->setWindowTitle("客户端");ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);//tcp部分tcpSocket = new QTcpSocket(this);connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),this, SLOT(mStateChanged(QAbstractSocket::SocketState)));
}/************************************************************ @函数名:~Widget* @功  能:析构函数* @参  数:无* @返回值:无*********************************************************/
Widget::~Widget()
{delete ui;
}/************************************************************ @函数名:receiveMessage* @功  能:槽函数---客户端接收服务端发送的数据* @参  数:无* @返回值:无*********************************************************/
void Widget::receiveMessage()
{ui->textBrowser->append("服务端:" + tcpSocket->readAll());
}/************************************************************ @函数名:mStateChanged* @功  能:槽函数---客户端连接状态改变的处理* @参  数:socketstate---当前连接状态* @返回值:无*********************************************************/
void Widget::mStateChanged(QAbstractSocket::SocketState socketstate)
{switch (socketstate) {case QAbstractSocket::UnconnectedState:ui->textBrowser->append("与服务端断开连接");ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);break;case QAbstractSocket::ConnectedState:ui->textBrowser->append("与服务端成功连接");ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(true);break;default:break;}
}/************************************************************ @函数名:on_pushButton_3_clicked* @功  能:"发送消息"按钮的槽函数,必须连接了服务端才发送* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_3_clicked()
{if (tcpSocket->state() == QAbstractSocket::ConnectedState){tcpSocket->write(ui->lineEdit->text().toUtf8());}else {ui->textBrowser->append("请先连接服务端!");}
}/************************************************************ @函数名:on_pushButton_clicked* @功  能:"连接服务端"按钮的槽函数* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_clicked()
{tcpSocket->connectToHost(QHostAddress("192.168.124.151"), 9999);
}/************************************************************ @函数名:on_pushButton_2_clicked* @功  能:"断开服务端"按钮的槽函数* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_2_clicked()
{tcpSocket->disconnectFromHost();
}

4. 服务端与客户端测试

4.1 注意事项:

  • 服务端中的"开始监听"和"停止监听"应该设置成互斥的。方法一:在ui设计器里将它们添加到一个按钮组,然后选中"exclusive",将它们的"checkable"勾选上,再将"停止监听"按钮的"checked"勾选。方法二:使用代码ui->pushButton->setEnable(对/错);实现它们逻辑的互斥。
  • 客户端中的"连接服务端"和"断开服务端"应该用上述的方法二实现互斥。
  • 在服务端中,当客户端断开连接时,直接调用delete可能会出错(其他地方可能还在用这个变量)。因此,应当使用tmpTcpSocket.deleteLater(); 来删除客户端对象。

4.2 运行效果:


三、QT中的UDP编程

1. UDP简介

  • 是一个轻量级的,不可靠的,面向数据报的无连接协议。
  • 通常音频、视频和普通数据在传送时使用 UDP 较多。
  • UDP 消息传送有三种模式:单播、广播和组播三种模式。

2. UDP单播与广播程序

2.1 编写步骤:

【1】配置:①pro文件中添加network;②添加头文件<QUdpSocket>。

【2】创建UDP对象:QUdpSocket *udpSocket;(具体分配空间在构造函数中)

【3】编写函数绑定端口:调用udpSocket->bind(端口号);

【4】编写函数解除绑定:调用udpSocket->abort();

【5】“发送-接收”的信号槽连接:connect(udpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));

【6】编写【5】中的receiveMessage来获取接收的数据:内部调用udpSocket->readDatagram(mesg.data(), mesg.size(), &receiveAddress, &port);

【7】编写函数来单播发送数据:调用udpSocket->writeDatagram(ui->lineEdit->text().toUtf8(), QHostAddress("127.0.0.1"), 9999);

【8】编写函数来广播发送数据:与【7】类似,只是将倒数第二个参数换成QHostAddress::Broadcast。要广播几个ip和端口,就调用几次writeDatagram。

【8】要想获取当前连接的状态,操作和TCP中的一样。

2.2 实例代码:

【1】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void receiveMessage();void on_pushButton_3_clicked();void on_pushButton_clicked();void on_pushButton_2_clicked();void on_pushButton_4_clicked();private:Ui::Widget *ui;QUdpSocket *udpSocket;
};
#endif // WIDGET_H

【2】widget.cpp:

#include "widget.h"
#include "ui_widget.h"/* 构造函数 */
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);//创建udp对象udpSocket = new QUdpSocket(this);connect(udpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));
}/* 析构函数 */
Widget::~Widget()
{delete ui;
}/* 接收信息的槽函数*/
void Widget::receiveMessage()
{QByteArray mesg;mesg.resize(udpSocket->pendingDatagramSize());QHostAddress receiveAddress;quint16 port;while (udpSocket->hasPendingDatagrams()) {udpSocket->readDatagram(mesg.data(), mesg.size(), &receiveAddress, &port);//保存接收的数据ui->textBrowser->append("接收来自:" + receiveAddress.toString() + ", 端口:" + QString::number(port));ui->textBrowser->append("接收信息:" + mesg);}
}/* 发送信息按钮的槽函数 */
void Widget::on_pushButton_3_clicked()
{udpSocket->writeDatagram(ui->lineEdit->text().toUtf8(), QHostAddress("127.0.0.1"), 9999);ui->textBrowser->append("发送信息:" + ui->lineEdit->text().toUtf8());
}/* 绑定端口按钮的槽函数 */
void Widget::on_pushButton_clicked()
{udpSocket->bind(9999);ui->textBrowser->append("当前绑定端口:" + QString::number(9999));ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(true);
}/* 解除绑定按钮的槽函数 */
void Widget::on_pushButton_2_clicked()
{udpSocket->abort();ui->textBrowser->append("解除绑定");ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);
}/* 广播信息按钮的槽函数 */
void Widget::on_pushButton_4_clicked()
{udpSocket->writeDatagram(ui->lineEdit->text().toUtf8(), QHostAddress::Broadcast, 9999);ui->textBrowser->append("发送信息:" + ui->lineEdit->text().toUtf8());
}

【3】ui设计器:

【4】运行效果:双开该程序,每次新运行程序前修改一下绑定的端口号并编译。同时,这两个端口号需要对应才能显示单播的效果。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高速直线导轨驱动与控制,精准稳定的运动核心元件

直线导轨在工业生产中&#xff0c;精度和稳定性是至关重要的。而在各种机械设备中&#xff0c;高精度直线导轨是提高设备运动控制精度和平稳性的核心部件&#xff0c;当我们考虑高速运动时&#xff0c;直线导轨的精度和稳定性是非常重要的因素。 直线导轨系统中如何确保高速运动…

电脑自带录屏在哪?电脑录屏,4个详细方法

在现代社会中&#xff0c;越来越多的人需要在电脑上录制视频&#xff0c;比如录制游戏操作、制作教学视频、演示文稿等等。因此&#xff0c;电脑录屏成为了一项非常重要的功能。那么电脑自带录屏在哪&#xff1f;本文将带领大家看看可以使用哪些方法进行录屏。 录屏方法一&…

linux中: IDEA 由于JVM 设置内存过小,导致打开项目闪退问题

1. 找到idea安装目录 由于无法打开idea&#xff0c;只能找到idea安装目录 在linux(debian/ubuntu)中idea的插件默认安装位置和配置文件在哪里? 默认路径&#xff1a; /home/当前用户名/.config/JetBrains/IntelliJIdea2020.具体版本号/options2. 找到jvm配置文件 IDEA安装…

【Gitlab】Gitlab MAC M1通过Docker Desktop安装教程

目录 一、拉取镜像 二、配置容器 2.1 配置Volumes 2.2 配置Gitlab 2.3 配置完成&#xff0c;重启GitLab容器 2.4 查看GitLab的root密码 三、brew安装gitlab 3.1 安装命令 3.2 启动命令 参考资料 一、拉取镜像 docker pull yrzr/gitlab-ce-arm64v8 二、配置容器 2.1 …

设计模式——建造者模式(生成器模式)

建造者模式(生成器模式) 将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示的意图 用了建造者模式&#xff0c;那么用户就只需要指定需要构建的类型就可以得到它们&#xff0c;而具体构造的细节和过程不需要知道 概括地说&#xff0c;Bu…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(三十二)- 微服务(12)

目录 12.8 RestClient查询文档 12.8.1 快速入门 12.8.2 match&#xff0c; term&#xff0c;bool&#xff0c;range查询 12.8.3 排序和分页 12.8.4 高亮 12.8 RestClient查询文档 12.8.1 快速入门 Testvoid testMatchALL() throws IOException {// 1. 准备requestSearchReq…

Tita 360评估:有效 360度反馈流程的 10 大步骤

宣传过程 如果你的公司首次引入多方位反馈或 360 度反馈&#xff0c;那么向所有利益相关者描述这一流程至关重要。由于流程太新&#xff0c;很多人还不了解。确保参与该流程的每个人都了解其目的&#xff0c;以及将如何实施该流程和使用其结果。花时间在一对一会议、小组会议和…

MyBatis 动态 SQL 的详细内容讲解

1. MyBatis 动态 SQL 的详细内容讲解 文章目录 1. MyBatis 动态 SQL 的详细内容讲解2. 准备工作3. if 标签4. where 标签5. trim 标签6. set 标签7. choose when otherwise 标签8. foreach 标签8.1 批量删除8.2 批量添加 9. SQL 标签与 include 标签10. 总结&#xff1a;11. 最…

centos下创建raid6磁盘阵列

在CentOS系统中创建RAID 6阵列&#xff0c;可以使用mdadm工具。 以下是创建RAID 6阵列的基本步骤和示例代码&#xff1a; 安装mdadm工具&#xff08;如果尚未安装&#xff09;&#xff1a; sudo yum install mdadm 假设你有至少四个以上的磁盘设备&#xff08;例如 /dev/sdi…

2024年最新Microsoft Edge关闭自动更新的方法分享

这里写自定义目录标题 打开【服务】 打开【服务】 windows中搜索服务&#xff0c;如下图&#xff1a; 打开服务界面&#xff0c;找到“Microsoft Edge Update Service (edgeupdate)” 及 “Microsoft Edge Update Service (edgeupdatem)” 两个服务&#xff0c;设置为禁用

【DrissionPage】Linux上如何将https改为http

最近有个老板找我做一个自动化的程序&#xff0c;要求部署到Linux上 这是一个http协议的网站&#xff0c;chrome在默认设置下&#xff0c;会将http的网站识别成不安全的内容&#xff0c;然后自动将http转化成https访问 但是&#xff0c;这个http的网站它的加载项里既有http的…

开源大模型之辩:真假开源

目录 前言开源的定义什么是开源大模型&#xff1f;大模型时代首次出现闭源和开源“齐头并进”开源和闭源不是绝对对立的 大模型到底开源什么&#xff1f;传统开源软件与开源大模型的差别开源软件让开源大模型“受益匪浅” 不同大模型企业&#xff0c;开源、闭源策略不同开源…

安装操作系统1-Win10版本介绍及硬件要求

注意&#xff1a;安装系统&#xff0c;首先弄清有哪些版本及所需硬件环境。 1.Win10有哪些版本 微软将 Win10为以下7个版本&#xff1a; Windows 10 家庭版&#xff08;Home&#xff09; 面向所有普通用户&#xff0c;提供Win 10的基本功能。此版本适合个人家庭用户使用&am…

一维信号的时频分析(Python)

代码较为简单&#xff0c;很容易读懂。 Importing the required libraries import os import numpy as np import pywt import pandas as pd import pickle as pkl from matplotlib import pyplot as plt Parameters or Required Variables DATA_POINTS_PER_FILE 2560 TIM…

Android Jetpack Compose入门教程(二)

一、列表和动画 列表和动画在应用内随处可见。在本课中&#xff0c;您将学习如何利用 Compose 轻松创建列表并添加有趣的动画效果。 1、创建消息列表 只包含一条消息的聊天略显孤单&#xff0c;因此我们将更改对话&#xff0c;使其包含多条消息。您需要创建一个可显示多条消…

(代数:解一元二次方程)可以使用下面的公式求一元二次方程 ax2+bx+c0 的两个根:

(代数:解一元二次方程)可以使用下面的公式求一元二次方程 ax2bxc0 的两个根: b2-4ac 称作一元二次方程的判别式。如果它是正值,那么一元二次方程就有两个实数根。 如果它为 0&#xff0c;方程式就只有一个根。如果它是负值&#xff0c;方程式无实根。 编写程序&#xff0c;提示…

STM32存储左右互搏 模拟U盘桥接SPI总线FATS读写FLASH W25QXX

STM32存储左右互搏 模拟U盘桥接SPI总线FATS读写FLASH W25QXX STM32的USB接口可以模拟成为U盘&#xff0c;通过FATS文件系统对连接的存储单元进行U盘方式的读写。 这里介绍STM32CUBEIDE开发平台HAL库模拟U盘桥接SPI总线FATS读写W25Q各型号FLASH的例程。 FLASH是常用的一种非易失…

vs2019 c++20规范 STL 库中头文件 <atomic> 源码注释及探讨几个知识点

&#xff08;1 探讨一&#xff09; 模板类 atomic 的继承关系与数据结构如下&#xff1a; (2 探讨二 ) 可见 atomic 的 fetch_xx 函数&#xff0c;返回的都是 atomic 中存储的旧值。测试如下&#xff1a; 谢谢

无公网IP与服务器完成企业微信网页应用开发远程调试详细流程

文章目录 前言1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 前言 本文主要介绍如何在企业微信开发者中心通过使用内网穿透工具提供的公网域名成功验证回调本地接口服务! …

互联网应用主流框架整合之SpringMVC初始化及各组件工作原理

Spring MVC的初始化和流程 MVC理念的发展 SpringMVC是Spring提供给Web应用领域的框架设计&#xff0c;MVC分别是Model-View-Controller的缩写&#xff0c;它是一个设计理念&#xff0c;不仅仅存在于Java中&#xff0c;各类语言及开发均可用&#xff0c;其运转流程和各组件的应…