[Qt]常用控件介绍-多元素控件-QListWidget、QTableWidget、QQTreeWidget
目录
1.多元素控件介绍
2.ListWidget控件
属性
核心方法
核心信号
细节
Demo:编辑日程
3.TableWidget控件
核心方法
QTableWidgetItem核心信号
QTableWidgetItem核心方法
细节
Demo:编辑学生信息
4.TreeWidget控件
核心方法
核心信号
QTreeWidgetItem核心方法
细节
控件使用案例
1.多元素控件介绍
Qt中为我们提供的多元素控件有QListWidget、QListView、QTableWidget、QTableView、QTreeWidget、QTreeView六个。那么我可以发现,他们是两两一组,xxxWidget和xxxView两种形式,那么他俩之间有什么区别呢?
xxxView是更底层的实现,xxxWidget是基于xxxView封装而来的,用户使用起来比较容易。此处的xxxView是MVC结构的实现,MVC是软件开发中非常经典的软件结构组织形式。
M:model数据 V:view视图(界面) C:controller控制器,数据和视图之间的业务流程。
对于xxxView来说只是负责了上述的视图,不负责数据如何表示,以及数据和视图之间如何交互,如果用户使用xxxView的话,就需要自己创建model对象,和视图关联起来。而QxxxWidget则是QxxxView的子类,对Model进行了封装,不需要我们自己去创建model对象,直接向xxxWidget中添加数据即可。
2.ListWidget控件
该控件表示的是一个纵向的列表
属性
| 属性 | 说明 |
| currentRow | 当前被选中的是第几行 |
| count | 一共有多少行 |
| sortingEnabled | 是否允许排序 |
| isWrapping | 是否允许换行 |
| itemAlignment | 元素的对齐方式 |
| selectRectVisible | 被选中的元素矩形是否可见 |
| spacing | 元素之间的间隔 |
核心方法
| 方法 | 说明 |
| addItem(QString& label) addItem(QListWidgetItem* item) | 列表中添加元素 |
| currentItem() | 返回当前选中的QListWidgetItem* 对象元素 |
| setCurrentItem(QListWidgetItem* item) | 设置选中哪一个元素 |
| setCurrentRow(int row) | 设置选中第几行的元素 |
| insertItem(const QString& label, int row) insertItem(QListWidgetItem* item, int row) | 第一个是添加到最后一行,这个方法是插入到第row行 |
| item(int row) | 获取第row行的QListWidgetItem* 对象元素 |
| takeItem(int row) | 删除指定行的元素,返回删除的元素对象 |
核心信号
| 信号 | 说明 |
| currentItemChanged(QListWidgetItem* current, QListWidgetItem* old) | 选中不同元素的时候会触发,参数是当前选中的元素和之前选中的元素 |
| currentRowChanged(int) | 选中不同元素的时候触发,参数是当前选中元素的行数 |
| itemClicked(QListWidgetItem* item) | 点击某个元素的时候触发 |
| itemDoubleClicked(QListWidgetItem* item) | 双击某个元素的时候触发 |
| itemEntered(QListWidgetItem* item) | 鼠标进入元素范围触发 |
细节
- 对于一个QListWidget控件,内部的元素是一个个的QListWidgetItem组成的。本质上改类的内部就是一个文本+图标构成,所以QListWidgetItem内部提供了很多操作文本和图标的方法。例如:设置字体、设置图标、设置对齐方式等内容。
Demo:编辑日程
该demo中有QListWidget控件来显示日程列表,提供了两个按钮去进行操作日程表的添加和删除的操作,为添加按钮设置一个QLineEdit控件,在增加的时候,获取QLineEdit控件输入的内容,然后添加到日程表当中。删除的时候,获取到选中的是第几行,然后进行调用方法删除。
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//初始化日程表//以字符串形式添加元素ui->listWidget->addItem("健身");ui->listWidget->addItem("学习");ui->listWidget->addItem("打球");//用对象的形式添加元素QListWidgetItem* item = new QListWidgetItem("玩游戏");ui->listWidget->addItem(item);//匿名对象添加元素ui->listWidget->addItem(new QListWidgetItem("吃饭"));
}Widget::~Widget()
{delete ui;
}//增加日程
void Widget::on_pushButton_add_clicked()
{//获取lineEdit单行输入框中的内容const QString str = ui->lineEdit->text();//设置到listWidegt控件中ui->listWidget->addItem(new QListWidgetItem(str));
}//删除日程
void Widget::on_pushButton_del_clicked()
{//获取到被选中的元素的行号int row = ui->listWidget->currentRow();if(row < 0)return;//删除ui->listWidget->takeItem(row);
}

3.TableWidget控件
该控件表示的是一个表格控件,包括横向和纵向两个方向由若干行若干列组成,每一个表格都是由一个QTableWidgetItem对象构成。
核心方法
| 方法 | 说明 |
| item(int row, int column) | 根据行数和列数获取指定的QTableWidgetItem*对象 |
| setItem(int row, int column, QTbleWidget*) | 根据行数列数设置表格中的元素 |
| currentItem() | 返回被选中的表格QTableWidgetItem对象 |
| currentRow() | 返回被选中的是第几行 |
| currentColumn() | 返回被选中的是第几列 |
| row(QTableWidgetItem*) | 获取指定item是第几行 |
| column(QTableWidgetItem*) | 获取指定item是第几列 |
| rowCount() | 获取行数 |
| columnCount() | 获取列数 |
| insertRow(int row) | 在第row行插入 |
| insertColumn(int column) | 在第column列插入 |
| removeRow(int row) | 删除第row行 |
| removeColumn(int column) | 删除第column列 |
| setHorizontalHeaderItem(int column, QTableWidget*) | 设置指定列的表头 |
| setVericalHeaderItem(int row, QTableWidget*) | 设置指定行的表头 |
QTableWidgetItem核心信号
| 信号 | 说明 |
| cellClicked(int row, int column) | 点击单元格的时候触发 |
| cellDoubleClicked(int row, int column) | 双击单元格的时候触发 |
| cellEntered(int row, int column) | 鼠标进入单元格的时候触发 |
| currentCellChanged(int row, int column, int prevuiousRow, int previousColumn) | 选中不同的单元格的时候触发 |
QTableWidgetItem核心方法
| 方法 | 说明 |
| row() | 获取当前在第几行 |
| column() | 获取当前在第几列 |
| setText(const QString&) | 设置文本 |
| setTextAlignment(int) | 设置文本呢对齐方式 |
| setlcon(const QIcon&) | 设置图标 |
| setSelected(bool) | 设置被选中 |
| setSizeHints(const QSize&) | 设置尺寸 |
| setFont(onst QFont&) | 设置字体 |
细节
- 对于单元格默认程序运行之后是可以编写文本内容的,如果我们不想让用户去修改单元格中的内容的话,需要设置:
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
Demo:编辑学生信息
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->lineEdit->setPlaceholderText("请输入新增的列名称");//创建3行3列ui->tableWidget->insertRow(0);ui->tableWidget->insertRow(1);ui->tableWidget->insertRow(2);ui->tableWidget->insertColumn(0);ui->tableWidget->insertColumn(1);ui->tableWidget->insertColumn(2);//设置每一列的名称ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("学号"));ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("姓名"));ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("电话号"));//添加初始数据ui->tableWidget->setItem(0, 0, new QTableWidgetItem("2000"));ui->tableWidget->setItem(0, 1, new QTableWidgetItem("zhangsan"));ui->tableWidget->setItem(0, 2, new QTableWidgetItem("000-0000-0000"));ui->tableWidget->setItem(1, 0, new QTableWidgetItem("2001"));ui->tableWidget->setItem(1, 1, new QTableWidgetItem("lisi"));ui->tableWidget->setItem(1, 2, new QTableWidgetItem("123-4567-8901"));ui->tableWidget->setItem(2, 0, new QTableWidgetItem("2002"));ui->tableWidget->setItem(2, 1, new QTableWidgetItem("wangwu"));ui->tableWidget->setItem(2, 2, new QTableWidgetItem("342-4483-1992"));
}Widget::~Widget()
{delete ui;
}//增加一行
void Widget::on_pushButton_add_row_clicked()
{//获取行数int row_count = ui->tableWidget->rowCount();//增加一行ui->tableWidget->insertRow(row_count);
}//增加一列
void Widget::on_pushButton_column_add_clicked()
{//获取列数int column_count = ui->tableWidget->columnCount();//获取新增列的表头const QString str = ui->lineEdit->text();//如果为空的话,就不添加了if(str.isEmpty())return;//增加一列ui->tableWidget->insertColumn(column_count);//设置表头ui->tableWidget->setHorizontalHeaderItem(column_count, new QTableWidgetItem(str));
}//删除选中行
void Widget::on_pushButton_row_del_clicked()
{//获取当前选中的行int row = ui->tableWidget->currentRow();//删除ui->tableWidget->removeRow(row);
}//删除选中列
void Widget::on_pushButton_column_del_clicked()
{//获取当前选中的列int column = ui->tableWidget->currentColumn();//删除ui->tableWidget->removeColumn(column);
}


4.TreeWidget控件
该控件表示的是一个树形的控件,里面的每一元素都是一个QTreeWidgetItem对象,该对象内部可以包含多个文本和图标,每一个文本或者图标是一列。可以给QTreeWidget设置顶层节点,顶层节点可以是多个,然后再给顶层节点添加子节点,从而构成了树形结构。
核心方法
| 方法 | 说明 |
| clear() | 清空所有子节点 |
| addTopLevelItem(QTreeWidegtItem* item) | 新增顶层节点 |
| topLevelItem(int index) | 获取指定下标的顶层节点 |
| topLevelItemCount() | 获取顶层节点的个数 |
| indexOfTopLevelItem(QTreeWidgetItem* item) | 查询指定节点在顶层节点中的下标 |
| takeTopLevelItem(int index) | 删除指定的顶层节点,返回删除的QTreeWidgetItem*元素对象 |
| currentItem() | 获取到当前选中的节点,返回QTreeWidgetItem元素怒对象 |
| setCurrentItem(QTreeWidgetItem* item) | 选中指定节点 |
| setExpanded(bool) | 展开/关闭节点 |
| setHeaderLabel(const QString& text) | 设置TreeWidget的header名称 |
核心信号
| 信号 | 说明 |
| currentChanged(QTreeWidgetItem* current, QTreeWidgetItem* old) | 切换园中元素的时候触发 |
| itemClicked(QTreeWidgetItem* item, int col) | 点击元素的时候触发 |
| itemDoubleClicked(QTreeWidgetItem* item, int col) | 双击元素的时候触发 |
| itemEntered(QTreeWidgetItem* item, int col) | 鼠标进入元素范围的时候触发 |
| itemExpanded(QTreeWidgetItem* item) | 元素被展开的时候触发 |
| itemCollapsend(QTreeWidgetItem* item) | 元素被折叠的时候触发 |
QTreeWidgetItem核心方法
| 方法 | 说明 |
| addChild(QTreeWidgetItem* child) | 新增子节点 |
| childCount() | 获取子节点个数 |
| child(int index) | 获取指定下标的子节点,返回QTreeWidgetItem对象指针 |
| takeChild(int index) | 删除指定下标的子节点 |
| removeChild(QTreeWidgetItem* child) | 删除对应的元素 |
| parent() | 获取该元素的父节点 |
细节
- 在添加顶层节点或者子节点传递QTreeWidgetItem对象的时候,在设置文本的时候,需要传递两个参数,第一个表示第n列,第二个参数是文本内容,因为QTreeWidgetItem对象可以有很多列,所以需要传递设置的文本是第几列。但是如果设置多列的话,那么我们对应的设置控件名称的时候就需要调用setHeaderLabels设置多个列名称了。这样的话才能显示出来我们设置的多列元素。
- 对于删除的时候来说,删除的时候需要调用他的父节点的删除函数,所以说要考虑删除元素的是不是顶层元素,因为顶层元素没有父元素,所以需要调用控件的删除函数去删除顶层元素,如果不是的话,调用父节点的删除函数即可。
- 如果删除的节点下面还有子节点的话,也会一起删除的。
控件使用案例
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置根节点的名称ui->treeWidget->setHeaderLabel("食物");//添加顶层节点QTreeWidgetItem* item1 = new QTreeWidgetItem();item1->setText(0, "蔬菜");ui->treeWidget->addTopLevelItem(item1);QTreeWidgetItem* item2 = new QTreeWidgetItem();item2->setText(0, "水果");ui->treeWidget->addTopLevelItem(item2);
}Widget::~Widget()
{delete ui;
}//添加顶层元素
void Widget::on_pushButton_topItem_add_clicked()
{//获取输入框的文本内容const QString& str = ui->lineEdit->text();if(str.isEmpty())return;//设置到顶层节点QTreeWidgetItem* item = new QTreeWidgetItem();item->setText(0, str);ui->treeWidget->addTopLevelItem(item);
}//添加到选中元素
void Widget::on_pushButton_item_add_clicked()
{//获取输入框中的本文内容const QString& str = ui->lineEdit->text();if(str.isEmpty())return;//获取选中元素QTreeWidgetItem* item = ui->treeWidget->currentItem();if(item == nullptr)return;//添加节点QTreeWidgetItem* new_item = new QTreeWidgetItem();new_item->setText(0, str);item->addChild(new_item);//设置展开父节点item->setExpanded(true);
}//删除选中元素
void Widget::on_pushButton_item_del_clicked()
{//获取选中元素QTreeWidgetItem* item = ui->treeWidget->currentItem();if(item == nullptr)return;//获取父元素QTreeWidgetItem* parent = item->parent();//如果是顶层节点的话if(parent == nullptr){//获取下标int index = ui->treeWidget->indexOfTopLevelItem(item);//删除ui->treeWidget->takeTopLevelItem(index);}//非顶层节点else{parent->removeChild(item);}
}


相关文章:
[Qt]常用控件介绍-多元素控件-QListWidget、QTableWidget、QQTreeWidget
目录 1.多元素控件介绍 2.ListWidget控件 属性 核心方法 核心信号 细节 Demo:编辑日程 3.TableWidget控件 核心方法 QTableWidgetItem核心信号 QTableWidgetItem核心方法 细节 Demo:编辑学生信息 4.TreeWidget控件 核心方法 核心信号…...
深入Android架构(从线程到AIDL)_32 JNI架构原理_Java与C的对接05
1、EIT造形观点 基于熟悉的EIT造形,很容易理解重要的架构设计决策议题。 前言 2、混合式EIT造形 一般EIT造形是同语言的。也就是<E>、 <I>和<T>都使用同一种语言撰写的,例如上述的Java、 C/C等。于此,将介绍一个EIT造…...
【gRPC】clientPool 客户端连接池简单实现与go案例
什么是 gRPC 客户端连接池? 在 gRPC 中,创建和维护一个到服务器的连接是非常消耗资源的(比如 TCP 连接建立和 TLS 握手)。 而在高并发场景下,如果每次请求都创建新的连接,不仅会导致性能下降,还…...
Android 15应用适配指南:所有应用的行为变更
Android系统版本适配,一直是影响App上架Google Play非常重要的因素。 当前Google Play政策规定 新应用和应用更新 必须以 Android 14(API 级别 34)为目标平台,才能提交到Google Play。现有应用 必须以 Android 13(AP…...
24-25-1-单片机开卷部分习题和评分标准
依据相关规定试卷必须按评分标准进行批改。 给分一定是宽松的,能给分一定给,如有疑问也可以向学院教务办申请查卷。 一部分学生期末成绩由于紧张或其他原因导致分数过低,也是非常非常遗憾的。 个人也是非常抱歉的。 开卷考试 简答题 第一…...
STM32第6章、WWDG
一、简介 WWDG:全称Window watchdog,即窗口看门狗,本质上是一个能产生系统复位信号和提前唤醒中断的计数器。 特性: 是一个递减计数器。 看门狗被激活后, 当递减计数器值从 0x40减到0x3F时会产生复位(即T6位…...
汽车免拆诊断案例 | 2007 款法拉利 599 GTB 车发动机故障灯异常点亮
故障现象 一辆2007款法拉利599 GTB车,搭载6.0 L V12自然吸气发动机(图1),累计行驶里程约为6万km。该车因发动机故障灯异常点亮进厂检修。 图1 发动机的布置 故障诊断 接车后试车,发动机怠速轻微抖动,…...
C语言-数据结构-队列
目录 1.队列的特点 2.队列的实现 2.1.初始化队列 2.2.入队列 2.2.1.入空队列 2.2.2.入非空队列 2.3.出队列 2.4.销毁队列 2.5.完整代码 3.实际应用 1.队列的特点 队列是一种常见的数据结构,它遵循先进先出(FIFO, First In First Out)…...
STL之VectorMapList针对erase方法踩坑笔记
前沿 如下总结的三种容器,开头都会涉及当前容器的特点,再者就本次针对erase方法的使用避坑总结。 一.Vector vector关联关联容器,存储内存是连续,且特点支持快速访问,但是插入和删除效率比较地(需要找查找和移动)。另…...
梯度下降法为什么要提前停止
什么是提前停止(Early Stopping)? 提前停止是一种正则化技术,用于在训练机器学习模型(特别是神经网络)时防止过拟合。它的核心思想是通过监控模型在验证集上的性能,在性能开始恶化之前停止训练…...
【vue3项目使用 animate动画效果】
vue3项目使用 animate动画效果 前言一、下载或安装npm 安装 二、引入组件三、复制使用四、完整使用演示总结 前言 提示:干货篇,不废话,点赞收藏,用到会后好找藕~ 点击这里,直接看官网哦 👉 官网地址&#…...
1.1.1 C语言常用的一些函数(持续更新)
总框架见(0. 总框架-CSDN博客) (1)socket (a)分配fd;(b)分配tcp控制块(tcb) int socket(int domain, int type, int protocol);AF_INET IPv4 Internet protocols ip(7)AF_INET6 IP…...
李宏毅机器学习课程笔记03 | 类神经网络优化技巧
文章目录 类神经网络优化技巧局部最小值local minima 与 鞍点saddle pointSaddle Point 的情况更常见 Tips for training:Batch and MomentumSmall Batch vs Large Batch回顾:optimization优化 找到参数使L最小问题:为什么要用Batchÿ…...
简洁明快git入门及github实践教程
简洁明快git入门及github快速入门实践教程 前言git知识概要:一:什么是 Git?二:安装 Git三:配置 Git配置git的用户名和邮箱地址创建仓库 四:Git实践五:远程仓库操作(基于git命令使用G…...
Python使用socket实现简易的http服务
在接触的一些项目中,有时为了方便可视化一些服务状态(请求数很少),那么很容易想到使用http服务来实现。但开源的web后端框架,例如flask,fastapi,django等略显沉重,且使用这些框架会有…...
【Hive】海量数据存储利器之Hive库原理初探
文章目录 一、背景二、数据仓库2.1 数据仓库概念2.2 数据仓库分层架构2.2.1 数仓分层思想和标准2.2.2 阿里巴巴数仓3层架构2.2.3 ETL和ELT2.2.4 为什么要分层 2.3 数据仓库特征2.3.1 面向主题性2.3.2 集成性2.3.3 非易失性2.3.4 时变性 三、hive库3.1 hive概述3.2 hive架构3.2.…...
linux系统监视(centos 7)
一.系统监视 1.安装iostat,sar,sysstat(默认没有,安装过可以跳跃) iostat 和 sar: 同样,iostat 和 sar 是 sysstat 软件包的一部分。使用以下命令安装:sudo yum install sysstat解释…...
Blazor中Syncfusion图像编辑器组件使用方法
Blazor中Syncfusion图像编辑器组件是一个功能丰富的图像处理工具,支持多种编辑、操作和交互方式,帮助用户高效处理图像。以下是该组件的主要功能总结: 主要功能: 图像打开与保存 图像编辑器允许用户通过简单的点击操作打开支持的…...
电动汽车V2G技术Matlab/Simulink仿真模型
今天给大家更新关于V2G技术的仿真,不是研究这个方向的,可能会对这个名称比较陌生,那么,什么是“V2G”? V2G全称:Vehicle-to-Grid,即车网互动,利用电动汽车特有的储能功能与电网“双…...
C++中的unordered_set和unordered_map的模拟实现
一、封装基本结构 与map和set的封装过程很想,unordered_set和unordered_map也需要用MapKeyOfT和SetKeyOfT创建哈希表类型,借此获取对应的key值来使用; 因此,在哈希表中也一样需要用参数class T来替代set中的key和map中的pair<…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
Java多线程实现之Runnable接口深度解析
Java多线程实现之Runnable接口深度解析 一、Runnable接口概述1.1 接口定义1.2 与Thread类的关系1.3 使用Runnable接口的优势 二、Runnable接口的基本实现方式2.1 传统方式实现Runnable接口2.2 使用匿名内部类实现Runnable接口2.3 使用Lambda表达式实现Runnable接口 三、Runnabl…...
第22节 Node.js JXcore 打包
Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...
SOC-ESP32S3部分:30-I2S音频-麦克风扬声器驱动
飞书文档https://x509p6c8to.feishu.cn/wiki/SKZzwIRH3i7lsckUOlzcuJsdnVf I2S简介 I2S(Inter-Integrated Circuit Sound)是一种用于传输数字音频数据的通信协议,广泛应用于音频设备中。 ESP32-S3 包含 2 个 I2S 外设,通过配置…...
