• Qt+ArcGIS Engine 10.1 开发(一)


    Qt作为一个跨平台C++图形用户界面应用程序开发框架,相当于微软的MFC(只能运行在Windows平台上),Qt命运多舛,几经易主,现在属于芬兰IT服务公司Digia。

    1. Qt环境安装

    Qt的最新版本是Qt5.0,该版本是在12月中旬发布的,在这里我用的是Qt4.8。1版本,也不建议大家着急着用最新版本,关于软件的下载地址可以在下面找到。

    http://download.qt.nokia.com/qt/source/

    http://qt-project.org/downloads#qt-other

    安装过程很单,只需要点击下一部即可。

    因为我采用的是VS2010作为Qt的集成开发环境,整个开发环境需要下载两个软件

    http://download.qt.nokia.com/qt/source/qt-win-opensource-4.8.1-vs2010.exe

    http://releases.qt-project.org/vsaddin/qt-vs-addin-1.1.11-opensource.exe

     

    说明:

    如果有人不愿意这么做,还可以使用QtCreator以及qt-win-opensource-4.8.1-mingw.exe的组合,因为新版本的QtCreator已经不包含mingw,所以要单独下载。

     

    1. Qt的第一个程序

    安装完后,需要配置几个环境变量,QMAKESPE(根据自己的情况配置,因为我用的是VS2010,所有配置win32-msvc2010),如下图:

    QTDIR(Qt的安装目录),如下图:

    在Path中添加Qt的bin目录如下图:

    打开VS2010,新建工程可以找到Qt4 的模板:

     

     

    完成之后,在VS中运行,出现下面的界面,因为我们什么都没做,在弹出的界面上什么都没有,不过没关系,只要能出现,就说明我们的Qt已经可以使用了,如下图:

     

    1. ArcGIS Engine的环境

    安装ArcGIS ArcObjects for Cross Platform C++ 的SDK,这个没有什么好说的。

    1. ArcGIS Engine+Qt(控制台开发)

    安装了SDK之后,我们就需要将ArcGIS Engine的类库等引入到开发环境中,在Qt中引入ArcGIS Engine的类库等信息.在新建立的Qt控制台程序工程右键,找到C/C++,然后找到常规,在右侧的附加包含目录中输入下面三个目录的地址(因为我的有x(86),所以出现了下面的特殊符号):

    说明:在MFC中我们除了引入三个目录地址,还配置了预处理器定义"ESRI_WINDOW",在这里我并没有配置。

    配置好这个之后,在主程序文件中输入代码(这个代码我在这里就不做解释,到时候可以看这个文档的姊妹篇- 《VC2010+ArcGIS Engine10.1开发》

    ,最后效果如下:

    #include <QtCore/QCoreApplication>

    #include "ArcSDK.h"

    #include "qtextstream.h"

    int main(int argc, char *argv[])

    {

        ::CoInitialize(NULL);

    #pragma region 绑定许可

        IArcGISVersionPtr ipVer(__uuidof(VersionManager));

        VARIANT_BOOL succeeded;

        if (FAILED(ipVer->LoadVersion(esriArcGISEngine , L"10.1",&succeeded)))

            return 0;

    #pragma endregion

        //

    #pragma region 初始化许可

        IAoInitializePtr ipInit(CLSID_AoInitialize);

        esriLicenseStatus status;

        ipInit->Initialize(esriLicenseProductCodeEngine, &status);

        if (status != esriLicenseCheckedOut)

        {

            AoExit(0);

            return 0;

        }

            

    #pragma endregion

        QCoreApplication a(argc, argv);

    #pragma region 打开工作空间

        IWorkspaceFactoryPtr ipWorkspaceFactory(CLSID_ShapefileWorkspaceFactory);

        IWorkspacePtr pWs;

        BSTR bstr_str;

        QString q_str="D:\\guest\\chinasimplify";

            bstr_str = SysAllocString(q_str.utf16());

        HRESULT hr=ipWorkspaceFactory->OpenFromFile(bstr_str,0,&pWs);

        SysFreeString(bstr_str);

        QString q_str1="china_simply.shp";

            BSTR bStringWS=SysAllocString(q_str1.utf16());

        if (FAILED(hr))

        {

            return 0;

        }

    #pragma endregion

    #pragma region QI 这里和NET下不一样

        IFeatureWorkspacePtr ipRastWork (pWs);

    #pragma endregion

    #pragma region 打开要素类并获取个数

        IFeatureClassPtr pFtClass;

        hr=ipRastWork->OpenFeatureClass(bStringWS,&pFtClass);

        SysFreeString(bStringWS);

        if (FAILED(hr))

        {

            return 0;

        }

        long pCount=0;

        pFtClass->FeatureCount(NULL,&pCount);

    #pragma endregion

         QString s = QString::number(pCount, 10);

         QTextStream cout(stdout);

         cout<<s<< endl;

         QString str;

         QTextStream in(stdin);

         in >> str;

        return a.exec();

    }

     

    运行后可以看到下面的效果

     

    1. ArcGIS Engine+Qt(GUI开发)

    在MFC中我们介绍了两种开发GUI的方法,一种是通过生成相应的Activex控件MFC类,另一种是通过插入Activex控件的方法,在Qt里面做GUI的AE开发,也有两种不同的做法,而这两种做法需要引入的头文件也有差异,除了头文件的差异,我们需要配置额外的信息,在这里我们分别对两种方法介绍。

    1. ArcGIS Engine+Qt(GUI开发,使用Esri提供的控件类)

      1. 额外的配置

    对于这种方法,需要配置很多信息,在工程项目的连接器的常规中找到SDK的lib目录(在MFC的开发中,我们应该没有这个步骤),如下图:

     

    在附加依赖项中输入qt4ctl.lib和aoctl.lib文件如下图:

     

    此外还要在环境变量中配置Path(不一定要在Path中配置,只要在运行的时候能找到相应的文件即可),要不然在运行的时候会报下面的错误,如下图:

     

    这是因为Qt的AE在运行的时候用到了Engine安装目录下的bin下的三个文件:Qt4ctl.dll, aoctl.dll, ctlbase.dll,只要将Engine的bin目录配置到Path中就可以了,如下图:

    1. Esri提供的控件类

    当这些信息配置好了,我们就可以开发出GUI程序了,在Qt中我们认为一个可视化的组件是一个QWidget,这个QWidget类似MFC中的窗体,一旦有了这些QWidget,就可以用父组件的addWdiget方法加入,Esri提供了继承这些控件QWidget的类,我们可以在qtaxtcl.h头文件中找到,如下:

    class ESRI_EXT_CLASS QAxCtl

        : public QWidget

    {

    public:

        QAxCtl(const char *progID = NULL, QWidget *parent = NULL, const char *name = NULL);

        QAxCtl(const ControlDataPtr progID, QWidget *parent = NULL, const char *name = NULL);

        ~QAxCtl();

        HRESULT getInterface(IUnknown **ppUnk);

        HRESULT setCursor(HCURSOR cur);

    protected:

        bool eventFilter(QObject *qo, QEvent *qe);

    #if defined(ESRI_UNIX)

        bool x11Event(XEvent *event);

    #endif /* ESRI_UNIX */

    private:

        char *m_sProgID;

        AxContainerPtr m_pAxCont;

        void initialize(const char *progID);

    };

    1. 代码编写

    我们将这种GUI开发的先决条件都准备好了,下来就开始一个简单的GUI,这个例子我只将TOC,Map和Toolbar三个控件添加上去,并在Toolbar上添加了几个命令和工具,完整的代码如下(功能也比较简单,界面也不好看,只是当做一个例子,大家就将就看):

    #include <stdio.h>

    #include <qapplication.h>

    #include <qpushbutton.h>

    #include <qboxlayout.h>

    #include <qsplitter.h>

    #include <ArcSDK.h>

    #include <AxCtl/qt4axctl.h>

    #include <Ao/AoControls.h>

    void add_toolbar_items(IToolbarControl* pToolbar);

    int main(int argc, char **argv)

    {

            ::CoInitialize(NULL);

    #pragma region 绑定许可

        IArcGISVersionPtr ipVer(__uuidof(VersionManager));

        VARIANT_BOOL succeeded;

        if (FAILED(ipVer->LoadVersion(esriArcGISEngine , L"10.1",&succeeded)))

            return 0;

    #pragma endregion

            IAoInitializePtr ipInit(CLSID_AoInitialize);

            esriLicenseStatus status;

            ipInit->Initialize(esriLicenseProductCodeEngine, &status);

            if (status != esriLicenseCheckedOut)

            {

                printf("Invalid Licensing.\n");

                AoExit(0);

            }

        

        QApplication qapp(argc, argv);

        QWidget window;

        window.resize(500,400);

          

        

        QVBoxLayout vbox(NULL);

        QAxCtl tlb(AoPROGID_ToolbarControl);

        tlb.setMinimumHeight(30);

        tlb.setMaximumHeight(30);

        QSplitter split;

        QAxCtl toc(AoPROGID_TOCControl);

        QAxCtl map(AoPROGID_MapControl);

        window.setLayout(&vbox);

        vbox.addWidget(&tlb);

    split.addWidget(&toc);

        split.addWidget(&map);

        vbox.addWidget(&split);

        

            IToolbarControlPtr ipToolbar;

            IMapControl3Ptr ipMap;

            ITOCControlPtr ipToc;

            HRESULT hr;

            hr = tlb.getInterface((IUnknown **)&ipToolbar);

            hr = toc.getInterface((IUnknown **)&ipToc);

            hr = map.getInterface((IUnknown **)&ipMap);

            if (ipToolbar != 0)

                ipToolbar->SetBuddyControl(ipMap);

            if (ipToc != 0)

                ipToc->SetBuddyControl(ipMap);

            add_toolbar_items(ipToolbar);

        window.show();

        qapp.exec();    

        ipInit->Shutdown();

        ::CoUninitialize();

        AoExit(0);

        return 0;

    }

    void add_toolbar_items(IToolbarControl* pToolbar)

    {

        CComVariant varTool;

        long itemindex;

        if (!pToolbar)

            return;

        varTool = L"esriControlCommands.ControlsOpenDocCommand";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsAddDataCommand";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsMapZoomInTool";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_TRUE, 0,

            esriCommandStyleIconOnly, &itemindex);

          

        

        varTool = L"esriControlCommands.ControlsMapZoomOutTool";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsMapZoomInFixedCommand";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsMapZoomOutFixedCommand";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsMapPanTool";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsMapFullExtentCommand";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsMapZoomToLastExtentBackCommand";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsMapZoomToLastExtentForwardCommand";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsSelectFeaturesTool";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

        varTool = L"esriControlCommands.ControlsSelectTool";

        pToolbar->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,

            esriCommandStyleIconOnly, &itemindex);

    }

    运行效果如下图:

    1. 小结

    这种方式跟在MFC中使用Axtivex的MFC类比较类似,都是自己实例化一个控件,然后将这个控件添加到父类控件中,但是Esri提供的这个方式,也有自己的弊端,不能调试,只能在Release版本下运行,估计是这中方式需要的几个dll,没有提供Debug版本的,如果调试,那么程序会在我们实例化控件的地方跳出去,这个问题搞了我好几天,总找不到什么原因,借助伟大的Google,最后在Esri的英文论坛中也看到类似的,论坛中在求这个dll和相关lib的debug,看到这个,我也就明白了。

    1.  
  • 相关阅读:
    .net中的委托
    GridView, DataList and ListBox 行 单击与双击事件处理
    ChineseCalendar类[转]
    数据契约(DataContract)
    XPath 语法(复习)
    正则表达式学习笔记
    瑞星笔试:现场上机做题[转]
    发送带有附件的电子邮件使用 Cdosys.dll 库
    DataContractJsonSerializer 类 操作json类型数据
    i guess a bug on Castle
  • 原文地址:https://www.cnblogs.com/zuiyirenjian/p/2843682.html
Copyright © 2020-2023  润新知