有很多的朋友在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