Qt 讀寫Excel,並顯示到tablewidget
阿新 • • 發佈:2019-02-01
<pre name="code" class="cpp">#include "excelengine.h" #include "qt_windows.h" ExcelEngine::ExcelEngine() { pExcel = NULL; pWorkbooks = NULL; pWorkbook = NULL; pWorksheet = NULL; sXlsFile = ""; nRowCount = 0; nColumnCount = 0; nStartRow = 0; nStartColumn = 0; bIsOpen = false; bIsValid = false; bIsANewFile = false; bIsSaveAlready = false; HRESULT r = OleInitialize(0); if (r != S_OK && r != S_FALSE) { qDebug("Qt: Could not initialize OLE (error %x)", (unsigned int)r); } } ExcelEngine::ExcelEngine(QString xlsFile) { pExcel = NULL; pWorkbooks = NULL; pWorkbook = NULL; pWorksheet = NULL; sXlsFile = xlsFile; nRowCount = 0; nColumnCount = 0; nStartRow = 0; nStartColumn = 0; bIsOpen = false; bIsValid = false; bIsANewFile = false; bIsSaveAlready = false; HRESULT r = OleInitialize(0); if (r != S_OK && r != S_FALSE) { qDebug("Qt: Could not initialize OLE (error %x)", (unsigned int)r); } } ExcelEngine::~ExcelEngine() { if ( bIsOpen ) { //析構前,先儲存資料,然後關閉workbook Close(); } OleUninitialize(); } /** *@brief 開啟sXlsFile指定的excel報表 *@return true : 開啟成功 * false: 開啟失敗 */ bool ExcelEngine::Open(UINT nSheet, bool visible) { if ( bIsOpen ) { //return bIsOpen; Close(); } nCurrSheet = nSheet; bIsVisible = visible; if ( NULL == pExcel ) { pExcel = new QAxObject("Excel.Application"); if ( pExcel ) { bIsValid = true; } else { bIsValid = false; bIsOpen = false; return bIsOpen; } pExcel->dynamicCall("SetVisible(bool)", bIsVisible); } if ( !bIsValid ) { bIsOpen = false; return bIsOpen; } if ( sXlsFile.isEmpty() ) { bIsOpen = false; return bIsOpen; } /*如果指向的檔案不存在,則需要新建一個*/ QFile f(sXlsFile); if (!f.exists()) { bIsANewFile = true; } else { bIsANewFile = false; } if (!bIsANewFile) { pWorkbooks = pExcel->querySubObject("WorkBooks"); //獲取工作簿 pWorkbook = pWorkbooks->querySubObject("Open(QString, QVariant)",sXlsFile,QVariant(0)); //開啟xls對應的工作簿 } else { pWorkbooks = pExcel->querySubObject("WorkBooks"); //獲取工作簿 pWorkbooks->dynamicCall("Add"); //新增一個新的工作薄 pWorkbook = pExcel->querySubObject("ActiveWorkBook"); //新建一個xls } pWorksheet = pWorkbook->querySubObject("WorkSheets(int)", nCurrSheet);//開啟第一個sheet //至此已開啟,開始獲取相應屬性 QAxObject *usedrange = pWorksheet->querySubObject("UsedRange");//獲取該sheet的使用範圍物件 QAxObject *rows = usedrange->querySubObject("Rows"); QAxObject *columns = usedrange->querySubObject("Columns"); //因為excel可以從任意行列填資料而不一定是從0,0開始,因此要獲取首行列下標 nStartRow = usedrange->property("Row").toInt(); //第一行的起始位置 nStartColumn = usedrange->property("Column").toInt(); //第一列的起始位置 nRowCount = rows->property("Count").toInt(); //獲取行數 nColumnCount = columns->property("Count").toInt(); //獲取列數 bIsOpen = true; return bIsOpen; } /** *@brief Open()的過載函式 */ bool ExcelEngine::Open(QString xlsFile, UINT nSheet, bool visible) { sXlsFile = xlsFile; nCurrSheet = nSheet; bIsVisible = visible; return Open(nCurrSheet,bIsVisible); } /** *@brief 儲存表格資料,把資料寫入檔案 */ void ExcelEngine::Save() { if ( pWorkbook ) { if (bIsSaveAlready) { return ; } if (!bIsANewFile) { pWorkbook->dynamicCall("Save()"); } else /*如果該文件是新建出來的,則使用另存為COM介面*/ { pWorkbook->dynamicCall("SaveAs (const QString&,int,const QString&,const QString&,bool,bool)", sXlsFile,56,QString(""),QString(""),false,false); } bIsSaveAlready = true; } } /** *@brief 關閉前先儲存資料,然後關閉當前Excel COM物件,並釋放記憶體 */ void ExcelEngine::Close() { //關閉前先儲存資料 Save(); if ( pExcel && pWorkbook ) { pWorkbook->dynamicCall("Close(bool)", true); pExcel->dynamicCall("Quit()"); delete pExcel; pExcel = NULL; bIsOpen = false; bIsValid = false; bIsANewFile = false; bIsSaveAlready = true; } } /** *@brief 把tableWidget中的資料儲存到excel中 *@param tableWidget : 指向GUI中的tablewidget指標 *@return 儲存成功與否 true : 成功 * false: 失敗 */ bool ExcelEngine::SaveDataFrTable(QTableWidget *tableWidget) { if ( NULL == tableWidget ) { return false; } if ( !bIsOpen ) { return false; } int tableR = tableWidget->rowCount(); int tableC = tableWidget->columnCount(); //獲取表頭寫做第一行 for (int i=0; i<tableC; i++) { if ( tableWidget->horizontalHeaderItem(i) != NULL ) { this->SetCellData(1,i+1,tableWidget->horizontalHeaderItem(i)->text()); } } //寫資料 for (int i=0; i<tableR; i++) { for (int j=0; j<tableC; j++) { if ( tableWidget->item(i,j) != NULL ) { this->SetCellData(i+2,j+1,tableWidget->item(i,j)->text()); } } } //儲存 Save(); return true; } /** *@brief 從指定的xls檔案中把資料匯入到tableWidget中 *@param tableWidget : 執行要匯入到的tablewidget指標 *@return 匯入成功與否 true : 成功 * false: 失敗 */ bool ExcelEngine::ReadDataToTable(QTableWidget *tableWidget) { if ( NULL == tableWidget ) { return false; } //先把table的內容清空 int tableColumn = tableWidget->columnCount(); tableWidget->clear(); for (int n=0; n<tableColumn; n++) { tableWidget->removeColumn(0); } int rowcnt = nStartRow + nRowCount; int columncnt = nStartColumn + nColumnCount; //獲取excel中的第一行資料作為表頭 QStringList headerList; for (int n = nStartColumn; n<columncnt; n++ ) { QAxObject * cell = pWorksheet->querySubObject("Cells(int,int)",nStartRow, n); if ( cell ) { headerList<<cell->dynamicCall("Value2()").toString(); } } //重新建立表頭 tableWidget->setColumnCount(nColumnCount); tableWidget->setHorizontalHeaderLabels(headerList); //插入新資料 for (int i = nStartRow+1, r = 0; i < rowcnt; i++, r++ ) //行 { tableWidget->insertRow(r); //插入新行 for (int j = nStartColumn, c = 0; j < columncnt; j++, c++ ) //列 { QAxObject * cell = pWorksheet->querySubObject("Cells(int,int)", i, j );//獲取單元格 //在r新行中新增子項資料 if ( cell ) { tableWidget->setItem(r,c,new QTableWidgetItem(cell->dynamicCall("Value2()").toString())); } } } return true; } /** *@brief 獲取指定單元格的資料 *@param row : 單元格的行號 *@param column : 單元格的列號 *@return [row,column]單元格對應的資料 */ QVariant ExcelEngine::GetCellData(UINT row, UINT column) { QVariant data; QAxObject *cell = pWorksheet->querySubObject("Cells(int,int)",row,column);//獲取單元格物件 if ( cell ) { data = cell->dynamicCall("Value2()"); } return data; } /** *@brief 修改指定單元格的資料 *@param row : 單元格的行號 *@param column : 單元格指定的列號 *@param data : 單元格要修改為的新資料 *@return 修改是否成功 true : 成功 * false: 失敗 */ bool ExcelEngine::SetCellData(UINT row, UINT column, QVariant data) { bool op = false; QAxObject *cell = pWorksheet->querySubObject("Cells(int,int)",row,column);//獲取單元格物件 if ( cell ) { QString strData = data.toString(); //excel 居然只能插入字串和整型,浮點型無法插入 cell->dynamicCall("SetValue(const QVariant&)",strData); //修改單元格的資料 op = true; } else { op = false; } return op; } /** *@brief 清空除報表之外的資料 */ void ExcelEngine::Clear() { sXlsFile = ""; nRowCount = 0; nColumnCount = 0; nStartRow = 0; nStartColumn = 0; } /** *@brief 判斷excel是否已被開啟 *@return true : 已開啟 * false: 未開啟 */ bool ExcelEngine::IsOpen() { return bIsOpen; } /** *@brief 判斷excel COM物件是否呼叫成功,excel是否可用 *@return true : 可用 * false: 不可用 */ bool ExcelEngine::IsValid() { return bIsValid; } /** *@brief 獲取excel的行數 */ UINT ExcelEngine::GetRowCount()const { return nRowCount; } /** *@brief 獲取excel的列數 */ UINT ExcelEngine::GetColumnCount()const { return nColumnCount; }
最近用Qt在幫別人最一個管理工具,需要操作Excel,在網上找了大半天,發現大多都是對excel進行讀操作,少有寫的,而我的需求是,既需要從excel中讀資料,也需要網excel中寫,同時需要和tablewidget關聯,也就是,最後實現,可從excel中讀取資料直接顯示到tablewidget中,並且,可把tablewidget中的資料匯出到excel報表中,網上找了半天,沒找到,多數都是抄來抄去的,於是就自己封裝了一個類。
最近修改:最近在繼續使用這個類操作Excel,發現向Excel中插入資料時,就然只能插入字串型別或者整型,浮點數型別無法插入,第二個問題是,線上程中無法使用這個類。
解決方案:關於第一個問題,我自己在類內部把插入的資料先toString成字串再插入,但是介面不變,還是原來的SetCellData(int row,int column,QVarient data);
第二個問題,搜了一下,發現是在GUI中使用COM時,Qt內部程式碼會幫我們初始化OLE環境,但是執行緒中不會,得我們自己初始化,所以,我在類的建構函式中添加了初始化的程式碼,在解構函式中清除環境。
經過改變後,類可以線上程中使用,也可以插入任何型別的資料
zz 最近修改:匯出檔案時,通過新建xls檔案方式建立檔案,原來的方法較土,是通過拷貝模板來建立
說明:該類使用COM操作excel,需要在.pro中加入CONFIG += qaxcontainer