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.  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM