【Qt学习笔记】(一)初识Qt

Qt学习笔记

  • 1 使用Qt Creator 新建项目
  • 2 项目代码解释
  • 3 创建第一个 Hello World 程序
  • 4 关于内存泄漏问题
  • 5 Qt 中的对象树
  • 6 关于 qDebug()的使用
  • 7 使用其他方式创建一个 Hello World 程序(编辑框和按钮方式)
  • 8 关于 Qt 中的命名规范 / 快捷键 / 查询文档
  • 9 Qt 窗口坐标系

本文使用的是Qt6.2

1 使用Qt Creator 新建项目

新建项目
打开Qt Creator 界面后点击左上角的 文件 选择 new project
在这里插入图片描述
选择项目模板
在这里插入图片描述

项目模板说明
ApplicationQt应用程序,包括普通窗体程序和QtQuick程序
Libary可以创建动态库、静态库以及Qt Quick 扩展插件、QtCreator 自身插件
其他项目可以创建单元测试项目、Qt4设计师自定义控件、子目录项目等
Non-Qt-Project非Qt项目。可以创建纯C或C++项目
import Project导入项目。从版本控制系统管理的软件项目导入旧的项目

常用的是第一类,选中后,在右侧会显示出Qt应用程序的五个子模版:

  • Qt Widgets Application :普通窗体模板,传统基于部件的窗体界面程序
  • Qt console Application :Qt 控制台应用程序。因为Qt主要用于图形界面设计,这个控制台项目基本不用。
  • Qt for Python:在Python 下用LGPL的许可来开发闭源Qt软件。
  • Qt Quick Application: Qt 提供的一种高级用户界面技术,使用它可以方便快速的为移动以及嵌入式设备开发流畅美观的用户界面。QtQuick模块是开发QML应用的标准库,提供了使用QML创建用户界面所需的一切,包括可视化、交互、动画、模型、视图、粒子效果以及着色效果等。

选择了不同的项目模板,Qt Creator 就会在项目创建完毕以后生成不同的基础代码

选择项目路径
在这里插入图片描述

注意创建路径名称不能有中文!!!

选择构建系统

在这里插入图片描述

使用默认的qmake即可

Qt中的构建工具有三种可供选择,分别是: qmake、CMake、 Qbs,下面依次介绍。

  • qmake: qmake是一个构建工具(build tool) ,用于自动生成makefile文件。qmake支持跨平台构建。qmake编辑的是一个后缀名为.pro的文件。
  • CMake: CMake是一个跨平台的构建工具。CMake本身不是一个编译器,其实就是生成一个让编译器能读懂编译流程的文件工具。让CMake自动生成构建系统,例如Makefile和Visual Studio项目文件。CMake 是一个第三方工具,有自己的文档。
  • Qbs: Qbs (Qt Build Suite: Qt构建套件)同qmake、 CMake一样都是构建工具。Qbs号称是新一代的构建工具,比qmake编译速度更快。Qbs 没有绑定Qt版本,它从项目文件的高级项目描述中生成一个正确的依赖表。而传统的MakeFile生成工具如qmake和CMake,其在生成MakeFile文件后将实际的命令交给Make工具去执行。

Qt官方声明,因市场原因,弃用Qbs。对于Qt用户来说,qmake是当前使用最广泛的构建工具,CMake其次。

填写类信息设置界面
在这里插入图片描述
对于基类的选择,目前有三种基类

基类说明
QMainWindow主窗口类,一般用于较为复杂的应用程序,除了中央客户区界面,还包括菜单栏、工具栏、状态栏以及多个可停靠的工具对话框等
QWidget最简单、最基本的窗体程序,里面可以放置多个控件实现程序功能.
QDialog基于对话框的程序,对话框一般用于弹窗, 也可以用于主界面显示。对话框是从QWidget继承而来的,并丰富了一些能,如模态显示和返回值等

三者关系如下图
在这里插入图片描述

选择语言和翻译文件 在这里插入图片描述
这里的语言不是编程语言,而是例如“中文” “英文” 这种语言
由于暂时不需要考虑国际化问题,直接点击下一步即可

选择 Qt 套件

在这里插入图片描述
Qt套件是指Qt程序从编译链接到运行环境的全部工具和Qt类库的集合,对于MinGW版本Qt程序生成和调试,至少需要MinGW中的编译器g++ (自 动调用链接器)、g++ 配套的基础库、调试器gdb还有使用MinGW环境编译而成的Qt类库自身。默认情况下,在上面Kit Selection里选中全部套件。

选择版本控制系统

在这里插入图片描述
如果想把代码提交到github可以在这里选择

项目构建完成
在这里插入图片描述
点击左下角运行按钮,或者按CTRL+R,查看效果
在这里插入图片描述

2 项目代码解释

main.cpp 文件解析
在这里插入图片描述
QApplication 为应用程序类;代码中 QApplication a ,a 为应用程序对象,有且仅有一个;

  • QApplication 管理图形用户界面应用程序的控制流和主要设置;
  • QApplication是Qt的整个后台管理的命脉。它包含主事件循环,在其中来自窗口系统和其它资源的所有事件处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理。
  • 对于任何一个使用Qt的图形用户界面应用程序,都正好存在一个QApplication对象,而不论
    这个应用程序在同一时间内是不是有0、1、 2或更多个窗口。

Widget 为刚才创建项目的时候,所选的类名

  • w.show() 调用show函数显示窗口
  • Widget 的父类是QWidget,函数由该父类提供

a.exec() :程序进入消息循环,等待对用户输入进行响应。这里main()把控制权转交给Qt, Qt 完
成事件处理工作,当应用程序退出的时候exec()的值就会返回。在exec() 中,Qt接受并处理用户
和系统的事件并且把它们传递给适当的窗口部件。

widget.h 文件解析
在这里插入图片描述

  • 在 Qt 中,头文件的命名是有规律的,一般类名和头文件的命名相同。
  • Q_OBJECT 本质上是一个宏,展开后是一长段代码。如果某个类想使用信号和槽机制,就需要引入这个宏。
  • 图中第17行代码为构造函数,这里在后面的“对象树”中会再次提到。
  • Ui::Widget *ui 和form file文件密切相关,通过该指针,可以访问UI界面中的任意控件。

widget.cpp 文件解析

在这里插入图片描述
widget.ui 文件解析
点击form file 中的 ui 文件,打开图形编辑界面
在这里插入图片描述

在这里插入图片描述
点击左侧的“编辑”,查看该ui界面的本体
在这里插入图片描述

该格式为XML格式,和HTML格式类似
Qt 中使用XML文件去描述程序的界面,进一步会结合qmake 调用相关的工具,依据XML文件生成C++代码,从而把完整的界面构造出来

.pro 文件解析

在这里插入图片描述

  • .pro 是Qt项目的工程文件,也是qmake工具构建时的重要依据。
  • .pro 类似与Makefile 文件,qmake搭配.pro文件起到的作用和Makefile是类似的
  • 图中第一行代码是要引入的QT模块,后面学习一些内容的时候会修改这里
    在这里插入图片描述
    中间文件

如果编译运行Qt项目,构建过程中还会生成一些中间文件,如下图,打开资源管理器查看
在这里插入图片描述
打开后,返回上一级会看到多出来一个build-xxx文件夹,这个文件夹里面就是项目在运行过程中生成的一些临时文件
在这里插入图片描述
在这里插入图片描述

  • 可以看到编译Qt程序,还是会用到makefile文件,只不过不需要我们手动去写,而是qmake自动生成的。
  • widget.ui 由xml 生成的ui_widget.h 文件也在图中,双击打开查看
    在这里插入图片描述
    之前提到的 widget.h 里的ui指针就是该类的指针
    在这里插入图片描述
  • 点击debug 文件,可以看到最终生成的可执行程序
    在这里插入图片描述
    直接运行,效果和在Qt Creator 中运行是相同的效果。(运行失败的话,看看有没有配置环境变量)

3 创建第一个 Hello World 程序

利用 Qt 创建一个Hello World 程序有两种方式。分别是图形化的方式和纯代码的方式。

图形化方式
图形化方式比较简单,打开 ui 界面,然后找到 Label标签 拖动到编辑界面,然后输入文字即可。
在这里插入图片描述

运行程序,查看效果。
在这里插入图片描述
在 Qt Designer 的右边可以查看有哪些控件,label 实际上就是一个界面上用来显示字符串的控件
在这里插入图片描述
在编辑界面可以看到XML文件中多了一段代码,qmake就会在编译项目的时候,基于这个内容生成一段C++代码,构建出界面内容。
在这里插入图片描述
在这里插入图片描述
纯代码方式创建Hello World 程序

一般通过代码来构造界面的时候,通常会把构造界面的代码放到 Widget 的构造函数中
在这里插入图片描述

代码如下,记得包含头文件
在这里插入图片描述
运行查看效果
在这里插入图片描述
Hello World 程序创建完成。但是文字默认在左上角,通过纯代码的方式也可以修改,后面会讲。

4 关于内存泄漏问题

在这段代码中,在 new 了一个对象之后,却没有 delete ,会不会造成内存泄漏?
答案是在 Qt 中不会造成内存泄漏。此处通过 new 的方式创建对象,就是为了把该对象的生命周期交给 Qt 的对象树统一管理。代码中的 label 对象会在合适的时机被析构释放,这个合适的时机是指在窗口关闭的时候。
在这里插入图片描述

5 Qt 中的对象树

Qt 中的对象树,是一颗 N叉树 ,通过该树把界面上的各种元素组织起来。
比如有如下几种元素。
在这里插入图片描述
经过对象树组织后,就变成下图所示
在这里插入图片描述
使用对象树组织起来,最主要的目的,就是为了在合适的时机,也就是窗口关闭的时候,把这些对象统一释放。

  QLabel *label = new QLabel(this);

代码中传入this 参数是为了将该对象挂在对象树上。通过 new 的方式在堆上建立对象,交给对象树管理。
而之前说的下面这种方式,是不推荐的

QLabel label(this);

这种在栈上创建的方式,可能存在“提前释放”的问题。运行查看效果。
在这里插入图片描述
在这里插入图片描述
窗口中没有设定好的 label 控件,因为被提前释放掉了。

6 关于 qDebug()的使用

qDebug() 的使用效果和 std::cout << std::endl 的效果一样,但是比后者好。
原因是 qDebug() 会自动处理编码方式,在 Qt 中如果用 cout 打印文字日志,可能会出现乱码,因为编码不同。

比如在析构函数中加入打印语句。
在这里插入图片描述
运行后,然后关闭窗口,自动调用析构函数,查看应用程序输出,会看到乱码
在这里插入图片描述
所以通常采用 qDebug() 的方式去打印日志。
在这里插入图片描述
在这里插入图片描述
qDebug() 还有一个优点就是可以统一打开和关闭,就能方便程序员调试。
在 .pro 文件加入这条代码即可

DEFINES += QT_NO_DEBUG_OUTPUT

在这里插入图片描述
需要 清除 然后重新构建才有效
在这里插入图片描述

7 使用其他方式创建一个 Hello World 程序(编辑框和按钮方式)

除了上面使用 label 标签的形式,还可以采用编辑框和按钮的方式。同样分为图形化界面方式和纯代码方式完成。

编辑框图形化方式
如下图所示,编辑框分为单行编辑框和多行编辑框,这里选择单行编辑框即可。拖动到编辑界面,然后输入文字。
在这里插入图片描述
运行查看效果。编辑框的内容运行后可以自己修改。
在这里插入图片描述
编辑框纯代码方式
纯代码方式和之前介绍过的大同小异。首先需要创建一个 QLineEdit 对象,然后设置文字。
在这里插入图片描述
运行查看效果。
在这里插入图片描述
按钮图形化方式
在 ui 界面找到 Push Button 然后拖动到图形化编辑界面输入文字
在这里插入图片描述

运行查看效果
在这里插入图片描述
这个按钮是可以点击的,但是点击了没有反应。如果想要点击了有反应,需要用到信号和槽机制,后面会讲。这里先简单说一下,本质就是给按钮的点击操作,关联一个处理函数,当用户点击的时候,就会执行这个处理函数。
这里需要用到 connect 函数
代码如图所示:
在这里插入图片描述

  • 第一个参数需要访问到 ui 文件中创建的控件,表示哪个控件发出的信号,在 Qt Designer 中创建一个控件的时候,此时就会给这个控件分配一个 objectName 属性,这个属性的值,要求在界面中是唯一的。qmake 在预处理.ui文件的时候,就会根据这里的 objectname 生成对应的C++代码。这个值可以在ui界面手动修改 在这里插入图片描述
    在这里插入图片描述
  • 第二个参数表示发出了个什么信号,这里 clicked 表示点击,当用户点击按钮时就会发出该信号
  • 第三个参数表示谁来处理该信号,将第二个参数的信号能够关联到对应的槽函数上,在此之前需要确认关联到哪个对象的槽函数,填写 this ,关联到 widget 对象的槽函数。
  • 第四个参数传一个具体的处理函数,这个函数需要我们自己去写处理方式。我们的处理方式是:点击一次按钮,文本在 Hello World!和Hello Qt! 之间来回切换。代码如下:
void Widget::handClick()
{
    if(ui->pushButton->text() == QString("Hello World!"))
    {
        ui->pushButton->setText("Hello Qt!");
    }
    else
    {
        ui->pushButton->setText("Hello World!");
    }
}

在这里插入图片描述

记得先在头文件声明该函数。声明以后,快速生成函数定义快捷键:alt + 回车
会自动在 .cpp 文件帮我们处理好一些代码

在这里插入图片描述
运行查看效果
在这里插入图片描述
点击一次按钮

在这里插入图片描述
文本内容改变了,再点击一次
在这里插入图片描述
点击一次按钮就会在两个文本内容之间来回切换,成功实现我们想要的功能。

纯代码方式实现按钮版 Hello World 程序
纯代码方式实现,首先需要我们自己 new 一个 button 对象,为了能让其他成员函数能够访问该变量,需要将该对象定义为成员变量。

在这里插入图片描述

具体代码如下,功能如上面所述
在这里插入图片描述
运行查看效果
在这里插入图片描述

点击后
在这里插入图片描述
再次点击
在这里插入图片描述
成功实现。

实际开发以纯代码为主还是图形化界面为主?
这两者都很重要,难分主次。如果当前程序界面,界面内容是比较固定的,此时就会以图形化界面的方式来构造界面。如果当前界面,经常要动态变化,此时就会以代码的方式来构造界面。这两种方式,哪种方便就用哪种,而且这两种方式可以配合使用。

8 关于 Qt 中的命名规范 / 快捷键 / 查询文档

命名规范

  • 类名:首字母大写,单词和单词之间首字母大写,也就是大驼峰命名法。如:QPushButton
  • 函数名:首字母小写,单词和单词之间首字母大写,也就是小驼峰命名法。如:setText

快捷键

  • 注释: ctrl+ /
  • 运行: ctrl+ R
  • 编译: cttrl+ B
  • 字体缩放: ctrl +鼠标滑轮
  • 查找: ctrl + F
  • 整行移动: ctrl+shift+ ↑/↓
  • 帮助文档: F1
  • 自动对齐: ctrl+ i;
  • 同名之间的.h和.cpp的切换: F4
  • 生成函数声明的对应定义: alt + enter

使用帮助文档
打开文档一共有三种方法

  • 光标放到要查询的类名/方法名上,直接按F1
  • Qt Creator左侧边栏中直接用鼠标单击"帮助"按钮
  • 找到Qt Creator的安装路径,在"bin"文件夹下找到assistant.exe,双击打开;

9 Qt 窗口坐标系

坐标体系:以左上角为原点(0,0),X向右增加,Y向下增加
在这里插入图片描述
对于嵌套窗口,其坐标是相对于父窗口来说的。
在这里插入图片描述
比如图中 QPushButton 的父窗口就是 QWidget,原点就是QWidget 左上角。QWidget没有父元素,相当于父元素就是整个显示器,原点就是显示器左上角。

上面我们提到过,以纯代码的方式创建一个这样一个程序,按钮会默认在左上角,也就是原点(0,0)处,这里的位置是可以改变的。
在这里插入图片描述
需要用到 move 函数
在这里插入图片描述
把这个按钮相对于原点水平移动200像素,垂直移动300像素,效果如下
在这里插入图片描述
在这里插入图片描述
还可以设置窗口弹出时的位置。设置为弹出为显示器的原点处
在这里插入图片描述
查看效果,在窗口弹出后位置在显示器左上角。
在这里插入图片描述

以上是关于 Qt 的一些基础操作,下篇文章是关于 Qt 的信号和槽机制。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云智能集团副总裁安筱鹏:企业数字化的终局是什么?

以下文章来源于数字化企业 &#xff0c;作者安筱鹏博士 回答数字化终局追问的起点是&#xff0c;企业需要重新定义我是谁。成为有竞争力的行业领导厂商&#xff0c;你应当成为一个客户运营商&#xff0c;即能够实时洞察、实时满足客户需求&#xff0c;追求极致的客户体验。而要…

使用 Docker 部署扫雷小游戏

1&#xff09;源码 介绍&#xff1a;扫雷游戏是一款经典的单人益智游戏&#xff0c;旨在通过揭示方块和避开地雷来展示玩家的逻辑思维和推理能力。 源码&#xff1a;saolei.zip 个人文件站&#xff1a;https://share.wuhanjiayou.cn/ 2&#xff09;部署 2.1&#xff09;安装…

SpringBoot中处理校验逻辑的两种方式:Hibernate Validator+全局异常处理

最近正在开发一个知识库学习网站编程喵&#x1f431;&#xff0c;需要对请求参数进行校验&#xff0c;比如说非空啊、长度限制啊等等&#xff0c;可选的解决方案有两种&#xff1a; 一种是用 Hibernate Validator 来处理一种是用全局异常来处理 两种方式&#xff0c;我们一一…

基于EdgeWorkers的边缘应用如何进行单元测试?

随着各行各业数字化转型的持续深入&#xff0c;越来越多企业开始选择将一些应用程序放在距离最终用户更近的边缘位置来运行&#xff0c;借此降低延迟&#xff0c;提高应用程序响应速度&#xff0c;打造更出色的用户体验。 相比传统集中部署和运行的方式&#xff0c;这种边缘应…

websocket编写聊天室

【黑马程序员】WebSocket打造在线聊天室【配套资料源码】 总时长 02:45:00 共6P 此文章包含第1p-第p6的内容 简介 温馨提示&#xff1a;现在都是第三方支持聊天&#xff0c;如极光&#xff0c;学这个用于自己项目完全没问题&#xff0c;大项目不建议使用 需求分析 代码

Vue学习总结

声明&#xff1a;本文来源于黑马程序员PDF讲义 双向绑定&#xff1a; 修改表单项标签&#xff0c;发现vue对象data中的数据也发生了变化 双向绑定的作用&#xff1a;可以获取表单的数据的值&#xff0c;然后提交给服务器 事件绑定 v-on: 用来给html标签绑定事件的。需要注意…

了解 Redis Channel:消息传递机制、发布与订阅,以及打造简易聊天室的实战应用。

文章目录 1. Redis Channel 是什么2. Redis-Cli 中演示使用3. 利用 Channel 打造一个简易的聊天室参考文献 1. Redis Channel 是什么 Redis Channel 是一种消息传递机制&#xff0c;允许发布者向特定频道发布消息&#xff0c;而订阅者则通过订阅频道实时接收消息。 Redis Cha…

LRU 缓存置换策略:提升系统效率的秘密武器(下)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

小程序定制开发前,应该考虑些什么?

引言 在移动互联网时代&#xff0c;小程序已经成为许多企业和个人推广业务、提供服务的理想平台。然而&#xff0c;在进行小程序定制开发之前&#xff0c;开发者和业务方需要细致入微地考虑一系列关键因素&#xff0c;以确保最终的小程序既能满足用户需求&#xff0c;又能够顺…

Linux第40步_移植ST公司uboot的第1步_创建配置文件_设备树_修改电源管理和sdmmc节点

ST公司uboot移植分两步走&#xff1a; 第1步&#xff1a;完成“创建配置文件&#xff0c;设备树&#xff0c;修改电源管理和sdmmc节点&#xff0c;以及shell脚本和编译”。 第2步“完成”修改网络驱动、USB OTG设备树和LCD驱动&#xff0c;以及编译和烧写测试“。 移植太复杂…

牛客——中位数图(连续子数组和二维前缀和)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 给出1~n的一个排列&#xff0c;统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后&#xff0c;位于中间的数。 输入描述: 第一行为两个正…

Mysql基础篇笔记

数据表 链接&#xff1a;https://pan.baidu.com/s/1dPitBSxLznogqsbfwmih2Q 提取码&#xff1a;b0rp --来自百度网盘超级会员V5的分享 sql的执行顺序 根据顺序 也就是说 select后面的字段别名 只能在order by中使用 mysql不支持sql92的外连接 mysql不支持满外连接 可以…

springBoot+Vue汽车销售源码

源码描述: 汽车销售管理系统源码基于spring boot以及Vue开发。 针对汽车销售提供客户信息、车辆信息、订单信息、销售人员管理、 财务报表等功能&#xff0c;提供经理和销售两种角色进行管理。 技术架构&#xff1a; idea(推荐)、jdk1.8、mysql5.X(不能为8驱动不匹配)、ma…

Docker多节点部署Minio分布式文件系统并测试

文章目录 一、前提准备二、文件配置1. .env2. env/minio.env3. docker-compose-minio.yml 三、测试四、Java测试1. 引入依赖2. 增删改 一、前提准备 准备如下文件夹和文件 ./ ├── docker-compose-minio.yml ├── .env ├── env │ ├── minio.env ├── minio │…

使用 Paimon + StarRocks 极速批流一体湖仓分析

摘要&#xff1a;本文整理自阿里云智能高级开发工程师王日宇&#xff0c;在 Flink Forward Asia 2023 流式湖仓&#xff08;二&#xff09;专场的分享。本篇内容主要分为以下四部分&#xff1a; StarRocksPaimon 湖仓分析的发展历程使用 StarRocksPaimon 进行湖仓分析主要场景和…

力扣hot100 跳跃游戏 贪心

Problem: 55. 跳跃游戏 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 参考 挨着跳&#xff0c;记录最远能到达的地方 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) Code class Solution {public boolean canJump(int[] nums)…

利用onenet mqtt协议 ,ESP32上传温湿度数据流成功(arduinoIDE)

目标&#xff1a;开发esp32通过onenet平台远程控制LED、继电器等其它设备&#xff0c;并利用onenet可视化功能开发出一个简单的控制页面。 原以为能够快速完成&#xff0c;没想到接入mqtt协议、数据流上传、可视化按键都不同程度遇到了问题&#xff0c;还好经过一番查找和修改…

docker安装elasticsearch+kibana

目录 1.安装es 2.安装kibana 3.kibana监控es 1.安装es 拉取镜像 docker pull elasticsearch:7.6.1 创建存放配置文件、数据、插件的各个文件夹 mkdir -p /home/docker/elasticsearch/config mkdir -p /home/docker/elasticsearch/data mkdir -p /home/docker/elasticsearch…

【每日一题】 2024年1月汇编

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 【1.4】2397.被列覆盖的最多行数 2397. 被列覆盖的最多行数https://leetcode.cn/problems/maximum-rows-covered-by-columns/ 这…

Websocket基本用法

1.Websocket介绍 WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并进行双向数据传输。 应用场景&#xff1a; 视频弹幕网页聊天体育实况更新股票基金…