學習背景:
適合熟悉些qt開發,但是不是深入了解的開發者學習。具體實現(qt 5.1版本),office2007 Excel做驗證,Win 7(64位),如有講解有誤,歡迎斧正!
一.簡單介紹
QAxObject是Qt提供的包裝COM組件的類,通過COM通過COM操作使用QAxObject類,使用此類,需要在pro文件中添加"QT += axcontainer "。
二.與excel com連接的方法
1. #include <ActiveQt/QAxObject>
2. QAxObject *excel = new QAxObject("Excel.Application"); //!建立excel操作對象,並連接Excel控件
3. excel->dynamicCall("SetVisible (bool Visible)", "false"); //! 設置為不顯示窗體
4.excel->setProperty("DisplayAlerts", false); //! 不顯示任何警告信息, 如關閉時的是否保存提示
5.excel->dynamicCall("Quit(void)"); //! 關閉excel程序,操作完后記着關閉,由於是隱藏在后台進程中,不關閉進程會有很多excel.exe。
6.workbook->dynamicCall("Close(Boolean)", false); //! 關閉exce程序先關閉.xls文件
三.Excel基本操作
只介紹簡單的讀寫操作,需要修改單元格格式等操作,請"Excel VBA參考手冊.chm"
3.1 excel文件操作
獲取當前工作簿的集合
1> QAxObject *workbooks = excel->querySubObject("Workbooks"); //! 獲取工作簿(excel文件)集合
新建一個工作簿
1> workbooks->synamicCall("Add"); //新建一個工作簿
QAxObject *workbook = excel->querySubObject("ActiveWorkBook"); //! 獲取當前工作簿
打開一個已有的工作簿
1>QString filename = "e:/123.xlsx";
2>QAxObject* workbook = workbooks->querySubObject("Open(const QString&)", filename);
保存工作簿
1>workbook->dynamicCall("Save()"); //!保存文件
2>workbook->dynamicCall("Close(Boolean)", false); //! 關閉文件
3>excel->dynamicCall("Quit()"); //! 關閉excel
另存為工作簿
1>QDir::toNativeSeparators,將路徑中的"/"轉換為"\",否則無法保存,"/"只是qt中可以識別
2>workbook->dynamiCall("SaveAs(const QString&)", QDit::toNativeSeparators(filename));
3>workbook->synamicCall("Close(Boolean)", false); //! 關閉文件
4>excel->dynamicCall("Quit()"); //! 關閉excel
3.2 Sheet工作表操作
獲取所有工作表
1> QAxObject *worksheets = workbook->querySubObject("Sheets"):
根據序號獲取某個工作表,序號順序就是excel 打開后下方的排序
1>QAxObject *worksheet = worksheets->querySubObejct("Item(int)", 1);
獲取表中的行數列數
1>QAxObject* usedrange = worksheet->querySubObject("UsedRange"); //! sheet 范圍
2>int intRowStart = usedrange->property("Row").toInt(); //! 起始行數
3>int intColStart = usedrange->property("Column").toInt(); //! 起始列數
4>QAxObject *rows, *columns;
5>rows = usedrange->querySubObject("Rows"): //! 行
6>columns = usedrange->querySubObject("Columns"); //! 列
7>int intRow = rows->property("Count").toInt(); //! 行數
8>int intCol = columns->property("Count").toInt(); //! 列數
3.3 內容操作
數據內容操作--獲取單元格--基於坐標
1> QAxObject *cell = worksheet->querySubObject("Cells(int, int)", i, j);
數據內容操作--獲取單元格--基於行列名稱
1>QAxObject *cell = worksheet->querySubObject("Range(QVariant, QVariant)", "A1");
數據內容操作--讀單元格內容
1> QVariant cell_value = cell->property("Value");
數據內容操作-- 寫單元格內容
1> cell->setProperty("Value", "內容");
4.其他(沒有實踐操作)
4.1 大數據量讀取
讀取所有單元格內容-數據量大,只需要進行一次操作即可讀取所有內容,避免重復對每個單元格進行QAxObect操作
1. QVariant var;
2. QAxObject * usedRange = sheet->querySubObject("UseRange"); //! 獲取用戶區域范圍
3. if(NULL == usedRange || usedRange->isNull()){
return var;
}
4. var = usedRange->dynamicCall("Value"); // 讀取區域內所有值
5.delete usedRange;
此時結果以QVariant保存,需要自行轉化為QList<QList<QVariant>>
QList<QList<QVariant>> excel_list;
auto rows = var.toList();
for(auto row:rows) {
- excel_list.append(row.toList());
- }
- 4.2 大數據寫入
以QList<QList<QVariant>>存儲,需要限定范圍
1>QAxObject *user_rang = this->sheet->querySubObject("Rang(const QString&)", "A1:D100");
寫入數據
1> rang->setProperty("Value", var);
4.3 簡單的范例
1 // HRESULT r = OleInitialize(0); 2 // if(r != S_OK && r != S_FALSE) 3 // { 4 //qWaring("Qt:初始化Ole 失敗(error %x)", (unsigned int)r); 5 //} 6 QString filename = "e:/123.xlsx"; //具體路徑 7 QFile file(filename); 8 bool isExit = file.exists(); 9 if(!isExit) 10 return false; 11 qDebug()<<"isExit"<<isExit; 12 qDebug()<<filename; 13 QAxObject *excel = new QAxObject("Excel.Application"); 14 excel->dynamicCall("SetVisible(bool Visble)", "false"); 15 excel->setProperty("DisplayAlerts", false); 16 QAxObject *workbooks = excel->querySubObject("WorkBooks"); 17 QAxObject *workbook = workbooks->querySubObject("Open(const QString&)", filename); 18 QAxObject *worksheets = workbook->querySubObject("Sheets"); 19 QAxObject *worksheet = worksheets->querySubObject("Item(int)", 1); 20 21 //寫入到指定位置 22 QAxObject *workrang = worksheet->querySubObject("Cells(int, int)", 5, 1); 23 //不能這么存 24 workrang->dynamicCall("SetValue(const QString&)", QString("1ssssssfffssssssssssssssssssssssssssssss10987654321")); 25 26 27 //讀取出來並打印 28 QAxObject *workrang1 = worksheet->querySubObject("Cells(int,int)", 3, 5); 29 30 QVariant var = workrang1->dynamicCall("Value"); 31 qDebug()<<var; 32 qDebug()<<var.toDouble(); 33 34 //另存保存 35 //workbook->dynamicCall("SaveAs(const QString&)", 36 // QDir::toNativeSeparators(filename)); 37 38 workbook->dynamicCall("Save()", true); 39 //關閉文件 40 workbook->dynamicCall("Close(Boolean)", true); 41 excel->dynamicCall("Quit()"); 42 delete excel; 43 excel = NULL; 44 // OleUninitialize();
4.4 關於權限配置
1):在服務器上安裝office的Excel軟件.
2):在"開始"->"運行"中輸入dcomcnfg.exe啟動"組件服務" ,win7 64 可以通過在運行里面輸入 comexp.msc -32 來打開32位的組件服務,在里就能看到excel組件了
3):依次雙擊"組件服務"->"計算機"->"我的電腦"->"DCOM配置"
4):在"DCOM配置"中找到"Microsoft Excel 應用程序",在它上面點擊右鍵,然后點擊"屬性",彈出"Microsoft Excel 應用程序屬性"對話框
5):點擊"標識"標簽,選擇"交互式用戶
6):點擊"安全"標簽,在"啟動和激活權限"上點擊"自定義",然后點擊對應的"編輯"按鈕,在彈出的"安全性"對話框中填加一個"NETWORK SERVICE"用戶
(注意要選擇本計算機名),並給它賦予"本地啟動"和"本地激活"權限.
7):依然是"安全"標簽,在"訪問權限"上點擊"自定義",然后點擊"編輯",在彈出的"安全性"對話框中也填加一個"NETWORK SERVICE"用戶,然后賦予"本地訪問"權限.
8).如果交互式用戶設置后出現錯誤8000401a,可取消交互式用戶,指定為administratr,可暫時解決此問題。進一步的解決方式還有待探討
9).采用第8點的設置后,打開Excel可能會出現“無法使用對象引用或鏈接”,並且不能進行單元格粘貼。原因不明,取消設置后即可消失。
4.5 關於在分線程中調用QAXObject
請首先初始化COM
代碼:
1 HRESULT r = OleInitialize(0); 2 if(r != S_OK && r != S_FALSE) 3 { 4 qWaring("Qt:初始化Ole 失敗(error %x)", (unsigned int)r); 5 } 6 OleUninitialize();
2018-08-06 00:22:30
