1. 程式人生 > >Qt批量操作Excel

Qt批量操作Excel

最近在做一個專案,客戶要求把查詢到的資料匯出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秒鐘。