您的位置:首页 > 编程语言 > Qt开发

Qt批量操作Excel

2015-07-13 15:21 489 查看
最近在做一个项目,客户要求把查询到的数据导出Excel,而网上大部分资料描述的都很局限、很简单。

由于要导出的数据量很大(QTableView中大约有几十万条数据),一开始我是找到一个单元格就写入一个值,但这样的话程序就会把大量的时间花费在线程切换中,导致效率太低(5000行数据大概需要5分钟)。

最后找到了一种方法,即为对Excel进行批量写入值操作,下面是我程序中导出excel部分的源码:

<span style="white-space:pre"> </span>QString strContent;
QAxObject *range;
QList<QVariant> mLstData;
QList<QString> mLstCurData;
int nColumns = 0;
QString strMergeCell;
int nIndex = 0, nTotal = 0; // 记录数据个数
QStringList strListParaName;
QMap<int,PidInfoStruct> mapPidInfo;

//建立Excel对象
HRESULT r = OleInitialize(0);<span style="white-space:pre"> </span>//由于我把导出数据的操作放在了一个新线程中,所以在调用activeX之前要初始化com组件
if (r != S_OK && r != S_FALSE) {
qWarning("Qt: Could not initialize OLE (error %x)", (unsigned int)r);
}
QAxObject *excel = new QAxObject("Excel.Application");
excel->dynamicCall("SetVisible(bool)", false);
excel->setProperty("Visible", false);
QAxObject *workbooks = excel->querySubObject("WorkBooks");
if (workbooks == NULL)
{
return;
}
workbooks->dynamicCall("Add");
QAxObject *workbook = excel->querySubObject("ActiveWorkBook");
QAxObject *worksheet = workbook->querySubObject("Worksheets(int)", 1);

nTotal = mapNdtPidVal.count();
mLstData.clear();
QMapIterator<uint, QMap<int,float>> itor(mapNdtPidVal);<span style="white-space:pre"> </span>//map中为到导出的数据(此为我项目中的数据)
while (itor.hasNext())
{
itor.next();
++nIndex;
QString strTime = QDateTime::fromTime_t(itor.key()).toString(
"yyyy-MM-dd hh:mm:ss");
QMapIterator<int, float> hashItOfPidVal(itor.value());
QList<QString> fListVal;
while (hashItOfPidVal.hasNext())
{
hashItOfPidVal.next();

if (nIndex <= 1) // 只有解析第一条数据时,装载参数列表
{
mapPidInfo.clear();
if (!WinManager::instance().getPidInfoByType(nDevType, mapPidInfo))
{
continue;
}
strListParaName.append(mapPidInfo.value(hashItOfPidVal.key()).strName);
}
fListVal.append(QString("%1").arg(hashItOfPidVal.value()));
}
// 参数个数和对应参数值个数不一致,丢掉此数据
if (strListParaName.count() != fListVal.count())
{
--nIndex;
continue;
}

if (nIndex <= 1) // 只有解析第一条数据时,设置表头
{
QStringList strHorizontalHeader;
strHorizontalHeader << QStringLiteral("序号") << QStringLiteral("时间") << strListParaName;
mLstData << QVariant(strHorizontalHeader);
}
mLstCurData.clear();
mLstCurData << QString("%1").arg(nIndex);
mLstCurData << strTime;

mLstCurData << fListVal;
if (mLstCurData.count() > nColumns)
{
nColumns = mLstCurData.count();
}
mLstData << QVariant(mLstCurData);
emit showExportState((int)(nIndex * 99 / nTotal));
}
<span style="white-space:pre"> </span>//指定导出数据的行列范围
strMergeCell.append(QChar('A')); //初始列
strMergeCell.append(QString::number(1)); //初始行
strMergeCell.append(":");
strMergeCell.append(QChar(nColumns - 1 + 'A')); //终止列
strMergeCell.append(QString::number(mLstData.count())); //终止行
<span style="white-space:pre">	</span>//批量写入所有数据
QAxObject *merge_range = worksheet->querySubObject("Range(const QString&)", strMergeCell);
merge_range->setProperty("Value", QVariant(mLstData));

workbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(strFileName));
emit showExportState(100);
workbook->dynamicCall("Close()");
worksheet->clear();//释放所有工作表
excel->dynamicCall("Quit()");
delete excel;//释放excel
OleUninitialize();
最后,由于这是一个耗时的操作,所以建议尽量把导出excel操作放在一个新线程里面,然后把导出进度通过信号发给UI线程,让UI显示导出进度。通过批量操作的方式,10万条数据只需要5秒钟。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: