Qt批量操作Excel
阿新 • • 發佈:2019-02-06
最近在做一個專案,客戶要求把查詢到的資料匯出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())); //終止行
最後,由於這是一個耗時的操作,所以建議儘量把匯出excel操作放在一個新執行緒裡面,然後把匯出進度通過訊號發給UI執行緒,讓UI顯示匯出進度。通過批量操作的方式,10萬條資料只需要5秒鐘。<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();