Qt 系统相关 - 网络与音视频

目录

一、Qt 网络

1. UDP Socket

1.1 核心 API 概览

1.2 回显服务器

1.3 回显客户端

2. TCP Socket

2.1 核心 API 概览

2.2 回显服务器

2.3 回显客户端

3. HTTP Client

3.1 核心 API

3.2 代码示例

二、Qt 音视频

1. Qt 音频

1.1 核心API概览

1.2 示例

2. Qt 视频

2.1 核心API概览

2.2 示例


一、Qt 网络

  • 和多线程类似, Qt 为了支持跨平台, 对网络编程的 API 也进行了重新封装.
  • 在进行网络编程之前, 需要在项目中的 .pro 文件中添加 network 模块.
  • 添加之后要手动编译一下项目, 使 Qt Creator 能够加载对应模块的头文件.

1. UDP Socket

1.1 核心 API 概览

主要的类有两个. QUdpSocket QNetworkDatagram

  • QUdpSocket 表示一个 UDP 的 socket 文件.
名称类型说明对标原生 API
bind(const QHostAddress&, quint16)方法绑定指定的端口号.bind
receiveDatagram()方法返回 QNetworkDatagram . 读取⼀个 UDP 数据报.recvfrom
writeDatagram(const QNetworkDatagram&)方法发送⼀个 UDP 数据报.sendto
readyRead信号在收到数据并准备就绪后触发.无 (类似于 IO 多路复用的通知机制)
  • QNetworkDatagram 表示一个 UDP 数据报.
名称类型说明对标原生 API
QNetworkDatagram(const QByteArray&, const QHostAddress& , quint16 )构造函数通过 QByteArray , 目标 IP 地址, 目标端口号 构造⼀个 UDP 数据报. 通常用于发送数据时.
data()方法获取数据报内部持有的数据. 返回 QByteArray
senderAddress()方法获取数据报中包含的对端的 IP 地址.无, recvfrom 包含了该功能.
senderPort()方法获取数据报中包含的对端的端口号.无, recvfrom 包含了该功能.

1.2 回显服务器

1) 创建界面, 包含⼀个 QListWidget 用来显示消息.

2) 创建 QUdpSocket 成员

  • 修改 widget.h(注意:先在 .pro 文件中添加 network 模块.)
#include <QUdpSocket>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;QUdpSocket* socket;void processRequest();QString process(const QString& request);
};
  • 修改 widget.cpp, 完成 socket 后续的初始化
  1. 一般来说, 要先连接信号槽, 再绑定端口.
  2. 如果顺序反过来, 可能会出现端口绑定好了之后, 请求就过来了. 此时还没来得及连接信号槽. 那么这个请求就有可能错过了.
#include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 创建出这个对象socket = new QUdpSocket(this);// 设置窗口标题this->setWindowTitle("服务器");// 连接信号槽,处理收到的请求connect(socket, &QUdpSocket::readyRead, this, &Widget::processRequest);// 绑定端口号bool ret = socket->bind(QHostAddress::Any, 9090);if (!ret){QMessageBox::critical(nullptr, "服务器启动出错", socket->errorString());return;}
}

3) 实现 processRequest , 完成处理请求的过程

  • 读取请求并解析
  • 根据请求计算响应
  • 把响应写回到客户端
#include <QNetworkDatagram>// 这个函数完成的逻辑,就是服务器的最核心逻辑
void Widget::processRequest()
{// 1. 读取请求并解析const QNetworkDatagram& requestDatagram = socket->receiveDatagram();QString request = requestDatagram.data();// 2. 根据请求计算响应(由于是回显服务器,响应不需要计算,就是请求本身)const QString& response = process(request);// 3. 把响应写回到客户端QNetworkDatagram responseDatagram(response.toUtf8(), requestDatagram.senderAddress(), requestDatagram.senderPort());socket->writeDatagram(responseDatagram);// 显示打印日志QString log = "[" + requestDatagram.senderAddress().toString() + ":" +QString::number(requestDatagram.senderPort())+ "] req: " + request + ", resp: " + response;ui->listWidget->addItem(log);}

4) 实现 process 函数

  • 由于我们此处是实现回显服务器. 所以 process 方法中并没有包含实质性的内容.
QString Widget::process(const QString &request)
{// 由于当前是回显服务器,响应就是和请求完全一样// "根据请求处理响应" 是服务器开发中的最核心的步骤.//一个商业服务器程序, 这里的逻辑可能是几万行几十万行代码量级的.return request;
}

此时, 服务器程序编写完毕.

但是直接运行还看不出效果. 还需要搭配客户端来使用.

1.3 回显客户端

1) 创建界面. 包含⼀个 QLineEdit , QPushButton , QListWidget

  • 先使用水平布局把 QLineEdit 和 QPushButton 放好, 并设置这两个控件的垂直方向的sizePolicy Expanding
  • 再使用垂直布局把 QListWidget 和上面的水平布局放好.
  • 设置垂直布局的 layoutStretch 为 5, 1 (尺寸比例根据个人喜好微调).

2) 在 widget.cpp 中, 先创建两个全局常量, 表示服务器的 IP 和 端口

// 提前定义好服务器的 IP 和 端口
const QString& SERVER_IP = "127.0.0.1";
const quint16 SERVER_PORT = 9090;

3) 创建 QUdpSocket 成员

  • 修改 widget.h, 定义成员
#include <QUdpSocket>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;// 创建 socket 成员QUdpSocket* socket;
};

修改 widget.cpp, 初始化 socket

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 1. 设置窗⼝名字this->setWindowTitle("客⼾端");// 2. 实例化 socketsocket = new QUdpSocket(this);
}

4) 给发送按钮 slot 函数, 实现发送请求.

#include <QNetworkDatagram>void Widget::on_pushButton_clicked()
{// 1. 获取到输⼊框的内容const QString& text = ui->lineEdit->text();// 2. 构造 UDP 的请求数据QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT);// 3. 发送请求数据socket->writeDatagram(requestDatagram);// 4. 把发送的请求也添加到列表框中ui->listWidget->addItem("客⼾端说: " + text);// 5. 清空输⼊框ui->lineEdit->setText("");
}

5) 再次修改 Widget 的构造函数, 通过信号槽, 来处理服务器的响应.

// 通过信号槽,来处理服务器返回的数据
connect(socket, &QUdpSocket::readyRead, this, &Widget::processResponse);void Widget::processResponse()
{// 通过这个函数来处理收到的响应// 1.读取到响应数据const QNetworkDatagram& responseDatagram = socket->receiveDatagram();QString response = responseDatagram.data();// 2.把响应数据显示到界面上ui->listWidget->addItem("服务器说:" + response);
}

6) 最终执行效果(启动多个客户端都可以正常工作.

  • 客户端服务器程序测试时候的基本原则,一定是先启动服务器,后启动客户端

2. TCP Socket

2.1 核心 API 概览

核心类是两个: QTcpServer QTcpSocket

  • QTcpServer 用于监听端口, 和获取客户端连接.
名称类型说明对标原生 API
listen(const QHostAddress&, quint16 port)方法绑定指定的地址和端口号, 并开始监听.bind 和 listen
nextPendingConnection()方法从系统中获取到⼀个已经建立好的 tcp 连接. 返回⼀个 QTcpSocket , 表示这个客户端的连接. 通过这个 socket 对象完成和客户端之间的通信.accept
newConnection信号有新的客户端建立连接好之后触发.无 (但是类似于 IO 多路复用中的通知机制)
  • QTcpSocket 用于客户端和服务器之间的数据交互.
名称类型说明对标原生 API
readAll()方法读取当前接收缓冲区中的所有数据. 返回 QByteArray 对象.read
write(const QByteArray& )方法把数据写入 socket 中.write
deleteLater方法暂时把 socket 对象标记为无效. Qt 会在下个事件循环中析构释放该对象.无 (但是类似于 "半自动化的垃圾回收")
readyRead信号有数据到达并准备就绪时触发.无 (但是类似于 IO 多路复用中的通知机制)
disconnected信号连接断开时触发.无 (但是类似于 IO 多路复用中的通知机制)

QByteArray 用于表示一个字节数组. 可以很方便的和 QString 进行相互转换.

例如:

  • 使用 QString 的构造函数即可把 QByteArray 转成 QString.
  • 使用 QString 的 toUtf8 函数即可把 QString 转成 QByteArray.
     

2.2 回显服务器

1) 创建界面. 包含一个 QListWidget , 用于显示收到的数据.

2) 创建 QTcpServer 并初始化

  • 修改 widget.h, 添加 QTcpServer 指针成员.
#include <QTcpServer>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void processConnection();QString process(const QString& request);private:Ui::Widget *ui;// 创建 QTcpServerQTcpServer* tcpServer;
};

修改 widget.cpp, 实例化 QTcpServer 并进行后续初始化操作.

  • 设置窗口标题
  • 实例化 TCP server. (父元素设为当前控件, 会在父元素销毁时被一起销毁).
  • 通过信号槽, 处理客户端建立的新连接.
  • 监听端口
#include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 1.修改窗口标题this->setWindowTitle("服务器");// 2.创建 QTcpServer 的实例tcpServer = new QTcpServer(this);// 3.通过信号槽,指定如何处理连接connect(tcpServer, &QTcpServer::newConnection, this, &Widget::processConnection);// 4.绑定并监听端口号bool ret = tcpServer->listen(QHostAddress::Any, 9090);if (!ret){QMessageBox::critical(this, "服务器启动失败", tcpServer->errorString());exit(1);}
}

3) 继续修改 widget.cpp, 实现处理连接的具体方法 processConnection

  • 获取到新的连接对应的 socket.
  • 通过信号槽, 处理收到请求的情况
  • 通过信号槽, 处理断开连接的情况
void Widget::processConnection()
{// 1. 通过 tcpServer 拿到一个 socket 对象,通过这个对象来和客户端进行通信QTcpSocket* clientSocket = tcpServer->nextPendingConnection();QString log = QString("[") + clientSocket->peerAddress().toString()+ ":" + QString::number(clientSocket->peerPort()) + "] 客户端上线!";ui->listWidget->addItem(log);// 2. 通过信号槽, 处理收到请求的情况connect(clientSocket, &QTcpSocket::readyRead, this, [=](){// a) 读取请求QString request = clientSocket->readAll();// b) 根据请求处理响应const QString& response = process(request);// c) 把响应写回客户端clientSocket->write(response.toUtf8());// d) 把上述信息记录到日志中QString log = QString("[") + clientSocket->peerAddress().toString()+ ":" + QString::number(clientSocket->peerPort()) + "] req: " +request + ", resp: " + response;ui->listWidget->addItem(log);});// 3. 通过信号槽, 处理断开连接的情况connect(clientSocket, &QTcpSocket::disconnected, this, [=]() {// a) 把断开连接的信息通过日志显示出来QString log = QString("[") + clientSocket->peerAddress().toString()+ ":" + QString::number(clientSocket->peerPort()) + "] 客户端下线!";ui->listWidget->addItem(log);// b) 手动释放 clientSocket。直接使用 delete 是下策,使用 deleteLater 更加合适 clientSocket->deleteLater();});        
}

4) 实现 process 方法, 实现根据请求处理响应.

  • 由于我们此处是实现回显服务器. 所以 process 方法中并没有包含实质性的内容.
// 此处写的是回显服务器
QString Widget::process(const QString &request)
{return  request;
}

此时, 服务器程序编写完毕.

但是直接运行还看不出效果. 还需要搭配客户端来使用.

2.3 回显客户端

1) 创建界面. 包含一个 QLineEdit , QPushButton , QListWidget

  • 先使用水平布局把 QLineEdit 和 QPushButton 放好, 并设置这两个控件的垂直方向的sizePolicyExpanding
  • 再使用垂直布局把 QListWidget 和上面的水平布局放好.
  • 设置垂直布局的 layoutStretch 为 5, 1 (尺寸比例根据个人喜好微调).

2) 创建 QTcpSocket 并实例化

  • 修改 widget.h, 创建成员.
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;// 新增 QTcpSocketQTcpSocket* socket;
};

修改 widget.cpp, 对 QTcpSocket 进行实例化.

  • 设置窗口标题
  • 实例化 socket 对象 (父元素设为当前控件, 会在父元素销毁时被一起销毁).
  • 和服务器建立连接.
  • 等待并确认连接是否出错.
#include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 1. 设置窗口标题.this->setWindowTitle("客户端");// 2. 实例化 socket 对象.socket = new QTcpSocket(this);// 3. 和服务器建⽴连接.socket->connectToHost("127.0.0.1", 9090);// 4. 等待并确认连接是否出错.if (!socket->waitForConnected()) {QMessageBox::critical(nullptr, "连接服务器出错!", socket->errorString());exit(1);}
}

3) 修改 widget.cpp, 给按钮增加点击的 slot 函数, 实现发送请求给服务器.

void Widget::on_pushButton_clicked()
{// 获取输入框的内容const QString& text = ui->lineEdit->text();// 发送消息给服务器socket->write(text.toUtf8());// 把消息显示到界⾯上ui->listWidget->addItem(QString("客户端说: ") + text);// 清空输入框内容ui->lineEdit->setText("");
}

4) 修改 widget.cpp 中的 Widget 构造函数, 通过信号槽, 处理收到的服务器的响应.

// 连接信号槽,处理响应
connect(socket, &QTcpSocket::readyRead, this, [=](){// a) 读取出响应内容QString response = socket->readAll();// b) 把响应内容显示到界面上ui->listWidget->addItem("服务器说:" + response);
});

6) 最终执行效果(先启动服务器, 再启动客户端,可以启动多个

  • 由于我们使用信号槽处理同一个客户端的多个请求, 不涉及到循环, 也就不会使客户端之间相互影响了.

3. HTTP Client

进行 Qt 开发时, 和服务器之间的通信很多时候也会用到 HTTP 协议.

  • 通过 HTTP 从服务器获取数据.
  • 通过 HTTP 向服务器提交数据.

3.1 核心 API

关键类主要是三个:QNetworkAccessManager , QNetworkRequest , QNetworkReply .

  • QNetworkAccessManager 提供了 HTTP 的核心操作.
方法说明
get(const QNetworkRequest& )发起⼀个 HTTP GET 请求. 返回 QNetworkReply 对象.
post(const QNetworkRequest& , const QByteArray& )发起⼀个 HTTP POST 请求. 返回 QNetworkReply 对象.
  • QNetworkRequest 表示一个 HTTP 请求(不含 body).

如果需要发送一个带有 body 的请求(比如 post), 会在 QNetworkAccessManager 的 post 方法中通过单独的参数来传入 body.

方法说明
QNetworkRequest(const QUrl& )通过 URL 构造⼀个 HTTP 请求.
setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)设置请求头.

其中的 QNetworkRequest::KnownHeaders 是一个枚举类型, 常用取值:

取值说明
ContentTypeHeader描述 body 的类型.
ContentLengthHeader描述 body 的长度.
LocationHeader用于重定向报文中指定重定向地址. (响应中使用, 请求用不到)
CookieHeader设置 cookie
UserAgentHeader设置 User-Agent
  • QNetworkReply 表示一个 HTTP 响应. 这个类同时也是 QIODevice 的子类.
方法说明
error()获取出错状态.
errorString()获取出错原因的文本.
readAll()读取响应 body.
header(QNetworkRequest::KnownHeaders header)读取响应指定 header 的值.

此外, QNetworkReply 还有一个重要的信号 finished 会在客户端收到完整的响应数据之后触发.

3.2 代码示例

给服务器发送⼀个 GET 请求.

1) 创建界面. 包含一个 QLineEdit , QPushButton

  • 先使用水平布局把 QLineEdit 和 QPushButton 放好, 并设置这两个控件的垂直方向的 sizePolicy 为 Expanding
  • 再使用垂直布局把 QPlainTextEdit 和上面的水平布局放好. ( QPlainTextEdit 的 readOnly 设为 true )
  • 设置垂直布局的 layoutStretch 为 5, 1 (尺寸比例根据个人喜好微调).

🌵此处建议使用 QPlainTextEdit 而不是 QTextEdit . 主要因为 QTextEdit 要进行富文本解析, 如果得到的 HTTP 响应体积很大, 就会导致界面渲染缓慢甚至被卡住.

2) 修改 widget.h, 创建 QNetworkAccessManager 属性

class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QNetworkAccessManager* manager;
};

3) 修改 widget.cpp, 创建实例

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("客户端");// 实例化属性manager = new QNetworkAccessManager(this);
}

4) 编写按钮的 slot 函数, 实现发送 HTTP 请求功能.

void Widget::on_pushButton_clicked()
{// 1. 获取到输⼊框中的 URL, 构造 QUrl 对象QUrl url(ui->lineEdit->text());// 2. 构造 HTTP 请求对象QNetworkRequest request(url);// 3. 发送 GET 请求QNetworkReply* response = manager->get(request);// 4. 通过信号槽来处理响应connect(response, &QNetworkReply::finished, this, [=]() {if (response->error() == QNetworkReply::NoError) {// 响应正确QString html(response->readAll());ui->plainTextEdit->setPlainText(html);// qDebug() << html;} else {// 响应出错ui->plainTextEdit->setPlainText(response->errorString());}// 还需要对 response 进行释放response->deleteLater();});
}

5) 执行程序, 观察效果

发送 POST 请求代码也是类似. 使用 manager->post() 即可.

二、Qt 音视频

1. Qt 音频

        在 Qt 中,音频主要是通过 QSound 类来实现。但是需要注意的是 QSound 类只只持播放 wav 格式的音频文件。也就是说如果想要添加音频效果,那么首先需要将 非wav格式 的音频文件转换为 wav 格式。

通过帮助手册查看 QSound 类如下:

注意:

  • 使用 QSound 类时,需要添加模块:multimedia

1.1 核心API概览

play()开始或继续播放当前源。

1.2 示例

/********************************* SoundTest.pro
*********************************/QT       += core gui multimedia //添加⾳频模块/********************************* widget.cpp
*********************************/
#include "widget.h"
#include "ui_widget.h"
#include <QSound> //添加⾳频头⽂件Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//实例化对象QSound *sound = new QSound(":/1.wav",this);connect(ui->btn,&QPushButton::clicked,[=](){sound->play(); //播放});
}Widget::~Widget()
{delete ui;
}

2. Qt 视频

        在 Qt 中,视频播放的功能主要是通过 QMediaPlayer类QVideoWidget类 来实现。在使用这两个类时要添加对应的模块 multimedia multimediawidgets

2.1 核心API概览

setMedia()设置当前媒体源。
setVideoOutput()将QVideoWidget视频输出附加到媒体播放器。 如果媒体播放器已经附加了视频输出,将更换⼀个新的。

2.2 示例

首先在 .pro 文件中添加 multimedia 和 multimediawidgets 两个模块;如下图示:

/********************************* widget.h *********************************/
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QHBoxLayout> //⽔平布局
#include <QVBoxLayout> //垂直布局
#include <QVideoWidget> //显⽰视频
#include <QMediaPlayer> //播放声⾳
#include <QPushButton> //按钮
#include <QStyle> //设置图标
#include <QFileDialog> //选择⽂件/⽂件夹class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void chooseVideo();private:QMediaPlayer *mediaPlayer;QVideoWidget *videoWidget;QVBoxLayout *vbox;//创建两个按钮:选择视频按钮和开播放按钮QPushButton *chooseBtn,*playBtn;
};#endif // WIDGET_H/********************************* widget.cpp
*********************************/
#include "widget.h"
#include <QMediaPlayer>
#include <QSlider>Widget::Widget(QWidget *parent): QWidget(parent)
{//对象实例化mediaPlayer = new QMediaPlayer(this);videoWidget = new QVideoWidget(this);//设置播放画⾯的窗⼝videoWidget->setMinimumSize(600,600);//实例化窗⼝布局---垂直布局this->vbox = new QVBoxLayout(this);this->setLayout(this->vbox);//实例化选择视频按钮chooseBtn = new QPushButton("选择视频",this);//实例化播放按钮playBtn = new QPushButton(this);//设置图标代替⽂件playBtn->setIcon(this->style()->standardIcon(QStyle::SP_MediaPlay));//实例化⼀个⽔平布局,将以上控件放⼊⽔平布局中QHBoxLayout *hbox = new QHBoxLayout;//添加控件hbox->addWidget(chooseBtn);hbox->addWidget(playBtn);//将播放窗⼝和⽔平布局都添加到垂直布局中vbox->addWidget(videoWidget);//布局中添加布局vbox->addLayout(hbox);//将选择视频对应的按钮和槽函数进⾏关联connect(chooseBtn,&QPushButton::clicked,this,&Widget::chooseVideo);
}void Widget::chooseVideo()
{//选择视频,返回⼀个播放视频的名字QString name = QFileDialog::getSaveFileName(this,"选择视频",".","WMV(*.wmv)");//设置媒体声⾳mediaPlayer->setMedia(QUrl(name));//输出视频画⾯mediaPlayer->setVideoOutput(videoWidget);//播放mediaPlayer->play();
}Widget::~Widget()
{ }

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

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

相关文章

加速网络体验,Squid缓存代理:让浏览如飞,畅享无限网络速度!

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元 个人主页&#xff1a;团儿.-CSDN博客 目录 前言: squ…

订单到期关闭如何实现?

目录 一、被动关闭 二、定时任务 三、JDK自带的DelayQueue 四、Netty的时间轮 五、Kafka的时间轮 六、RocketMQ延迟消息 七、RabbitMQ死信队列 八、RabbitMQ插件 九、Redis过期监听 十、Redis的Zset 十一、Redisson 在电商、支付等系统中&#xff0c;一般都是先创建…

详解华为项目管理,附华为高级项目管理内训材料

&#xff08;一&#xff09;华为在项目管理中通过有效的沟通、灵活的组织结构、坚持不懈的努力、细致的管理和科学的考核体系&#xff0c;实现了持续的创新和发展。通过引进先进的管理模式&#xff0c;强调以客户需求为导向&#xff0c;华为不仅优化了技术管理和项目研发流程&a…

多重示例详细说明Eureka原理实践

Eureka原理&#xff08;Eureka Principle&#xff09;是指在长时间的思考和积累之后&#xff0c;通过偶然的瞬间获得灵感或发现解决问题的方法的一种认知现象。这个过程通常包括三个主要阶段&#xff1a;准备阶段、潜伏期以及突然的灵感爆发。下面详细说明Eureka原理的实践步骤…

vue3 组合式API

<!-- 深度监听 deep 点击按钮控制台&#xff0c;才输出count变化了: 1, 老值: 0;否则控制台不输出 --> <script setup>import { ref,watch } from vueconst state ref({count:0})const setCount () > {state.count.value}watch(state, () > {console.log(…

QT中通过TCP协议多线程的文件传输(客户端)

首先&#xff0c;新建一个项目&#xff0c;我命名为了SendFileClient 首先我们要在pro文件中 代码第一行加入network的后缀 一、窗口搭建 如图所示&#xff0c;在第一个QWidget中让客户端输入IP&#xff0c;端口号 连接服务器 第二个Qwidget 设置一个LineEdit,供客户端选择要…

[godot] 采用状态机时,如何处理攻击时移动?如“冲撞”

这里以‘史莱姆撞击’为例子&#xff0c;将‘空中跃进’定义为伤害帧。&#xff08;见下图&#xff09; 先梳理流程&#xff1a;a.史莱姆原地蓄力(起跳准备)--->b.跳起并移动一段距离(空中跃进)--->c.落地调整 一 当状态机进入‘攻击状态’时&#xff0c;在enter()中…

计算机毕业设计PySpark+Django农产品推荐系统 农产品爬虫 农产品商城 农产品大数据 农产品数据分析可视化 PySpark Hadoop

基于Spark的农产品个性推荐系统 相关技术介绍: 1. Python Python是一种高级编程语言&#xff0c;具有简洁、易读、易学的特点&#xff0c;被广泛应用于Web开发、数据分析、人工智能等领域。 在此系统中&#xff0c;我们使用Python进行后端开发&#xff0c;利用其强大的语法…

基本数据类型 --- 浮点型

float的机器码表示&#xff1a; 一个float数据 (pow(-1, sign) fraction) * pow(2, exponent - 127) 由上图&#xff0c;可得&#xff1a; (pow(-1, sign) fraction) * pow(2, exponent - 127) ( 1 2^(-2) ) * pow(2, 124-127) 0.15625 其他文章&#xff1a; https://b…

鸿蒙HarmonyOS之使用ArkTs语言实现层级树状目录选择UI

一、实现效果 二、实现步骤 代码示例中用到的颜色、图片等资源可以自行替换设置 1、Index.ets 里面调用 import { CategoryView} from ./CategoryView;//主页面 Entry Component struct Index {State tabsIndex: number 0;build() {...//层级目录ViewCategoryView()...} …

ReTagList标签列表(API)

组件实现基于 Vue3 + Element Plus + Typescript,同时引用 vueUse + lodash-es + tailwindCss (不影响功能,可忽略) 基于ElTag实现的Tag列表,支持Tag列表多选,动态Tag列表 ReTagList标签列表 基础 简单展示Tag列表,可通过size指定尺寸 查看 /demo/tag-list/basic.md …

Arduino开源四足蜘蛛机器人制作教程

视频教程&#xff1a;手把手叫你做四足蜘蛛机器人——1零件介绍_哔哩哔哩_bilibili 一、项目介绍 1.1 项目介绍 Arduino主控&#xff0c;图形化编程&#xff0c;趣味学习 Arduino nano开发板舵机扩展底板 4.8V可充电电池&#xff0c;支持Arduino C语言编程和米思齐图形化编程…

Yolov10网络详解与实战(附数据集)

文章目录 摘要模型详解模型实战训练COCO数据集下载数据集 COCO转yolo格式数据集&#xff08;适用V4&#xff0c;V5&#xff0c;V6&#xff0c;V7&#xff0c;V8&#xff09;配置yolov10环境训练断点训练测试 训练自定义数据集Labelme数据集格式转换训练测试 总结 摘要 模型详解…

CeresPCL 岭回归拟合(曲线拟合)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 由于在使用最小二乘插值拟合时,会涉及到矩阵求逆的操作,但是如果这个矩阵接近于奇异时,那么拟合的结果就会与我们期望的结果存在较大差距,因此就有学者提出在最小二乘的误差函数中添加正则项,即: 这里我们也可…

OpenGL-ES 学习(8) ---- FBO

目录 FBO OverViewFBO 优点使用FBO的步骤 FBO OverView FBO(FrameBuffer Object) 指的是帧缓冲对象&#xff0c;实际上是一个可以添加缓冲区容器&#xff0c;可以为其添加纹理或者渲染缓冲区对象(RBO) FBO(FrameBuffer Object) 本身不能用于渲染&#xff0c;只有添加了纹理或者…

Stability AI发布了单目视频转4D模型的新AI模型:Stable Video 4D

开放生成式人工智能初创公司Stability AI在3月发布了Stable Video 3D&#xff0c;是一款可以根据图像中的物体生成出可旋转的3D模型视频工具。Stability AI在7月24日发布了新一代的Stable Video 4D&#xff0c;增添了赋予3D模移动作的功能。 Stable Video 4D能在约40秒内生成8…

数字乡村+智慧农业数字化转型大数据平台建设方案

1. 数字农业发展趋势 数字农业正经历全环节数字技术应用、全流程生产经营再造、全方位线上线下对接和管理服务全生命周期覆盖的四大趋势&#xff0c;标志着我国农业进入高质量发展新阶段。 2. 数字乡村的战略意义 数字乡村作为数字化、网络化和信息化的产物&#xff0c;对于…

Wemos D1 Mini pro/ nodeMcu / ESP8266 驱动 240*320 ILI9431 SPI液晶屏

Wemos D1 Mini / nodeMcu / ESP8266 驱动 240*320 ILI9431 SPI液晶屏 效果展示器件硬件连接引脚连接原理图引脚对照表 安装TFT_eSPI库TFT_eSPI库中User_Setup.h文件的参数修改User_Setup.h文件的位置User_Setup.h文件中需要修改的参数User_Setup.h完成源码 例程 缘起&#xff1…

网络间通信

1、udp通信 特点&#xff1a;&#xff08;1&#xff09;无连接 &#xff08;2&#xff09;不可靠 2、udp编程&#xff08;c/s模型&#xff09; ssize_t recvfrom(int sockfd, //socket的fd void *buf, //保存数据的一块空间的地址 …