qt之QActiveX

首先说明的是,我所用的是vs2013和qt5.3.1。
最近在做一个项目,是把三维地球整体放置到网页端,而这就需要用到了QT中的QActiveX。
对于QActiveX我们首要明白的一点是:它主要有两个模块:QAxContainer和QAxServer。对于这两个模块的分类,我有我自己的理解:先说QAxServer吧。
QAxServer:就相当于我新建立了一个ActiveX的项目,把这个三维的项目放置到这个ActiveX的项目里,然后封装成一个COM组件(也就是exe或者dlll);
QAxContainer:相当于我新建立了一个工程,把这个ActiveX组件加载到这个工程里来使用。

而对于我来说,我主要就是要把三维项目打包成ActiveX插件供网页端来使用。下面说说我实现的步骤:

1.新建一个Qt5的工程,选择菜单里面的ActiveQt Server这样就新建立了一个ActiveX的工程。

2.对于想要绕开安全验证的同志们,我们可以使用IObejctSafety来进行设置,具体的方法是:

virtual QAxAggregated * createAggregate();//这个虚方法是QAxBindable的虚方法,QAxBindable在工程建立的时候会自动生成。

QAxAggregated * AxGm3ds::createAggregate()
{
    return new ObjectSafetyImpl;//ObjectSafetyImpl只需要一个头文件,我在下面已经写了
}

ObjectSafetyImpl.h

#include <QAxAggregated>
#include <objsafe.h>
#include <QUuid>

class ObjectSafetyImpl : public QAxAggregated, public IObjectSafety
{
public:
    ObjectSafetyImpl() {}

    QAXAGG_IUNKNOWN;

    long queryInterface(const QUuid &iid, void **iface)
    {
        *iface = 0;
        if (iid == IID_IObjectSafety)
            *iface = (IObjectSafety*)this;
        else
            return E_NOINTERFACE;

        AddRef();
        return S_OK;
    }

    HRESULT WINAPI GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
    {
        *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACESAFE_FOR_UNTRUSTED_CALLER;
        *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACESAFE_FOR_UNTRUSTED_CALLER;
        return S_OK;
    }

    HRESULT WINAPI SetInterfaceSafetyOptions(REFIID riid, DWORD pdwSupportedOptions, DWORD pdwEnabledOptions)
    {
        return S_OK;
    }
};

其实到这个时候,基本的功能都已经实现了,下面我把代码全都粘贴出来,依次为大家讲解,事先声明,我做的很简单。

AxGm3ds.h

#ifndef AXGM3DS_H
#define AXGM3DS_H

#include <QtWidgets/QWidget>
#include <ActiveQt/QAxBindable>
#include <QMainWindow>
#include "Platform.h"

#include "ui_axgm3ds.h"

class AxGm3ds : public QMainWindow, public QAxBindable
{
    Q_OBJECT

public:
    AxGm3ds(QWidget *parent = 0);
    virtual QAxAggregated * createAggregate();

signals:
    //事件
    void eventMessageOccurred(QString message);
    void eventCameraPosChanged(double lon, double lat, double height);

    //ActiveX供外界调用的方法--------------------------------------------------------------------
    public slots:
    //错误处理类
    int Error_GetErrorCode();
    QString Error_GetErrorMessage();

    //向三维发送消息
    void Common_SendMessage(QString message);

    //相机操作类
    void Camera_FlyTo(QString id);
    void Camera_FlyToByRadian(double dLongitude, double dLatitude, double dHeight);
    void Camera_FlyToByDegree(double dLongitude, double dLatitude, double dHeight);

    //三维实体定位类
    void Locating_LocateById(QString strId);
    void Locating_LocateByFilter(QString strFilter);

    //三维实体选择类
    QString Selection_GetSelectedObjects();
    QString Selection_GetSelectionByScreenPoint(int x, int y);
    QString Selection_GetSelectionByScreenRect(int left, int top, int right, int bottom);
    QString Selection_GetSelectionByFilter(QString strFilter);
    void Selection_SelectObjectById(QString strId);
    void Selection_SetSelectEffect(QString strSelectionEffect);
    QString Selection_GetSelectEffect();

    //漫游控制类
    void Roaming_SetCurrentRoaming(QString strRoamingName,int nPathIndex);
    void Roaming_Play();
    void Roaming_Stop();
    void Roaming_Pause();

    //场景天空类
    void Sky_SetDateTime(QString strDateTime);
    void SKY_SetWeather(QString strWeatherType, int nTensity);

    //场景地形类
    void Terrain_SetTerrainOpacity(double dOpacity);
    void Terrain_ModifyTerrainByRect(double dLeft, double dTop, double dRight, double dBottom, double dDepth);
    void Terrain_ModifyTerrainByVertexes(QString strVertexesByRadian, double dDepth);

    //系统Action调用类
    void Action_Invoke(QString strActionName);

    //End

    private slots:
    virtual void showEvent(QShowEvent *);
    void onPlatformEvent(ea::IEventAdapter *pEventAdapter, ea::IEventObject *pEventObject);

private:
    void attachEventStub();

private:
    Ui::AxGm3dsClass ui;
    bool m_bEventStubAttached;
};

#endif // AXGM3DS_H

AxGm3ds.cpp

#include "axgm3ds.h"

#include <ActiveQt/QAxFactory>
#include "../Application/launcher.h"
#include "objectsafetyimpl.h"
#include <QMainWindow>
#include <iostream>
#include <QMessageBox>
#include "../AppEnv/sceneenv.h"
#include "../PlatformHolder/EventReceiver.h"
#include "../ServicesImp/CameraHelper.h"
#include "../CommonUtility/FileUtils.h"
#include <QDir>
#include "../ServicesImp/CameraHelper.h"
#include "../ServicesImp/ErrorHelper.h"
#include "../ServicesImp/ObjectLocatingHelper.h"
#include "../ServicesImp/ObjectSelectionHelper.h"
#include "../ServicesImp/RoamingHelper.h"
#include "../ServicesImp/SkyHelper.h"
#include "../ServicesImp/SystemActionHelper.h"
#include "../ServicesImp/TerrainHelper.h"

AxGm3ds::AxGm3ds(QWidget *parent)
: QMainWindow(parent), m_bEventStubAttached(false)
{
    Launcher::instance()->setApplicationEntryType(AET_WebBrowser);
    Launcher::instance()->init(qApp);
}

//绕过安全验证
QAxAggregated * AxGm3ds::createAggregate()
{
    return new ObjectSafetyImpl;
}

void AxGm3ds::attachEventStub()
{
    if (m_bEventStubAttached) return;
    EventReceiver* reciever = SceneEnv::instance()->getEventReceiver();
    if (!reciever) return;
    connect(reciever, SIGNAL(signalEventOccurred(ea::IEventAdapter*, ea::IEventObject*)), this, SLOT(onPlatformEvent(ea::IEventAdapter*, ea::IEventObject*)));
    m_bEventStubAttached = true;
}

void AxGm3ds::showEvent(QShowEvent *)
{
    this->setCentralWidget(Launcher::instance()->action());
    attachEventStub();
}

void AxGm3ds::onPlatformEvent(ea::IEventAdapter *pEventAdapter, ea::IEventObject *pEventObject)
{
    if (pEventObject->getAction() == ea::ACTION_SCENE_INFO)
    {
        cmm::variant_data data;
        pEventObject->getExtra("CameraCoord", data);
        std::vector<double> point = data;

        if (point.size() == 3)
        {
            emit eventCameraPosChanged(
                cmm::math::Radians2Degrees(point[0]),
                cmm::math::Radians2Degrees(point[1]),
                cmm::math::Radians2Degrees(point[2]));
        }
    }
}

//Class:类
//IIDClass:类ID的标识
//IIDInterface:接口ID的标识
//IIDEvents:事件ID的标识
//IIDTypeLib:类型库的输出ID标识
//IIDApp:
QAXFACTORY_DEFAULT(AxGm3ds,
    "{22F6B469-A701-4A1B-9CB2-8CD85C3021CD}",
    "{48107DA9-41A3-4E61-BBA6-CD1933C89079}",
    "{8D72F8C4-CCD3-46A7-B79C-CA9247327C4D}",
    "{36548113-FB7A-4F75-9522-EB11995447D6}",
    "{122099DF-8646-44F3-B718-E46559788B7E}")

//-------------------------------------------------------ActiveX外部方法-----------------------------------------------------------------

void AxGm3ds::Common_SendMessage(QString message)
{
    QMessageBox::information(this, "ShowBy QtActiveX", QStringLiteral("收到外部消息:") + message);

    //to do 

    emit eventMessageOccurred(QStringLiteral("消息[") + message + QStringLiteral("]处理完成"));
}

int AxGm3ds::Error_GetErrorCode()
{
    return ErrorHelper::getErrorType();
}

QString AxGm3ds::Error_GetErrorMessage()
{
    return ErrorHelper::getErrorMessage();
}

void AxGm3ds::Camera_FlyTo(QString id)
{
    CameraHelper::flyTo(id);
}

void AxGm3ds::Camera_FlyToByRadian(double dLongitude, double dLatitude, double dHeight)
{
    CameraHelper::flyToByRad(dLongitude, dLatitude, dHeight);
}

void AxGm3ds::Camera_FlyToByDegree(double dLongitude, double dLatitude, double dHeight)
{
    CameraHelper::flyToByDegree(dLongitude, dLatitude, dHeight);
}

void AxGm3ds::Locating_LocateById(QString strId)
{
    ObjectLocatingHelper::locatingById(strId);
}

void AxGm3ds::Locating_LocateByFilter(QString strFilter)
{
    ObjectLocatingHelper::locatingByFilter(strFilter);
}

QString AxGm3ds::Selection_GetSelectedObjects()
{
    return ObjectSelectionHelper::getSelectedObjects();
}

QString AxGm3ds::Selection_GetSelectionByScreenPoint(int x, int y)
{
    return ObjectSelectionHelper::getSelectionByScreenPoint(x, y);
}

QString AxGm3ds::Selection_GetSelectionByScreenRect(int left, int top, int right, int bottom)
{
    return ObjectSelectionHelper::getSelectionByScreenRect(left, top, right, bottom);
}

QString AxGm3ds::Selection_GetSelectionByFilter(QString strFilter)
{
    return ObjectSelectionHelper::getSelectionByFilter(strFilter);
}

void AxGm3ds::Selection_SelectObjectById(QString strId)
{
    ObjectSelectionHelper::selectObjectById(strId);
}

void AxGm3ds::Selection_SetSelectEffect(QString strSelectionEffect)
{
    ObjectSelectionHelper::setSelectEffect(strSelectionEffect);
}

QString AxGm3ds::Selection_GetSelectEffect()
{
    return ObjectSelectionHelper::getSelectEffect();
}

void AxGm3ds::Roaming_SetCurrentRoaming(QString strRoamingName,int nPathIndex)
{
    RoamingHelper::setCurrentRoaming(strRoamingName,nPathIndex);
}

void AxGm3ds::Roaming_Play()
{
    RoamingHelper::play();
}

void AxGm3ds::Roaming_Stop()
{
    RoamingHelper::stop();
}

void AxGm3ds::Roaming_Pause()
{
    RoamingHelper::pause();
}

void AxGm3ds::Sky_SetDateTime(QString strDateTime)
{
    SkyHelper::setDateTime(strDateTime);
}

void AxGm3ds::SKY_SetWeather(QString strWeatherType, int nTensity)
{
    SkyHelper::setWeather(strWeatherType, nTensity);
}

void AxGm3ds::Terrain_SetTerrainOpacity(double dOpacity)
{
    TerrainHelper::setTerrainOpacity(dOpacity);
}

void AxGm3ds::Terrain_ModifyTerrainByRect(double dLeft, double dTop, double dRight, double dBottom, double dDepth)
{
    TerrainHelper::modifyTerrain(dLeft, dTop, dRight, dBottom, dDepth);
}

void AxGm3ds::Terrain_ModifyTerrainByVertexes(QString strVertexesByRadian, double dDepth)
{
    TerrainHelper::modifyTerrain(strVertexesByRadian, dDepth);
}

void AxGm3ds::Action_Invoke(QString strActionName)
{
    SystemActionHelper::invoke(strActionName);
}

这样我们该写的都写了,下面我们就需要在网页中调用这个COM组件了,我所使用的是调用它的dll。在调用之前我们需要先把这个dll给注册了,注册的方法就是以管理员的身份打开命令窗口,输入regsvr32 C:\Users\Administrator\Documents\Visual Studio 2013\Projects\testActiveX\Win32\Debug\VShow.dll 我十分建议当我们输入dll的时候要用绝对路径,防止出现一些不必要的错误。同时,我需要提醒的是,这个dll依赖很多东西,我们选择的绝对路径,最好就是项目生成dll时候的那个路径,此外,当我们移动这个dll的位置的时候,我们需要重新注册,不然,你的浏览器是不可能打开的,对了,一定要使用IE浏览器,你可以试一下其它浏览器,会给你一个惊喜。

在注册完了之后,我们就要用JavaScript来写触发ActiveX的网页了。话不多说,直接上代码:

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio">
<TITLE></TITLE> 
</HEAD>
<BODY> 
     定位权利人:<input type="text" name="editOwner"><input type="button" value="定位" onclick="locate(editOwner.value);">  
     分层分户: 
     <input type="button" value="第二层带线框" onclick="layerDoor(1, -1,true);"> 
     <input type="button" value="第三层第二户" onclick="layerDoor(2, 1,false);"> 
     <input type="button" value="重置" onclick="layerDoor(-1, -1,false);"> 
     <br/> 
     二维发送消息给三维:<input type="text" name="edit1" style="width:500px" value="示例数据"> <input type="button" value="发送"  onclick="sendMessageTo3D(edit1.value);">  
     二维接收三维的消息:<input type="text" name="edit2" style="width:500px"> 
     <br/> 
     三维视点已变化:经度<input type="text" name="editLonCur"> 纬度<input type="text" name="editLatCur"> 高度<input type="text" name="editHeightCur"> 
     设置三维视点:经度<input type="text" name="editLon"> 纬度<input type="text" name="editLat"> 高度<input type="text" name="editHeight"> 
     <input type="button" value="设置" onclick="setCameraPos(117,45,0);">  


    <!--<object id="ax" width="100%" height="96%" classid="CLSID:22F6B469-A701-4A1B-9CB2-8CD85C3021CD"></object>-->
    <object id="ax" width="100%" height="96%" classid="CLSID:22F6B469-A701-4A1B-9CB2-8CD85C3021CD"></object>

    <script type="text/javascript">
        var axObject = document.getElementById('ax');
        function sendMessageTo3D(message) {
            axObject.Common_SendMessage(message);
        }
        function setCameraPos(lon, lat, height) {
            axObject.Camera_FlyToByDegree(lon, lat, height);
        }
        function ax::cameraPosChanged(lon, lat, height) {
            editLonCur.value = lon;
            editLatCur.value = lat;
            editHeightCur.value = height;
        }
    </script>
</BODY> 
</HTML>

从这个JS的文件中,我告诉你们ActiveX是如何触发的,主要就是:

    <object id="ax" width="100%" height="96%" classid="CLSID:22F6B469-A701-4A1B-9CB2-8CD85C3021CD"></object>

要想触发ActiveX,需要在js文件中写,id也是必须的,classID是这个ActiveX的生成ID,这个东西在你建立一个ActiveX的时候,会自动生成,我上面的代码中有,你可以看看。

好了,我写的就是这么简单,希望对你们有帮助。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值