Qt:读取已有数据的Excel文档,并将数据显示在通过QTableWidget绘制的表格中,之后将显示的数据保存成excel格式进行输出(包括表头等内容)

读取已有数据的Excel文档,并将数据显示在通过QTableWidget绘制的表格中,之后将显示的数据保存成excel格式进行输出(包括表头等内容)


  • UI展示及功能简介


  • 读取
//于Mainwindow中,on_read_clicked属于Pushbotton摁键的槽函数
void MainWindow::on_read_clicked()
{execel_read();//调用读取类方法,execel_read的具体内容见下文
}

 

选择【设置好内容的Excel文档】进行读取

结束后会显示读取完成。

上图为模板1.xlsx中的内容


  • 生成报表

//于Mainwindow中,on_pushButton_clicked属于Pushbotton摁键的槽函数void MainWindow::on_pushButton_clicked()
{dom->datasend(exceldata);//在MainWindow中调用dialog的类方法datasend()//dom是属于dialog类的对象,需要在MainWindow中包含dialog头文件,之后定义指针对象dom,并分配空间//具体操作如下***处QMessageBox::warning(this,tr("生成波表情况:"),tr("报表已经生成!"),QMessageBox::Yes);
}
*********************************
//MainWindow中包含dialog的头文件#include"dialog.h"//MainWindow.h中声明属于dialog类的对象class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();............
private slots:............private:............Dialog *dom;//命名还是个大问题,保留dialog,不能在前后加数字
};
//MainWindow.cpp中分配dom指针对象空间
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{.............dom = new Dialog(this);.............
}
*********************************

 

点击后会显示报表已经生成。


  • 查看报表

void MainWindow::on_sheet_clicked()
//显示部分,关于TableWidget已经于生成报表部分绘制完成,如有需要,生成报表和查看报表可以统一为一个部分
{dom->exec();//保持窗口
}

 

将会显示生成报表的结果。


  • 保存

将生成的报表保存成Excel文档

保存会出现提示窗口,选择是否要打开。选择是

void MainWindow::on_pushButton_2_clicked()
{saveas();
}

 


以上情况不具有普世应用的意义,如何应用需要根据工程中的具体内容而定,因为程序内部未对从excel中读取到的数据进行处理,所以输出的报表中,数据和读取时选择的【模板1.xlsx】数据一样。

在实际工程中,会出现对大量excel数据进行读取(录入),并进行数据处理,之后输出显示成表格(如查看报表功能),必要的话,有可能需要将显示表格中的内容进行保存。

本文的内容主要是省去了数据处理的部分,概括性的对上述复杂问题进行一个精炼。


  • 程序介绍

读取excel

void MainWindow::execel_read()
{QString path = QFileDialog::getOpenFileName(this,"open","../","execl(*.xlsx)");//指定父对象(this),“open”具体操作,打开,“../”默认,之后可以添加要打开文件的格式if(path.isEmpty()==false){//文件对象QFile file(path);//打开文件,默认为utf8变量,bool flag = file.open(QIODevice::ReadOnly);if(flag == true)//打开成功{QAxObject *excel = new QAxObject(this);//建立excel操作对象excel->setControl("Excel.Application");//连接Excel控件excel->setProperty("Visible", false);//不显示窗体看效果excel->setProperty("DisplayAlerts", false);//不显示警告看效果/*********获取COM文件的一种方式************/QAxObject *workbooks = excel->querySubObject("WorkBooks");//获取工作簿(excel文件)集合workbooks->dynamicCall("Open(const QString&)", path);//path至关重要,获取excel文件的路径//打开一个excel文件QAxObject *workbook = excel->querySubObject("ActiveWorkBook");QAxObject *worksheet = workbook->querySubObject("WorkSheets(int)",1);//访问excel中的工作表中第一个单元格QAxObject *usedRange = worksheet->querySubObject("UsedRange");//sheet的范围/*********获取COM文件的一种方式************///获取打开excel的起始行数和列数和总共的行数和列数int intRowStart = usedRange->property("Row").toInt();//起始行数int intColStart = usedRange->property("Column").toInt(); //起始列数QAxObject *rows, *columns;rows = usedRange->querySubObject("Rows");//行columns = usedRange->querySubObject("Columns");//列int intRow = rows->property("Count").toInt();//行数int intCol = columns->property("Count").toInt();//列数//起始行列号qDebug()<<intRowStart;qDebug()<<intColStart;//行数和列数qDebug()<<intRow;qDebug()<<intCol;int a,b;a=intRow-intRowStart+1,b=intCol-intColStart+1;QByteArray text[a][b];int coerow=0,coecol=0;for (int i = intRowStart; i < intRowStart + intRow; i++,coerow++){coecol=0;//务必是要恢复初值的for (int j = intColStart; j < intColStart + intCol; j++,coecol++){cell = excel->querySubObject("Cells(Int, Int)", i, j );QVariant cellValue = cell->dynamicCall("value");text[coerow][coecol]=cellValue.toByteArray();//QVariant转换为QByteArrayexceldata[coerow][coecol]=QString(text[coerow][coecol]);//QByteArray转换为QString}}workbook->dynamicCall( "Close(Boolean)", false );excel->dynamicCall( "Quit(void)" );delete excel;QMessageBox::warning(this,tr("读取情况"),tr("读取完成!"),QMessageBox::Yes);}file.close();}}

QTableWidget绘制表格

void Dialog::putoutsend()
{table->setRowCount(6);    //设置行数table->setColumnCount(4); //设置列数table->move(20,20);//QTableWidget *tableWidget = new QTableWidget(10,5); //这个可以代替上两行table->setWindowTitle("QTableWidget & Item");table->resize(550, 400);setFixedSize(580,500);//固定窗口的大小//设置表格的表头QStringList header;header<<"1"<<"2"<<"3"<<"4";table->setHorizontalHeaderLabels(header);//设置表头(横)QStringList header2;header2<<"abc"<<"jmc"<<"Month"<<"Description"<<"Month"<<"Description";table->setVerticalHeaderLabels(header2);//设置表头(竖)//设置行列的宽和高/*for(int i = 0;i<10;++i){Table_one->setRowHeight(i,40);}for(int i = 0;i<4;++i){Table_one->setColumnWidth(i,65);}*///设置表格内容(横坐标,纵坐标,QTableWidgetItem("输入文本"))//如果有要输入的需要,就是把处理过后的数据输出到报表中,即可使用这个功能//显示阶段for(int i=0;i<6;i++){for(int j=0;j<4;j++){table->setItem(i,j,new QTableWidgetItem(exsheet[i][j]));//注意,exsheet为QString类型的数组,只有QString类型才能显示,如果是double等数值类型,请使用QString::number转换类型qDebug()<<exsheet[i][j];}}table->setEditTriggers(QAbstractItemView::NoEditTriggers);//只读模式//表列随着表格变化而自适应变化table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//表行随着表格变化而自适应变化table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);//将widget设置为窗口的中心控件//setCentralWidget(widget);//将读到的内容存在tableDate中arow=table->rowCount(),acol=table->columnCount();//QString tabeDate[table->rowCount()][table->columnCount()];//读取行数和列数for(int i=0; i<arow; i++){for(int j=0; j<acol; j++){senddata[i][j] = table->item(i, j)->text();//将数据读入一个全局变量中,方便之后进行保存操作}}table->show();
}

行列高宽的设置

自定义:

    for(int i = 0;i<10;++i){Table_one->setRowHeight(i,40);}for(int i = 0;i<4;++i){Table_one->setColumnWidth(i,65);}

其他类型:

    Table_one->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);Table_one->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);

其中的参数:ResizeMode mode的具体内容如下: 

从上到下分别为:手动调整,固定大小,根据内容分配(两种模式)。 

 

读取QTableWidget绘制的表格中的内容

void Dialog::savedata()
{QString filepath = QFileDialog::getSaveFileName(table, "保存",QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),"Excel 文件(*.xls *.xlsx)");//返回应写入文件类型的目录,返回包含用户文档文件的目录if (filepath!=""){QAxObject *excel = new QAxObject(this);//建立excel操作对象if (excel->setControl("Excel.Application")) //连接Excel控件{excel->dynamicCall("SetVisible (bool Visible)","false");//不显示窗体excel->setProperty("DisplayAlerts", false);//不显示任何警告信息。如果为true那么在关闭是会出现类似“文件已修改,是否保存”的提示QAxObject *workbooks = excel->querySubObject("WorkBooks");//获取工作簿集合workbooks->dynamicCall("Add");//新建一个工作簿QAxObject *workbook = excel->querySubObject("ActiveWorkBook");//获取当前工作簿QAxObject *worksheet = workbook->querySubObject("Worksheets(int)", 1);//访问excel中的工作表中第一个单元格//保存到execl,总的来说就是操作单元格,赋值的赋值,改格式大的改格式,遵循一点,修改颜色,行高,字体这些属性,务必是要设定一个修改范围再动手int i,j,colcount=table->columnCount(),rowcount=table->rowCount();//表格的列数QAxObject *cell,*col;//标题行cell=worksheet->querySubObject("Cells(int,int)", 1, 1);//操作单元格cell->dynamicCall("SetValue(const QString&)", "title");//设置标题内容,SetValue(const QString&),后面就是打印的文本内容cell->querySubObject("Font")->setProperty("Size", 18);//前半句是获取单元格字体,后半句是设置字体大小//cell->setProperty("Name", QStringLiteral("华文彩云"));//设置单元格字体// cell->setProperty("Italic", true);  //设置单元格字体斜体//cell->setProperty("Underline", 2);  //设置单元格下划线//获取这个范围内的单元格,直接调整行高worksheet->querySubObject("Range(const QString&)", "1:1")->setProperty("RowHeight", 60);//合并标题行QString cellTitle;cellTitle.append("A1:");//初始原点cellTitle.append(QChar(colcount  + 'A'));//终止列(一般都要总列数减去1,Qchar)cellTitle.append(QString::number(1));//终止行()Qstring//下述第一条,可以理解为对sellTitle这个范围的单元格进行操作QAxObject *range = worksheet->querySubObject("Range(const QString&)", cellTitle);range->setProperty("WrapText", true);//自动换行range->setProperty("MergeCells", true);//合并单元格//排版:居中//左对齐(xlLeft):-4131  居中(xlCenter):-4108  右对齐(xlRight):-4152range->setProperty("HorizontalAlignment", -4108);//xlCenterrange->setProperty("VerticalAlignment", -4108);//xlCenter//行的表头for(i=0;i<colcount;i++){//读取QString columnName;//修改内容cell=worksheet->querySubObject("Cells(int,int)", 2, i+2);//确定操作单元格,将数据保存到哪儿,行的表头,所以要从第二列开始columnName=table->horizontalHeaderItem(i)->text();//获取此处的文本内容,i是列号,就是第几列中的文本内容cell->dynamicCall("SetValue(const QString&)", columnName);//打印到excel//前半句是获取单元格字体,后半句是字体加粗cell->querySubObject("Font")->setProperty("Bold", true);cell->querySubObject("Interior")->setProperty("Color",QColor(191, 191, 191));cell->setProperty("HorizontalAlignment", -4108);//xlCentercell->setProperty("VerticalAlignment", -4108);//xlCenter}//列的表头for(i=0;i<rowcount;i++){//读取QString rowName;//修改内容cell=worksheet->querySubObject("Cells(int,int)", i+3, 1);//确定操作单元格,将数据保存到哪儿列的表头,需要从第三行开始,所以+3rowName=table->verticalHeaderItem(i)->text();//horizontalHeaderItem(i)->text();//获取此处的文本内容,i是列号,就是第几列中的文本内容cell->dynamicCall("SetValue(const QString&)",rowName);//打印到excel//前半句是获取单元格字体,后半句是字体加粗cell->querySubObject("Font")->setProperty("Bold", true);cell->querySubObject("Interior")->setProperty("Color",QColor(191, 191, 191));cell->setProperty("HorizontalAlignment", -4108);//xlCentercell->setProperty("VerticalAlignment", -4108);//xlCenter}//数据区for(i=0;i<table->rowCount();i++){for (j=0;j<colcount;j++){QString rowdata[4];rowdata[j]=table->item(i,j)->text();worksheet->querySubObject("Cells(int,int)", i+3, j+2)->dynamicCall("SetValue(const QString&)",rowdata[j]);}}//画框线QString lrange;lrange.append("A2:");//起始行列位置(原点),修改后,开始的位置会变化,A2的从A2那一行开始,A3就是第三行lrange.append(colcount + 'A');//终止列,-1,就是正常状态,改变colcount后面的lrange.append(QString::number(table->rowCount() +2));//终止行//这个起始的位置,相当于原点,最终给一个行列的终止位置就行range = worksheet->querySubObject("Range(const QString&)", lrange);//querySubObject("Borders")是对边框的设置,必须有range->querySubObject("Borders")->setProperty("LineStyle", QString::number(1));range->querySubObject("Borders")->setProperty("Color", QColor(0, 0, 0));//颜色的设置//调整数据区行高QString rowsName;rowsName.append("A2:");rowsName.append(colcount + 'A');//上面两句也可以变成//rowsName.append("2:");//起始列rowsName.append(QString::number(table->rowCount() + 2));//终止行range = worksheet->querySubObject("Range(const QString&)", rowsName);range->setProperty("RowHeight", 20);//设置行高range->setProperty("ColumnWidth", 60);  //设置单元格列宽workbook->dynamicCall("SaveAs(const QString&)",QDir::toNativeSeparators(filepath));//保存至filepath//并将'/'分隔符转换为适合底层操作系统的分隔符。//在Windows上,toNativeSeparators(“c:/ winnt / system32”)返回“c:\ winnt \ system32”。//将filepath的路径workbook->dynamicCall("Close()");//关闭工作簿excel->dynamicCall("Quit()");//关闭exceldelete excel;excel=NULL;if (QMessageBox::question(NULL,"完成","文件已经导出,是否现在打开?",QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes){//QDesktopServices类提供了访问常见桌面服务的方法。//QDesktopServices::openUrl(const QUrl &url)//打开指定url中的文件//QDir目录结构及其内容的访问。QDesktopServices::openUrl(QUrl("file:///" + QDir::toNativeSeparators(filepath)));}}else{QMessageBox::warning(NULL,"错误","未能创建 Excel 对象,请安装 Microsoft Excel。",QMessageBox::Apply);}
}

整体程序布局(仅供参考)

整个头文件及源文件分布如下

mainwindow.h包含以下头文件

#include <QMainWindow>
#include <QAxObject>//excel必须包含此头文件
#include<QString>#include <QFileDialog>//文件操作必要#include<QTableWidget>//绘制表格需要#include"dialog.h"//dialog源文件的头文件#include<QDebug>

dialog.h包含以下头文件

#include <QDialog>
#include<QHBoxLayout>
#include <QMainWindow>
#include<QTextEdit>
#include<QWidget>
#include<QTableWidget>
#include<QDebug>
#include<QString>
#include <QFileDialog>
#include<QAxObject>
#include<QMessageBox>
#include <QDesktopServices>

上述的读取Excel代码位于mainwindow.cpp中

其他功能的代码位于dialog.cpp中

所以在选择查看报表的时候,会另外弹出一个QDialog类型的窗口显示内容,也可将以上功能都放置于同一个cpp中。


补充:

如果现在TableWidget中删除某行,执行以下操作

   int rowIndex = table->currentRow();if(rowIndex == -1){QMessageBox::warning(this,"Warning!","请选择一行再删除!",QMessageBox::Yes);}else if(rowIndex != -1){table->removeRow(rowIndex);}

解释:需要写入保护程序,当TableWidget没有行被选中的时候,返回值是-1,所以当有返回值不是-1,也就是我们选中某一行的时候,再进行删除操作,否则在调用过程中,可能会有如下错误。

行数: -1
ASSERT failure in QList<T>::at: "index out of range", file F:\Qt\5.9.5\mingw53_32\include/QtCore/qlist.h, line 541
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
Error - 
RtlWerpReportException failed with status code :-1073741823. Will try to launch the process directly

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

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

相关文章

chatgpt赋能python:如何利用Python处理表格

如何利用Python处理表格 在网站开发中&#xff0c;表格是至关重要的一种元素&#xff0c;它能够将复杂的信息整理成易于阅读和理解的格式。然而&#xff0c;在建立大型表格时&#xff0c;手动编写和修改HTML表格可能会变得繁琐和费时。利用Python可以轻松地批量处理和修改表格…

chatgpt赋能python:Python读取表格内容的方法

Python读取表格内容的方法 Python是一门功能强大而且易于理解的编程语言&#xff0c;在数据分析、数据科学和机器学习等领域中越来越受欢迎。在这些领域中&#xff0c;经常需要读取并处理表格数据的能力。在这篇文章中&#xff0c;我们将介绍Python中读取表格数据的常用方法。…

终于找到ChatGPT+Python爬虫搞钱新思路,快点上车

今年真是太科幻了&#xff0c;各路令人赞叹的AI产品接连问世&#xff0c;感觉幻想过的未来已在眼前。就与多年前移动互联网的普及一样&#xff0c;我们正处于AI改变世界的前夜。 在众多优秀的人工智能产品中&#xff0c;以ChatGPT最为火爆&#xff01;在OpenAI为其推出了GPT-4…

使用Python统计股票高开后的走势

股票高开是指当日股票的开盘价高于昨日的收盘价&#xff0c;为什么会这样&#xff1f;莫不是机构背着咱们搞交易&#xff1f; 股票开盘价由集合竞价产生&#xff0c;我们知道股市开盘时间为9:30-11:30~13:00-15:00&#xff0c;但集合竞价时间在9:15-9:30&#xff0c;这意味着有…

基于tushare的A股市场行情维护程序

基于tushare的A股市场行情维护程序 1 开发背景&#xff1a;2 tushare 简介3 功能需求3.1 tushare数据获取接口封装3.2 A股全市场股票日线数据的批量下载和更新 4 软件设计5 程序实现5.1 AshareDailyData.py5.2 TuShare.py 6 运行界面截图7 参考资料 1 开发背景&#xff1a; 笔…

利用Tushare获取股票数据(全面详细,照着敲就可以)

一.tushare简介 tushare是一个免费,开源的python财经数据接口包.主要实现对股票等金融数据从数据采集、清洗加工到数据存储的过程&#xff0c;能够为金融分析人员提供快速、整洁、和多样的便于分析的数据&#xff0c;为他们在数据获取方面极大地减轻工作量&#xff0c;使他们更…

【PostMan】PostMan可以打开但是窗口一直显示不出来问题

问题 如标题 解决方案&#xff1a; 1&#xff1a;关闭postman 2&#xff1a;打开如下路径 C:UsersUserNameAppDataRoamingPostman 找到一下window 文件删除该文件 说明&#xff1a;UserName 为你自己电脑上用户名称 其他情况的解决方案&#xff1a; https://github.com/postm…

开发避坑3——大鸟 pk Bug(使用postman测试POST接口遇到报错(ErrorMessage:Unauthorization request ......))

使用postman测试POST接口遇到报错&#xff08;ErrorMessage&#xff1a;Unauthorization request …) 不管你是前端、后端、测试还是运维等工程师&#xff0c;学会使用postman测试接口是工作中必不可少的。当我们使用前端页面调用接口发现浏览器报错我们就要排查是前端调用问题…

chatgpt赋能python:Python访问手机存储文件夹:移动设备编程新纪元

Python访问手机存储文件夹&#xff1a;移动设备编程新纪元 在移动设备时代&#xff0c;开发人员必须掌握能够访问手机存储文件夹的技能。Python是一种强大的编程语言&#xff0c;已成为许多应用程序和脚本的首选语言。Python为移动设备编程带来了新的可能性&#xff0c;例如可…

ChatGPT遭多国调查,OpenAI凌晨就安全问题发文,GPT-5要暂缓?

最近&#xff0c;意大利宣布禁用 ChatGPT&#xff0c;因为 OpenAI 违反了意大利相关的隐私规则和数据保护法&#xff0c;出现了用户数据丢失情况&#xff0c;而且未向用户告知。 消息出来后&#xff0c;德国、法国、爱尔兰、西班牙等国的监管部门都表示正在密切关注 ChatGPT 的…

通过AI算法预测彩票

最近工作上比较闲&#xff0c;于是抽时间写了个APP&#xff0c;运用一些AI算法&#xff0c;先排除一些明显不可能的号&#xff0c;然后结合历史数据&#xff0c;分析测算出可能得结果&#xff0c;试运行了大概10期&#xff0c;中了一个三等奖&#xff0c;蓝球概率有明显提高&am…

TOPIK 韩语考试历届考题下载

韩国语能力考试官网 http://www.topik.go.kr/ 历届考试真题下载。

5分钟带你学会MotionLayout 第二篇

1、前言 最近在开发中&#xff0c;同事居然对MontionLayout一知半解&#xff0c;那怎么行&#xff01;百里偷闲写出此文章&#xff0c;一起学习、一起进步。如果写的不好&#xff0c;或者有错误之处&#xff0c;恳请在评论、私信、邮箱指出&#xff0c;万分感谢&#x1f64f; …

重磅:宣布一件大事,大模型与 AIGC 专场来啦

文末有抽奖&#xff01; 6月30日-7月1日&#xff0c;在由稀土掘金开发者社区主办的稀土开发者大会上&#xff0c;邀你与最专业最前沿的嘉宾面对面交流&#xff01;6月30日上午的主会场&#xff0c;北京大学王选计算机研究所教授、CCF 自然语言处理专委会秘书长万小军&#xff0…

文末有抽奖|线下嗨聊 AIGC两整天!为什么我推荐你参加稀土开发者大会?!...

稀土开发者大会 6月30日-7月1日 北京新云南皇冠假日酒店&#xff08;近字节融中心工区&#xff09; &#x1f914; 若问今年谁最火&#xff1f;ChatGPT 答曰&#xff1a;AIGC 还有我&#xff01; 要问技术圈今年最火的话题是什么&#xff1f;无外乎这些关键词&#xff1a;AIGC、…

我用ChatGPT,给RabbitMQ加了个连接池

上次我把 RabbitMQ 集成到项目中&#xff0c;但是每次使用 RabbitMQ 时都去 New 一个连接&#xff0c;导致并发起不来&#xff0c;所以这次我们就给 RabbitMQ 加一个连接池。 为了偷个懒&#xff0c;我直接用 ChatGPT 教我加。 01 ChatGPT 生成的代码 我输入的关键字如下&am…

ClickPrompt

太长不看版&#xff1a; GitHub&#xff1a;github.com/prompt-engi…在线地址&#xff1a;www.clickprompt.org/ 欢迎来添加你的 AI Prompt 和使用心得。 再上个截图&#xff1a; ClickPrompt&#xff1a;简化你的 Prompt 设计之旅 上周末&#xff0c;为了更好地记录与分享…

线下嗨聊 AIGC两整天!为什么我推荐你参加稀土开发者大会?

&#x1f914; 若问今年谁最火&#xff1f; ChatGPT 答曰&#xff1a;AIGC 还有我&#xff01; 要问技术圈今年最火的话题是什么&#xff1f;无外乎这些关键词&#xff1a;AIGC、ChatGPT、某端已死、各行各业✖️ChatGPT…… 究其原因&#xff0c;是因为 AI 这些年在不断更新…

nodejs 获取微信小程序二维码

getQRCode(accessToken) {const { ctx } this;let parameters;let url https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token${accessToken};await axios({method: "post",url: url,responseEncoding: "base64", //重点data: {page: "pa…

我要开始在B站分享视频教程了

目录 前言一、精品网站分享ChatGPT菜鸟在线编辑器在线音乐网站 二、常用工具知识学习编程前端 视图文关于俺 前言 大家好&#xff0c;我是MIKE笔记&#xff0c;一名在CSDN经常分享技术文章和教程的博主。如果你也喜欢我的文章&#xff0c;那么我想向你推荐我的B站频道&#xf…