基于VC++的MAPX开发环的配置

有很多的朋友在VC下使用MapX的时候,总是感觉不是很顺手,其中一个很明显的问题就是老是出现COleVariant或Variant类型的数据,对于习惯了使用VC下形如CString等类型变量的朋友来说COleVariant或Variant类型给VC下使用MapX造成了很多不便;也造成了开发和调试效率很低,在数据类型上打转转。

    我这篇文章不是要告诉大家如果进行数据类型的转换,也不是来讲VC下如何使用MapX的各个功能来编写程序,而是要解决一个环境问题——帮助习惯了使用VC一般数据类型的朋友建立一个平易近人的MapX开发环境。

声明:我这篇文章只针对VC++6.0下使用MapX,以后不再加以说明。

一、”普适标准工程”

    只要安装了MapX控件,无论使用什么样的.H或.CPP文件,MapX在你的机器上就可以用来做开发使用了。

    一个使用MapX控件的”普适标准工程”就是将MapX安装目录下”/MapInfo/MapX 5.0/Samples50/C++/Cpp”文件夹下的MAPX.H和MAPX.CPP文件考到你的工程目录下,通过” Project->Add To Project->Files…”添加到工程中去就完成了。

    上面这个”普适标准工程”,会有几个比较棘手的问题出现:

    1.基于Dialog的工程中,以前可以直接从控件栏上拖下来一个MapX控件放在窗体上,还可以调整大小,设定一些初始值,”普适标准工程”无法做到了?

    2.基于Doc/View的工程下建立了一个”普适标准工程”后,如何添加一个MapX控件,并让它显示出来?如何给它添加事件响应?

    3.如何将我现有的工程转换成”普适标准工程”?

二、Dialog标准工程

    执行“Project->Add To Project->Components and Controls…”,在Components and Controls Gallary对话框中选择Mapinfo MapX 5.0控件,点击Insert并确认添加后会出现Comfirm Classes对话框:

 

    在Comfirm Classes对话框中显示出了添加MapX控件将会在我们的工程里面自动生成的所有类(包括.H和.CPP文件)。一般情况下,大家都是直接点击了确认,于是就会出现下图这样的情形:

 

    要建立Dialog的标准工程,这里不提倡上面的做法。而是采用下面的方法:除了必须添加的CCMapX类以外其他的类均不添加,具体的做法就是在点击OK前将其他类前复选框的对勾去掉,如下图:

 

    这样点击确认后就会出现下图的情形:

 

    添加完成后控件栏上就会多出一个MapX控件:

 

    接下来要做的就是从文件视图中,选中cmapx.h和cmapx.cpp两个文件,按下Delete键,将这两个文件从工程中删除;同时从工程目录下将cmapx.h和cmapx.cpp两个文件删除。删除的这两个文件其实就是支持COleVariant或Variant类型的文件,接下来要做的就是添加MAPX.H和MAPX.CPP两个文件。

 

    从MapX控件安装目录MapInfo/MapX 5.0/Samples50/C++/Cpp下找到MAPX.H和MAPX.CPP两个文件拷贝到Dialog工程目录下;通过“Project->Add To Project->Files…”添加到Dialog工程当中。此时的工程应该有如下形式:

 

    到此为止,一个Dialog标准工程就建立好了。你仍然可以从控件栏中拖下MapX控件,调整位置和大小,也可以通过属性页设置它的初始状态,还可以使用ClassWizard来给控件添加变量以及事件响应等等。但是,这个标准工程下,一般不会再出现COleVariant或Variant类型的数据了,很多地方都可以直接使用如CString这样的变量了。

三、Doc/View下如果使用MapX控件

    其实这里我说多了好多人都会笑话我的,但是基于从初学着的角度来讲还是说一点。

    MAPX是一个窗口控件,也就是它本身就是一个窗口,它跟CEdit、CComboBox这些控件是样的。要想在Doc/View中使用就必须动态创建,而MAPX控件创建的过程跟CEdit或CComboBox是没有什么区别的,只要你会在Doc/View中动态创建CEdit或CComboBox就应该会创建MAPX控件。一般都遵从这样的步骤:

    1.添加资源ID。

    这个需要在工程的资源视图下的String Table下增加一个ID,形如:    

 

    2.添加MAPX控件头文件的引用

    我一般直接把MAPX头文件的引用添加到工程的StdAfx.h文件中,这样就不必在其他的很多文件中添加这个引用了。#include MAPX.H

    3.声明CMapX类型变量

    在视图类中声明: CMapX m_ctrlMapX;

    4.使用MAPX的Creat方法,在工程中视图类创建(也可以是其他地方,但是要在视图类本身创建完成后)的时候创建MAPX控件。

    例如:

    int C**View::OnCreate(LPCREATESTRUCT lpCreateStruct) // (C**View类的WM_CREATE消息响应函数)

         {

                  if (CView::OnCreate(lpCreateStruct) == -1)        return -1;

 

                  RECT windRect;

                  GetClientRect(&windRect);       //取得视图区域

 

                  if (!m_ctrlMapX.Create(NULL, WS_VISIBLE, windRect, this,IDS_MAPX1))         return -1;

                  //这里创建的MAPX控件窗口覆盖整个视图区域

                  //这句代码用语言描述的话可以这样说:

                  //以当前视图窗口为父窗口,以IDS_MAPX1为标识,创建一个可见的、无窗口名称的、

                  //覆盖整个视图区域的MAPX控件窗口。

                  return 0;

         }

    5.设定控件的初始状态

    如果简单的创建了MAPX控件在显示的时候会显示美国的地图,这样就需要在视图出现前改变MAPX的基本设置,改变默认地图。当然进行一些其他的设置也是可以的,例如,改变地图中心、缩放率、是否可编辑、是否可选择以及添加一些新图层等等操作。

    我一般将这些初始化放在view类的OnInitialUpdate()函数中来做。例如:

    void C**View::OnInitialUpdate()

    {

                  CView::OnInitialUpdate();

 

                  //----------------加载中国地图---------------------------

                  m_ctrlMapX .SetGeoSet("CHINA.GST");

                  //-------------------------------------------------------------

                  CMapXLayers allLr= m_ctrlMapX .GetLayers();

                  //----------------- 添加现有数据图层 -----------------

                  allLr.Add("CHINAHWY.TAB");

                  allLr.Add("CHCTY_5K.TAB");

                  //--------------------------------------------------------------

 

                  //------------------添加用户绘制图层--------------------

                  CMapXLayer cusLr=allLr.AddUserDrawLayer(“userLr”,1);

                  allLr.SetAnimationLayer(cusLr.DetachDispatch());

                  //--------------------------------------------------------------

 

                  //-------------------添加一个”固定”图层-----------------        

                  CMapXLayer staLr;

                  staLr =allLr.CreateLayer(“stLrNa”,NULL, 2, 32);

                  //---------------------------------------------------------------

    }

    6.添加MAPX控件的事件响应

    很显然在Doc/View下要想像Dialog中那样通过ClassWizard来给MAPX控件添加事件响应已经不可能了。这个时候需要我们自己手动添加了。

    这里简单的扯两句,其实ClassWizard添加事件响应与我们手动添加有什么本质上的不同么?答案是没有,一模一样的。

    要正确的认识ClassWizard。ClassWizard其实就是一个助手,它只是让我们在代码生成上更加的直观,更加有效率,同时规避了一些内部必然的联系还需要我们手动来做的麻烦而已。如果我们不嫌麻烦,那么完全可以不用ClassWizard。

 

    下面是一个标准的菜单消息响应过程,这个过程主要包括四个部分:函数定义、宏声明、消息映射、函数实现.

    afx_msg void OnFileOpen();                                //H文件中函数定义

    DECLARE_MESSAGE_MAP()                            //H文件中宏声明

 

    BEGIN_MESSAGE_MAP(C**View, CView)     //CPP文件中消息映射

    //{{AFX_MSG_MAP(C**View)

    ON_COMMAND(ID_FILE_OPEN, OnFileOpen)

    //}}AFX_MSG_MAP

    END_MESSAGE_MAP()

 

    void C**View::OnFileOpen()                                //CPP文件中函数实现

    {

    }

    给动态生成的MAPX控件添加事件也需要这样一个过程,所不同的是,我们需要一个不同的宏来处理消息映射。这个不同的宏就是DECLARE_EVENTSINK_MAP()——槽事件处理宏声明。(这里不多讨论)

    我们只管照猫画虎,也弄出一个MAPX的消息响应过程来(以DrawUserLayer事件为例),如下:

    afx_msg void OnDrawUserLayerMap1 (LPDISPATCH Layer, long hOutputDC, long hAttributeDC, LPDISPATCH RectFull, LPDISPATCH RectInvalid);  

    //H文件中函数定义

    DECLARE_EVENTSINK_MAP()   //H文件中宏声明

 

    BEGIN_EVENTSINK_MAP (C**View, CView)

    //{{AFX_EVENTSINK_MAP(CMeteoCenView)

    ON_EVENT (C**View, IDS_MAP1, 10 /* DrawUserLayer */, OnDrawUserLayerMap1, VTS_DISPATCH VTS_I4 VTS_I4 VTS_DISPATCH VTS_DISPATCH)    

    //CPP文件中消息映射

    //}}AFX_EVENTSINK_MAP

    END_EVENTSINK_MAP ()

 

    void C**View::OnDrawUserLayerMap1 (LPDISPATCH Layer, long hOutputDC, long hAttributeDC, LPDISPATCH RectFull, LPDISPATCH RectInvalid) 

    //CPP文件中函数实现

    {

    }

    上面的老虎(MAPX控件)画好了,只要按照猫(菜单)的样子把各个代码分别分配到相应的位置就可以完成MAPX控件的事件响应了。

 

    主要解释一下下面这段代码的含义:

    ON_EVENT (C**View, IDS_MAP1, 10 /* DrawUserLayer */, OnDrawUserLayerMap1, VTS_DISPATCH VTS_I4 VTS_I4 VTS_DISPATCH VTS_DISPATCH)

    C**View:是MapX所在的View类。

    IDS_MAP1:是为MapX添加的窗体ID

    10 /* DrawUserLayer */:是MapX的事件代码,10表示的是DrawUserLayer事件。

    OnDrawUserLayerMap1:是DrawUserLayer事件的处理函数

    VTS_DISPATCH VTS_I4 VTS_I4 VTS_DISPATCH VTS_DISPATCH:这些是DrawUserLayer所携带的参数类型说明。

    整个这段代码的意思可以这样表述:

    当C**View接收到以IDS_MAP1标示的MapX窗体的DrawUserLayer(代码为10)事件时将通过OnDrawUserLayerMap1来处理这个事件。

    在Doc/View类型工程下使用MapX时我一般的做法是:建立一个Dialog的MAPX标准工程,使用ClassWizard给MAPX添加上所有的事件响应。然后,当我在Doc/View类型工程下需要的时候,我就去Dialog工程中所需要的事件响应过程考过去,改改ID和类名什么的就可以用了。

四、现有工程如果转到标准工程

    1.直接在文件视图中删除所有添加的以“C”打头的MAPX的.h和.cpp文件。

    2.删除工程目录下的所有自动生成的以“C”打头的MAPX的.h和.cpp文件。

    3.在整个工程中搜索”#include”,只要是还有上面这些文件的引用全部删除。

    4. 从MapX控件安装目录MapInfo/MapX 5.0/Samples50/C++/Cpp下找到MAPX.H和MAPX.CPP两个文件拷贝到工程目录下,并添加到工程当中去。

    5.在StdAfx.h文件中添加#include MAPX.H

    6.编译工程(肯定还有很多错误,一个一个往下找),将以前使用COleVariant或Variant类型以及其他不相符数据类型的地方改正过来,以前使用两个"C"打头的类换成一个"C"打头的类。(要细心,磨刀不费砍柴工!)

五、其他VC环境

    VC.net(VS2003/VS2005/VS2008)环境下MAPX的环境建立与本文所提到的方法与步骤基本相同,可以很顺利的移植过去。

六、简单对比(MapXLayer::SearchAtPoint函数)

    使用控件自动生成的文件时:SearchAtPoint第二个参数是一个VARIANT类型

    CCMapXFeatures CCMapXLayer::SearchAtPoint(LPDISPATCH Point, const VARIANT& SearchResultFlags)
        {
        LPDISPATCH pDispatch;
        static BYTE parms[] =
        VTS_DISPATCH VTS_VARIANT;
        InvokeHelper(0x1d, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,
        Point, &SearchResultFlags);
        return CCMapXFeatures(pDispatch);
        }

    使用MAPX安装目录下Demo中提供的MAPX.H和MAPX.CPP时:SearchAtPoint第二个参数是一个short类型

    CMapXFeatures CMapXLayer::SearchAtPoint(LPDISPATCH Point, short SearchResultFlags)
        {
        LPDISPATCH result;
        static BYTE parms[] =
        VTS_DISPATCH VTS_I2;
        InvokeHelper(0x1d, DISPATCH_METHOD, VT_DISPATCH, (void*)&result, parms,
        Point, SearchResultFlags);
        return CMapXFeatures(result);
        }

 

 


转至:http://blog.csdn.net/Tinary3v0/archive/2008/11/17/3321610.aspx

你可能感兴趣的:(GIS)