QT ActiveX和读取EXCEL

ActiveX,自己的理解为调用接口,用别人写好的软件。具体概念可以查看:

1.百度安全验证

2.Qt编写activex控件在网页中运行_feiyangqingyun的博客-CSDN博客

3.ActiveX基础——什么是ActiveX - Jingu - 博客园

4.ActiveX组件开发和使用_eldn__的博客-CSDN博客_activex组件

ActiveX在QT有3个模块:1.Active Qt。在Windows上提供ActiveX和COM的集成2.Building ActiveX servers in Qt一个仅用于windows的静态库,用于将Qt二进制文件转换为COM服务器3.在Qt中使用ActiveX控件和COM一个仅用于访问ActiveX控件和COM对象的窗口扩展。

Active Qt

Qt的ActiveX和COM支持允许Qt为Windows开发人员:

1.访问和使用任何ActiveX服务器在其Qt应用程序中提供的ActiveX控件和COM对象。

2.使他们的Qt应用程序作为COM服务器可用,任意数量的Qt对象和小部件作为COM对象和ActiveX控件。

ActiveQt框架由两个模块组成:

1.QAxContainer模块是一个实现QObject和QWidget子类的静态库,QAxObject和QAxWidget充当COM对象和ActiveX控件的容器。

2.QAxServer模块是一个静态库,它实现了进程内和可执行COM服务器的功能。此模块提供qaxaggregate、QAxBindable和QAxFactory类。

QT提供了一组工具来简化使用ActiveX的Qt项目的开发和构建。要构建静态库,请切换到activeqt目录(通常是QTDIR/src/activeqt),并在容器和控件子目录中运行qmake和make工具。库qaxcontainer。自由和qaxserver。lib将被链接到QTDIR/lib。如果您正在使用Qt的共享配置,请输入plugin子目录并运行qmake和make工具来构建一个将QAxContainer模块集成到Qt Designer中的插件。

以下工具支持Qt与ActiveX组件的集成。

IDC - The Interface Description Compiler (ActiveQt)
The dumpcpp Tool (ActiveQt)
The dumpdoc Tool (ActiveQt)
testcon - An ActiveX Test Container (ActiveQt)

在Qt中使用ActiveX控件和COM

QAxContainer模块是ActiveQt框架的一部分。它提供了一个实现QWidget子类QAxWidget的库,QAxWidget充当ActiveX控件的容器,QObject子类QAxObject可用于轻松访问非可视COM对象。通过QAxScript、QAxScriptManager和QAxScriptEngine类,可以使用这些类来编写嵌入COM对象的脚本,并且一组工具可以使以编程方式访问COM对象变得很容易。

该模块由六个类组成:

1.QAxBase是一个抽象类,它提供了一个API来初始化和访问COM对象或ActiveX控件。

2.QAxObject提供了一个封装COM对象的QObject。

3.QAxWidget是一个包装ActiveX控件的QWidget。

4.QAxScriptManager、QAxScript和QAxScriptEngine为Windows脚本主机提供一个接口。

1.Using the Library

QAxContainer库是静态的,因此在使用这个模块时不需要重新分发任何额外的文件。但是请注意,您正在使用的ActiveX服务器二进制文件可能没有安装在目标系统上,因此您必须将它们与包一起发布,并在应用程序的安装过程中注册它们。

2.Instantiating COM Objects

要实例化COM对象,可以使用QAxBase::setControl() API,或者直接将对象的名称传递到正在使用的QAxBase子类的构造函数中。可以用多种格式指定控件,但是最快和最强大的格式是直接使用对象的类ID (CLSID)。类ID可以使用有关对象应该在其上运行的远程机器的信息作为前缀,还可以包含用于已授权控件的许可密钥。

ActiveQt在运行时遇到错误情况时将错误消息打印到调试输出。通常,您必须在调试器中运行程序才能看到这些消息(例如,在Visual Studio的调试输出中)。

无法实例化请求的控件:在QAxBase::setControl()中请求的控件未安装在此系统上,或当前用户无法访问。
该控件可能需要管理员权限或许可证密钥。如果该控件已获得许可,则将许可密钥传递给QAxBase::setControl作为文档。

3.Accessing the Object API

ActiveQt为COM对象提供了一个Qt API,并将COM数据类型替换为Qt对等物。
在COM对象上调用api有四种方法:

1.生成一个c++名称空间
2.Call-by-name
3.通过脚本引擎
4.使用本机COM接口

生成一个c++名称空间

要为要访问的类型库生成c++名称空间,请使用dumpcpp工具。在您想要使用的类型库上手动运行这个工具,或者通过将类型库添加到您的应用程序的.pro文件中的TYPELIBS变量来将其集成到构建系统中:

注意,dumpcpp可能无法公开类型库中的所有api。
在代码中包含结果头文件,以便通过生成的c++类访问对象api。有关更多信息,请参见Qutlook示例。

Call-by-Name

使用QAxBase::dynamicCall()和QAxBase::querySubObject()以及QObject::setProperty()和QObject::property() api通过它们的名称来调用COM对象的方法和属性。使用dumpdoc工具获取任何COM对象及其子对象的Qt API文档;注意,并非所有COM对象的api都可用。

有关更多信息,请参见Webbrowser示例。

通过脚本引擎调用函数

Qt应用程序可以在系统上安装任何ActiveScript引擎。然后脚本引擎可以运行访问COM对象的脚本代码。
要实例化脚本引擎,请使用QAxScriptManager::addObject()来注册希望从脚本访问的COM对象,并使用QAxScriptManager::load()将脚本代码加载到引擎中。然后使用QAxScriptManager::call()或QAxScript::call()调用脚本函数。
通过脚本可以使用COM对象的哪些api取决于使用的脚本语言。
ActiveX测试容器演示了脚本文件的加载。

使用本机COM接口调用函数

要调用无法通过上述任何方法访问的COM对象的函数,可以使用QAxBase::queryInterface()直接请求COM接口。要获得相应接口类的c++定义,请使用该控件提供的类型库中的#import指令;有关详细信息,请参阅编译器手册。

ActiveQt在运行时遇到错误情况时将错误消息打印到调试输出。通常,您必须在调试器中运行程序才能看到这些消息(例如,在Visual Studio的调试输出中)。

QAxBase::internalInvoke:没有这样的方法——QAxBase::dynamicCall()失败了——函数原型与对象的API中可用的任何函数都不匹配。
调用IDispatch成员:非可选参数缺少QAxBase::dynamicCall()失败——函数原型是正确的,但是提供的参数太少了。
调用IDispatch成员:参数n的类型不匹配QAxBase::dynamicCall()失败-函数原型是正确的,但是索引n的参数类型错误,不能强制转换为正确的类型。
调用():没有脚本提供这个函数,你试图调用一个函数,它是通过一个不提供自省的引擎提供的。ActivePython或ActivePerl)。您需要直接在各自的QAxScript对象上调用该函数。

QAxObject 

QAxObject类提供了一个封装COM对象的QObject。可以将QAxObject实例化为空对象,使用它应该包装的COM对象的名称,或者使用表示现有COM对象的IUnknown指针。如果COM对象实现了IDispatch接口,则该对象的属性、方法和事件将作为Qt属性、插槽和信号可用。基类QAxBase提供了一个API,可以通过IUnknown指针直接访问COM对象。

QAxObject是一个QObject,可以这样使用,例如,它可以被组织在一个对象层次结构中,接收事件并连接到信号和插槽。

QAxObject还从QAxBase继承了大部分与activex相关的功能,尤其是dynamicCall()和querySubObject()。

警告:您可以子类化QAxObject,但是您不能在子类中使用Q_OBJECT宏(生成的moc文件不会编译),因此您不能添加更多的信号、插槽或属性。这个限制是由于运行时生成的元对象信息造成的。要解决此问题,请将QAxObject聚合为QObject子类的成员。

//实例

 excel = new QAxObject("Excel.Application")//创建一个Excel.Application的COM目标对象。

dynamicCall调用COM对象的方法函数,所有参数都作为字符串传递;它取决于控件是否正确地解释了它们,并且比使用具有正确类型参数的原型要慢。请注意,使用QObject::property()和QObject::setProperty()获取和设置属性要快一些。ActiveQt将不验证参数。

 QObject::setProperty //将对象的name属性的值设置为value。

querySubObject//返回一个指向包装方法或属性名提供的COM对象的QAxObject的指针,传递参数var1、var1、var2、var3、var4、var5、var6、var7和var8。启用COM的应用程序通常有一个对象模型,将应用程序的某些元素发布为调度接口。使用此方法导航对象模型的层次结构,在子线程中操作excel会报错,参考:QT操作Excel时将读写功能置于子线程内存报错解决方案_qinpanke的博客-CSDN博客

例如

EXCEL读取

bool ExcelManger::Test(QString &path)
{
    QAxObject *excel = NULL;    //本例中,excel设定为Excel文件的操作对象
    QAxObject *workbooks = NULL;
    QAxObject *workbook = NULL;  //Excel操作对象
    excel = new QAxObject("Excel.Application");
    excel->setProperty("EnableEvents", false);
    excel->dynamicCall("SetVisible(bool)", false); //true 表示操作文件时可见,false表示为不可见
    
    workbooks = excel->querySubObject("WorkBooks");


    //————————————————按文件路径打开文件————————————————————
    workbook = workbooks->querySubObject("Open(QString&)", path);
    // 获取打开的excel文件中所有的工作sheet
    QAxObject * worksheets = workbook->querySubObject("WorkSheets");


    //—————————————————Excel文件中表的个数:——————————————————
    int iWorkSheet = worksheets->property("Count").toInt();
    qDebug() << QString("Excel文件中表的个数: %1").arg(QString::number(iWorkSheet));


    // ————————————————获取第n个工作表 querySubObject("Item(int)", n);——————————
    QAxObject * worksheet = worksheets->querySubObject("Item(int)", 1);//本例获取第一个,最后参数填1


    //—————————获取该sheet的数据范围(可以理解为有数据的矩形区域)————
    QAxObject * usedrange = worksheet->querySubObject("UsedRange");

    //———————————————————获取行数———————————————
    QAxObject * rows = usedrange->querySubObject("Rows");
    int iRows = rows->property("Count").toInt();
    qDebug() << QString("行数为: %1").arg(QString::number(iRows));

    //————————————获取列数—————————
    QAxObject * columns = usedrange->querySubObject("Columns");
    int iColumns = columns->property("Count").toInt();
    qDebug() << QString("列数为: %1").arg(QString::number(iColumns));

    //————————数据的起始行———
    int iStartRow = rows->property("Row").toInt();
    qDebug() << QString("起始行为: %1").arg(QString::number(iStartRow));

    //————————数据的起始列————————————
    int iColumn = columns->property("Column").toInt();
    qDebug() << QString("起始列为: %1").arg(QString::number(iColumn));


    //——————————————读出数据—————————————
    //获取第i行第j列的数据
    //假如是第6行,第6列 对应表中F列6行,即F6
    QAxObject *range1 = worksheet->querySubObject("Range(QString)", "F6:F6");
    QString strRow6Col6 = "";
    strRow6Col6 = range1->property("Value").toString();
    qDebug() << "第6行,第6列的数据为:" + strRow6Col6;

    //待添加一个转换函数,即第6行,第6列,66转为F6


    //—————————————写入数据—————————————
    //获取F6的位置
    QAxObject *range2 = worksheet->querySubObject("Range(QString)", "F6:F6");
    //写入数据, 第6行,第6列
    range2->setProperty("Value", "中共十九大");
    QString newStr = "";
    newStr = range2->property("Value").toString();
    qDebug() << "写入数据后,第6行,第6列的数据为:" + newStr;

    //!!!!!!!一定要记得close,不然系统进程里会出现n个EXCEL.EXE进程
    workbook->dynamicCall("Save()");
    workbook->dynamicCall("Close()");
    excel->dynamicCall("Quit()");
    if (excel)
    {
        delete excel;
        excel = NULL;
    }

    return true;
}
读写excel在此基础上扩充。

补充

office要是没激活,使用excel保存的时候,有时候程序会挂。此时要是没激活比较麻烦,可采用CSV存储,用excel打开。

有些时候,比如杀毒软件等等的策略,导致QAxObject方式读写Excel怎么样都不行。这时候可以使用github上的一个接口。Github链接

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值