1.使用QAxObject读写Excel
QAxObject类提供了一个包裹COM对象的QObject。
QAxObject可以被实例化为一个空的对象,用它应该包裹的COM对象的名字,或者用一个指向代表现有COM对象的IUnknown的指针。如果COM对象实现了IDispatch接口,该对象的属性、方法和事件就可以作为Qt属性、槽和信号使用。基类,QAxBase,提供了一个API,可以通过IUnknown指针直接访问COM对象。
QAxObject是一个QObject,并可以作为QObject使用,例如,它可以被组织在一个对象的层次结构中,接收事件并连接到信号和槽。
QAxObject也从QAxBase继承了大部分与ActiveX相关的功能,特别是dynamicCall()和querySubObject()。
警告。你可以对QAxObject进行子类化,但是你不能在子类中使用Q_OBJECT宏(生成的moc-file将不会被编译),所以你不能进一步添加信号、槽或属性。这个限制是由于在运行时生成的元对象信息造成的。为了解决这个问题,将QAxObject聚合为QObject子类的一个成员。
也请参见QAxBase、QAxWidget、QAxScript和ActiveQt Framework。
下面是示例代码:
excelopt.h
#ifndef EXCELOPT_H
#define EXCELOPT_H
#include <QObject>
#include <QAxObject>
#include <Windows.h>
class ExcelOpt : public QObject
{
Q_OBJECT
public:
explicit ExcelOpt(QObject *parent = nullptr);
~ExcelOpt();
bool open(const QString &fileName);
bool save();
bool saveAs(const QString &fileName);
void close();
QVariant read(int row, int column);
bool write(int row, int column, const QVariant &value);
signals:
public slots:
void slots_exception(int code, const QString &source, const QString &desc, const QString &help);
private:
QAxObject *m_excel;
QAxObject *m_workbooks;
QAxObject *m_workbook;
QAxObject *m_worksheets;
QAxObject *m_worksheet;
};
#endif // EXCELOPT_H
excelopt.cpp
#include "excelopt.h"
#include <QDebug>
ExcelOpt::ExcelOpt(QObject *parent) : QObject(parent)
{
m_excel = NULL;
m_workbooks = NULL;
m_workbook = NULL;
m_worksheets = NULL;
m_worksheet = NULL;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
//HRESULT result = OleInitialize(nullptr); //换成CoInitialize似乎也是一样的
//if (result != S_OK && result != S_FALSE)
//{
// qDebug()<<QString("Could not initialize OLE (error %x)").arg(static_cast<unsigned int>(result));
//}
// 创建一个新的Excel应用程序
//m_excel = new QAxObject("Excel.Application");
m_excel = new QAxObject(this); //连接Excel控件
if (m_excel->setControl("Excel.Application"))
{
}
else
{
m_excel->setControl("ket.Application"); //连接Excel控件
}
m_excel->setProperty("Visible", false); //不显示窗体
connect(m_excel, SIGNAL(exception(int, const QString &, const QString &, const QString &)), this, SLOT(slots_exception(int, const QString &, const QString &, const QString &)));
// 获取所有工作簿
m_workbooks = m_excel->querySubObject("Workbooks");
}
ExcelOpt::~ExcelOpt()
{
// 关闭所有工作簿
m_workbooks->dynamicCall("Close()");
// 关闭Excel应用程序
m_excel->dynamicCall("Quit()");
delete m_worksheet;
delete m_worksheets;
delete m_workbook;
delete m_workbooks;
delete m_excel;
OleUninitialize();
}
bool ExcelOpt::open(const QString &fileName)
{
// 如果工作簿已打开,则先关闭它
if (m_workbook) {
m_workbook->dynamicCall("Close()");
delete m_worksheet;
delete m_worksheets;
delete m_workbook;
}
// 打开指定的工作簿
m_workbook = m_workbooks->querySubObject("Open(const QString&)", fileName);
if (!m_workbook)
return false;
// 获取所有工作表
m_worksheets = m_workbook->querySubObject("Worksheets");
if (!m_worksheets)
return false;
// 获取第一个工作表
m_worksheet = m_worksheets->querySubObject("Item(int)", 1);
if (!m_worksheet)
return false;
return true;
}
bool ExcelOpt::save()
{
if (!m_workbook)
return false;
// 保存工作簿
return m_workbook->dynamicCall("Save()").toBool();
}
bool ExcelOpt::saveAs(const QString &fileName)
{
if (!m_workbook)
return false;
// 将工作簿另存为指定的文件
return m_workbook->dynamicCall("SaveAs(const QString&)", fileName).toBool();
}
void ExcelOpt::close()
{
if (m_workbook) {
// 关闭工作簿
m_workbook->dynamicCall("Close()");
delete m_worksheet;
delete m_worksheets;
delete m_workbook;
m_worksheet = nullptr;
m_worksheets = nullptr;
m_workbook = nullptr;
}
}
QVariant ExcelOpt::read(int row, int column)
{
if (!m_worksheet)
return QVariant();
// 读取指定单元格的值
return m_worksheet->querySubObject("Cells(int,int)", row, column)->dynamicCall("Value()");
}
bool ExcelOpt::write(int row, int column, const QVariant &value)
{
if (!m_worksheet)
return false;
// 写入指定单元格的值
m_worksheet->querySubObject("Cells(int,int)", row, column)->setProperty("Value2", value);
return true;
}
void ExcelOpt::slots_exception(int code, const QString &source, const QString &desc, const QString &help)
{
}
main.cpp
#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
#include "excelopt.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ExcelOpt objExcel;
objExcel.open("C:\\Users\\roson\\Desktop\\test.xlsx");
qDebug() << objExcel.read(1, 1).toString();
objExcel.write(5, 2, QString("roson"));
qDebug() << "write finish";
objExcel.save();
QtWidgetsApplication1 w;
w.show();
return a.exec();
}
1.1 注意事项(非常重要)
(1)
运行上面的代码的时候,很可能会出现运行异常,错误信息的格式如下:
QAxBase: Error calling IDispatch member SaveAs: Exception thrown by server
Code : -2146827284
Source : Microsoft Excel
Description: Microsoft Excel ???D://24ED7000?? ???:
Help : xlmain11.chm
其中“Code”的值会因为错误类型的不同而不同,可以去网上查阅这个错误代码所指代的含义。
上面这个错误代码“-2146827284”一般是因为Excel表格文件的路径不对造成的,我们在传参时,一定要用文件的绝对路径,这样就可以有效的避免上面的错误,切记!!!
(2)
如果在程序运行时,报错QAxBase: Error calling IDispatch member ActiveSheet: Unknown error,或者Excel表格突然弹出激活、许可协议等界面,则说明你的office没有激活,用激活工具激活office后就好了
(3)
有的人会出现读取Excel内容可以成功,但是在写入数据的时候遇到了问题,写进去的东西为空。经过排查是因为office和wps的原因,主要是property的Value值的问题。
office支持的是
setProperty("Value", value)
然而要在装有wps中写入成功就需要把value属性改为Value2
setProperty("Value2", value)
Value2 wps 和 office中都可以使用。
(4)
使用QtCreator时,我们要使用QAxObject,是需要在.pro文件中添加: QT += axcontainer,使用VS开发时,也需要添加这个模块,否则编译不过的。
2.Qt Xlsx插件
QtXlsx是一个可以读取和写入Excel文件的第三方库。它不需要Microsoft Excel,可以在Qt5支持的任何平台上使用。该库可以用来:
(1)创建一个新的.xlsx文件
(2)读取.xlsx文件内容
(3)往.xlsx文件写入内容
官网:http://qtxlsx.debao.me/