本片文章主要记录和分享一下qt使用qxlsx开源文件读写xlsx表格文件用法。
windows
linux
qt5.7
首先安装和部署qxlsx文件我就不说了,网上很多很多,都是开源的pri文件夹,直接复制再pro文件调用添加即可。
本样例是读取某个表格1、2列内容,读取全部1、2列有的内容,除去第一行标题行,只保留内容
QString path=qApp->applicationDirPath()+"/code.xlsx";
QFile file(path);
if(!file.exists())
massage_dialog(1,"提示","xxx信息!",1);
else{
QStringList code_nums;code_nums.clear();
QStringList code_name;code_name.clear();
QXlsx::Document xlsx(path);
QXlsx::Workbook *workBook = xlsx.workbook();
QXlsx::Worksheet *workSheet = static_cast<QXlsx::Worksheet*>(workBook->sheet(0));
ulong xlsxrows=workSheet->dimension().rowCount();//读取文件行数
ulong xlsxcloums=workSheet->dimension().columnCount();//读取文件列数
for (int i=1;i<=xlsxrows;i++){
code_nums.append(workSheet->cellAt(i, 1)->value().toString());
code_name.append(workSheet->cellAt(i, 2)->value().toString());
}
code_nums.removeFirst();//去掉第一行标题行
code_name.removeFirst();//去掉第一行标题行
xlsx.deleteLater();
本样例是保存表格内容到指定名称的文件(新建),并生成某一列数据的曲线,从坐标1到坐标2
QXlsx::Document xlsx;
xlsx.addSheet(title_name[i]);
xlsx.selectSheet(title_name[i]);
///写大标题,标题在第一行
QXlsx::Format formatTitle;
formatTitle.setFontBold(true);// 粗体
formatTitle.setFontColor(QColor(Qt::black));//文字颜色
formatTitle.setFontSize(20);//字体大小
formatTitle.setBorderStyle(QXlsx::Format::BorderThin);//边框样式,细网格线
formatTitle.setPatternBackgroundColor(Qt::lightGray);//单元格背景色
formatTitle.setFillPattern(QXlsx::Format::PatternSolid);//填充样式
formatTitle.setHorizontalAlignment(QXlsx::Format::AlignHCenter);//文本水平居中
xlsx.mergeCells(QXlsx::CellRange(1,1,1,20), formatTitle);//合并单元格 第一行第1列到第一行第15列合并成一格
QString code="未知设备";
if(!ui->lineEdit->text().isEmpty())code=ui->lineEdit->text();
xlsx.write(1,1,"设备号:"+code+",信号名称:"+title_name[i]+",数据组数:"+QString::number(r_groupdata.size()));//给合并后的单元格写数据, 注意参数 (1,1,"title")
///写小标题,标题在第一行
QXlsx::Format format1;
format1.setBorderStyle(QXlsx::Format::BorderThin);//边框样式,细网格线
format1.setHorizontalAlignment(QXlsx::Format::AlignHCenter);//文本水平居中
xlsx.write(2,1,"信号值",format1);
xlsx.write(2,2,"时间戳",format1);
///写内容,从第三行开始,1-2列
QXlsx::Format format2;
format2.setBorderStyle(QXlsx::Format::BorderThin);//边框样式,细网格线
format2.setHorizontalAlignment(QXlsx::Format::AlignHCenter);//文本水平居中
//可以先按行写, 也可以按列写
//...
for (ulong row = 0; row < r_groupdata.size(); row++){
xlsx.write(row+3,1,r_groupdata[row].box_zhidong[2],format2);//档位开始
xlsx.write(row+3,2,r_groupdata[row].box_time.toString("yyyy-MM-dd hh:mm:ss"),format2);//时间
}
//生成曲线
Chart * Crom = xlsx.insertChart( 3, 5, QSize(1200, 800) );
Crom->setChartType( Chart::CT_ScatterChart );//CT_ScatterChart
Crom->addSeries( CellRange(QString("A3:A%1").arg(r_groupdata.size()+2)) );
Crom->setAxisTitle( Chart::Left, QString("数值") );
Crom->setAxisTitle( Chart::Bottom, QString("时间线") );
Crom->setChartTitle( QString(title_name[i]) );
//保存数据
bool res=false;
res = xlsx.saveAs(dir+historydir+"/信号"+QString("%1").arg(i+1,2,10,QChar('0'))+"-"+title_name[i]+QString("-%1数据包.xlsx").arg(r_groupdata.size()));
xlsx.deleteLater();
MySleep(10000,1000);
mysleep函数如下
//延时usetime:非阻塞时间 waittime:阻塞时间
void MySleep(uint usetime,ulong waittime)
{
QCoreApplication::processEvents(QEventLoop::AllEvents, usetime);//进入此函数内给之前数据usetime毫秒时间处理,处理完立马退出执行之后,超时立马退出
QThread::msleep(waittime);//阻塞延时waittime毫秒
}
在使用qxlsx保存文件时,会遇到有的时候保存数据量过大时程序崩溃的问题, 这种问题由于源码过于复杂原因未深入研究寻找原因,暂时使用其他方式解决,方案一就是将数据按列分开保存, 假如数据有30列,有20万行,就1列保存一个xlsx文件,然后循环30列保存,中间加上mysleep延时函数,这样在保存一列之后再中间的等待时间会释放已经申请的内存,然后保存第二列再用,再任务管理器中看现象就是内存500M→1500M→500M→1500M。。。
方案二就是按行保存,再保存超过一定行数之后就换另外一个文件保存
下面是一部分示例代码,我通过spinBox设置单个文件保存行数,10000行为步长
//导出excel
void MainWindow::on_pushButton_4_clicked()
{
QString dir = QFileDialog::getExistingDirectory(this, tr("选择信息导出文件目录"),"/home",QFileDialog::ShowDirsOnly|QFileDialog::DontResolveSymlinks);
if(dir.isEmpty())
QMessageBox::information(this,"提示","路径为空!设置保存报告路径失败!");
else{
bool exist;
QDir *folder = new QDir();
QString historydir="/histroy"+QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss");
exist = folder->exists(dir+historydir);//文件夹是否存在
if(!exist)folder->mkdir(dir+historydir);//不存在创建文件夹
// 设置excel表头(第一行数据)
QString groupname[27]={"时间","识别号","ID","度","度","角度","速","速度","半径","状态","卫星定位状态","状态","数","期","状态","状态","温度","据状态","据状态","模式态","路态","模式","指令","路件名","路编号","返航确认果","上态"};
QStringList titleList;
titleList.clear();
for(int i=0;i<27;i++)
titleList.append(groupname[i]);
bool res;
ulong allnum=ui->tableWidget->rowCount();
ulong thisnum=0,afternum=0;
QVector<ulong> savelistcount;
char count=allnum/ui->spinBox->value();
for(int i=0;i<count;i++)
savelistcount.append(ui->spinBox->value());
savelistcount.append(allnum%ui->spinBox->value());
for(int time=0;time<savelistcount.size();time++){
thisnum=afternum;
afternum+=savelistcount.at(time);
qDebug()<<thisnum<<afternum;
QXlsx::Document xlsx;
xlsx.setColumnWidth(1,10);//第一行,20列宽
for (int i = 0; i < titleList.size(); i++){
xlsx.write(1, i+1, titleList.at(i));//这里写第一行,第n列数据
//开始写第n行数据
for(int j = thisnum;j<afternum;j++){
xlsx.write(j+2-thisnum,i+1,ui->tableWidget->item(j,i)->text());
}
}
// 最后,保存文件
res=xlsx.saveAs(dir+historydir+"/"+QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss")+QString("(%1)").arg(time+1)+".xlsx");
xlsx.deleteLater();
QCoreApplication::processEvents(QEventLoop::AllEvents, 10000);//进入此函数内给之前数据usetime毫秒时间处理,处理完立马退出执行之后,超时立马退出
QThread::msleep(1000);//阻塞延时waittime毫秒
}
if(res)
QMessageBox::information(this,"提示","保存excel成功!");
else
QMessageBox::information(this,"提示","保存excel失败!");
}
}
其中所有数据再控件tabelwidget中
当个文件行数在控件spinBox中
新年第二篇文章,收尾一个去年计划中发表文章和实现功能。