使用Qt开发小工具时,有时会涉及到Excel文件读写操作,就我自己的经历总结了三种方法。
- 使用XmlDocument 写xls
Qt定义了xml文件读写接口QDomDocument,也可以通过这个接口写Excel表格,但仅限于xls文件。
bool MainWindow::TestQDomDocument()
{
QString selectedFile = QFileDialog::getSaveFileName(this,QStringLiteral("保存"), "./data/", QStringLiteral("XLS file (*.xls)"));
if (selectedFile.isEmpty() == true)
return false;
if (selectedFile.endsWith(".xls") == false)
selectedFile += ".xls";
QFile file(selectedFile);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
QMessageBox::warning(this, QStringLiteral("错误"), QStringLiteral("创建文件出错!"));
return false;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
QDomDocument domDoc;
QDomProcessingInstruction instruction = domDoc.createProcessingInstruction("xml","version=\'1.0\'");
domDoc.appendChild(instruction);
instruction = domDoc.createProcessingInstruction("mso-application","progid=\'Excel.Sheet\'");
domDoc.appendChild(instruction);
QDomElement rootEle = domDoc.createElement("Workbook");
rootEle.setAttribute("xmlns","urn:schemas-microsoft-com:office:spreadsheet");
rootEle.setAttribute("xmlns:ss","urn:schemas-microsoft-com:office:spreadsheet");
domDoc.appendChild(rootEle);
QDomElement workSheetEle = domDoc.createElement("Worksheet");
workSheetEle.setAttribute("ss:Name","Sheet1");
rootEle.appendChild(workSheetEle);
QDomElement tableEle = domDoc.createElement("Table");
workSheetEle.appendChild(tableEle);
//按行写数据
QStringList header;
header << QStringLiteral("名称") << QStringLiteral("类型")<< QStringLiteral("子类型")<<QStringLiteral("数量");
QList<QStringList> allTables;
allTables.push_back(header);
for(int i=0; i<m_pointList.size(); i++)//QList<PointInfo >
{
QStringList itemlist = m_pointList[i].toList();
allTables.push_back(itemlist);
// QStringList toList()
// {
// return QStringList() << name << type << subtype << num;//结构体转为QStringList
// }
}
int count = allTables.size();
for(int i=0; i<count; i++)
{
qApp->processEvents();
QStringList item = allTables[i];
QDomElement rowEle = domDoc.createElement("Row"); //添加标题
for(int j=0; j<item.count(); j++)
{
QDomElement cellEle = domDoc.createElement("Cell");
QDomElement dataEle = domDoc.createElement("Data");
QString strValue = item.at(j);
dataEle.setAttribute("ss:Type", "String");
QDomText domText = domDoc.createTextNode(strValue);
dataEle.appendChild(domText);
cellEle.appendChild(dataEle);
rowEle.appendChild(cellEle);
}
tableEle.appendChild(rowEle);
}
QTextStream outStream(&file);
outStream.setCodec(QTextCodec::codecForName("UTF-8"));
domDoc.save(outStream, 4, QDomNode::EncodingFromTextStream);
file.close();
QApplication::restoreOverrideCursor();
QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("保存文件成功!"));
return true;
}
- 使用QtXlsx写xlsx
QtXlsx并不是Qt5本身提供的库,需要下载源码编译才能使用,下载和编译部分我是参考链接:使用QtXlsx来读写excel文件,拜谢!
实际上源码部分已经给出了很多demo,大家找到examples目录可以看到具体内容,包括各种图片,文字,字体设置等等操作都有对应的小demo。
bool MainWindow::TestQXlsx()
{
QString selectedFile = QFileDialog::getSaveFileName(this,QStringLiteral("保存"), "./data/", QStringLiteral("XLSX file (*.xlsx)"));
if (selectedFile.isEmpty() == true)
return false;
if (selectedFile.endsWith(".xlsx") == false)
selectedFile += ".xlsx";
QXlsx::Document xlsx(selectedFile);
QStringList header;
header << QStringLiteral("名称") << QStringLiteral("类型")<< QStringLiteral("子类型")<<QStringLiteral("数量");
QList<QStringList> allTables;
allTables.push_back(header);
for(int i=0; i<m_pointList.size(); i++)
{
QStringList itemlist = m_pointList[i].toList();
allTables.push_back(itemlist);
}
int rowCount = allTables.size();
for (int row =0; row<rowCount; ++row)
{
QStringList item = allTables[row];
int colCount = item.size();
for (int col=0; col<colCount; ++col)
{
if(col == 3 && row > 0)
{
QString numstr = item[col];
double num = numstr.toDouble();
xlsx.write(row+1, col+1, num);
}
else
xlsx.write(row+1, col+1, item[col]);
}
}
xlsx.save();
QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("保存文件成功!"));
QDesktopServices::openUrl(QUrl::fromLocalFile(selectedFile));
return true;
}
- 使用QAxObject直接操作Excel
这部分内容也是我从网上找到的使用较多的方法,顺便列出来。我自己本身没有使用这个方法,但据说在windows上读写Excel文件是很快的(qt5 使用qtxlsx 读写excel ;快速读取数据量很大的Excel文件),大家可以根据自己的情况尝试下。(ps.代码部分参考博文地址没有单独保存,如果博主看到可以联系我。)
bool MainWindow::TestQAxObject(QString path)
{
QAxObject *excel = NULL; //本例中,excel设定为Excel文件的操作对象
QAxObject *workbooks = NULL;
QAxObject *workbook = NULL; //Excel操作对象
excel = new QAxObject("Excel.Application");
excel->dynamicCall("SetVisible(bool)", true); //true 表示操作文件时可见,false表示为不可见
workbooks = excel->querySubObject("WorkBooks");
//————————————————按文件路径打开文件————————————————————
workbook = workbooks->querySubObject("Open(QString&)", path);
// 获取打开的excel文件中所有的工作sheet
QAxObject * worksheets = workbook->querySubObject("WorkSheets");
//—————————————————Excel文件中表的个数:——————————————————
int iWorkSheet = worksheets->property("Count").toInt();
qDebug() << QString("Excel文件中表的个数: %1").arg(QString::number(iWorkSheet));
// ————————————————获取第n个工作表 querySubObject("Item(int)", n);——————————
QAxObject * worksheet = worksheets->querySubObject("Item(int)", 1);//本例获取第一个,最后参数填1
//—————————获取该sheet的数据范围(可以理解为有数据的矩形区域)————
QAxObject * usedrange = worksheet->querySubObject("UsedRange");
//———————————————————获取行数———————————————
QAxObject * rows = usedrange->querySubObject("Rows");
int iRows = rows->property("Count").toInt();
qDebug() << QString("行数为: %1").arg(QString::number(iRows));
//————————————获取列数—————————
QAxObject * columns = usedrange->querySubObject("Columns");
int iColumns = columns->property("Count").toInt();
qDebug() << QString("列数为: %1").arg(QString::number(iColumns));
//————————数据的起始行———
int iStartRow = rows->property("Row").toInt();
qDebug() << QString("起始行为: %1").arg(QString::number(iStartRow));
//————————数据的起始列————————————
int iColumn = columns->property("Column").toInt();
qDebug() << QString("起始列为: %1").arg(QString::number(iColumn));
//——————————————读出数据—————————————
//获取第i行第j列的数据
//假如是第6行,第6列 对应表中F列6行,即F6
QAxObject *range1 = worksheet->querySubObject("Range(QString)", "F6");
QString strRow6Col6 = "";
strRow6Col6 = range1->property("Value").toString();
qDebug() << "第6行,第6列的数据为:" + strRow6Col6;
//列的转换函数如下地址,第6列转为F列,第29列转为AC列
//—————————————写入数据—————————————
//获取F6的位置
QAxObject *range2 = worksheet->querySubObject("Range(QString)", "F6");
//写入数据, 第6行,第6列
range2->setProperty("Value", "中共十九大");
QString newStr = "";
newStr = range2->property("Value").toString();
qDebug() << "写入数据后,第6行,第6列的数据为:" + newStr;
//!!!!!!!一定要记得close,不然系统进程里会出现n个EXCEL.EXE进程
workbook->dynamicCall("Close()");
excel->dynamicCall("Quit()");
if (excel)
{
delete excel;
excel = NULL;
}
return true;
}