在进行MapX 开发之前,确保已经在计算机中正确的安装了MapX 控件。下面就用一个具体的实例,介绍在VC+ +中集成MapX 的方法。
在您的项目中包括MapX.cpp和.h文件。这两个文件包含用于对MapX控件进行访问的类定义和方法实现。MapX.h 和 MapX.cpp 文件可能位于安装有 MapX 的 Samples50CPP 子目录中(如果您安装的事MapX 4.0,则路径为 … Samples40C++Cpp)。
利用VC++ 环境下的应用程序生成向导创建一单文档应用程序MapSample。将MapX.h和MapX.cpp文件拷贝到当前工程路径下,然后从Project菜单中选择Add to Project >Files命令,此时打开Insert Files into Project对话框,选择MapSample文件夹下的MapX.h和MapX〉cpp文件加入到工程中。
警告:不要选择Project菜单中的Add to Project > Components And Controls命令。这样做将会创建一个.cpp文件,但该文件将是不完整的。我一开始就是这么做的,结果很多常用函数都没有,郁闷了我很长时间。希望大家一起要切记这一点。
在将包含该控件得视图中包括它:
#include “MapX.h”
:
:
:
Class CMapXSampleView : public CView
{
:
:
:
Protected:
CMapX m_ctrlMapX;
:
:
}
要声明表示用于MapX的控件ID的常数:
(1)选择“View”>”Resource Symble”。
(2)单击“New”。
(3)键入“IDC_MAP”来作为名称。
要在类向导中为WM_SIZE和WM_CREATE消息创建处理程序:
(1)转入”View”>”ClassWizard”;
(2)从“Class Name”组合框中选择您的视图类。
(3)在“Messages”列表框中,单击“WM_CREATE”,然后单击“Add Function”。
(4)接着还在该消息框中选择” WM_SIZE”并单击“Add Function”。
(5)然后,单击“Edit Code”
在创建视图时创建该控件。在CMapXSampleView::OnCreate中:
//create map with default size
//resize message will cause it to be size to the client area of the view
If(!m_ctrlMapX.Create(NULL,WS_VISIBLE, CRect(0,0,100,100),this,IDC_MAP))
Returen -1;
Keep the control’s size in sync with the containing window;
//resize the map to be the same size as our client area
Void CMapXSampleView:: OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if(cx!=0 && cy!=0)
m_ctrlMapX.MoveWindow(0,0,cx,cy);
}
像您为WM_CREATE消息所作的一样为WM_SETFOCUS消息创建新消息标头。
在我们的示例中,我们想要确保只要窗口被激活MapX就获得焦点:
void CMapXSampleView::OnSetFocus(CWnd* pOldWnd)
{
CView::OnSetFocus(pOldWnd);
m_ctrlMapX.SetFocus();
}
在地图显示出来后,用户通常要以各种比例查看地图的全局、局部或细部,必须提供诸如放大、缩小和漫游等功能。采用MapX通用工具,可以非常方便地实现上述功能。设定MapX使用标准工具的方法很简单,只需设定地图对象的CurrentTool属性。下面的例子是用标准放大工具实现放大功能。
添加新菜单项资源,输入标题“工具”,在“工具”下添加子菜单,输入标题“放大”及ID 为ID_ZOOM_ IN。打开类向导,选择视图类CMapXSampleView,为菜单项ID_ZOOM_IN 添加COMMAND 消息映射函数OnZoomIn ( ),并编辑码如下。
void CMapXSampleView::OnZoomIn()
{
m_ctrlMapX.SetCurrentTool(miZoomInTool);// miZoomInTool为放大工具常量
}
编译运行程序,选择“工具|放大”,就会看到此时光标变为放大镜,单击鼠标就会实现放大功能。可用相同方法实现其他标准工具的功能。MapX提供的可用标准工具如下表。
工具 |
常数 |
说明 |
添加线条 |
miAddLineTool |
将线条图元添加到插入图层中。 |
添加点 |
miAddPointTool |
单击该工具可将点图元添加到插入图层中。 |
添加折线 |
miAddPolyLineTool |
将折线图元添加到插入图层中。 |
添加区域 |
miAddRegionTool |
将区域图元添加到插入图层中。 |
箭头 |
miArrowTool |
单击标题或注释此外,在可编辑图层中移动选定图元或调整选定图元的大小。 |
居中 |
miCenterTool |
单击该工具可以重新将地图居中。 |
加标签 |
miLabelTool |
在一个图元上单击可以给该图元加标签。 |
平移 |
miPanTool |
拖动该工具可以重新将地图居中。 |
多边形选择 |
miPolygonSelectTool |
单击该工具可以绘制一个多边形;该多边形内的对象将被选定。 |
半径选择 |
miRadiusSelectTool |
拖动该工具可以选择半径内的图元。 |
矩形选择 |
miRectSelectTool |
拖动该工具可以选择矩形内的图元。 |
选择工具 |
miSelectTool |
单击该工具可以选择图元。 |
符号 |
miSymbolTool |
放置符号注释。 |
文本 |
miTextTool |
放置文本注释。 |
放大 |
miZoomInTool |
放大。 |
缩小 |
miZoomOutTool |
缩小。 |
MapX提供的地图标准工具能满足一般需要,但在一些特殊地方,用户可能需要某种特殊工具来完成某些特定的地图操作功能。因此,MapX提供了用户自定义工具的方法,这样可以大大扩展MapX的应用范围。开发者可使用地图对象的CreateCustomTool 方法创建自定义工具。一旦您已使用CreateCustomTool方法创建了定制工具后,就可以在用户使用定制工具时使用ToolUsed事件执行操作。
此示例进行测试以了解正使用哪一工具。然后,根据正在使用的工具,该示例或者:
• 更改光标下的地图图元的样式,或者
• 在用户单击处放置新符号。
void CMapXSampleView::OnToolUsed(short ToolNum, double X1, double Y1, double X2, double Y2, double Distance,BOOL Shift, BOOL Ctrl, BOOL* EnableDefault)
{
CString str;
CMapXPoint pnt;
str.Format("Tool=%d, [%f,%f] [%f, %f], dist=%f, %s %sn",
ToolNum, X1,Y1,X2,Y2,Distance,
(Shift)?"Shift":"",(Ctrl)?"Ctrl":"");
TRACE(str);
// change the style of the feature under the cursor
if (ToolNum == MAP_TOOL_CHANGESTYLE) {
try {
// Need the dispatch to use the point
if (pnt.CreateDispatch(pnt.GetClsid())) {
pnt.Set(X1, Y1);
}
else {
// something went wrong, can't use the point...
AfxThrowOleException(CO_E_CLASS_CREATE_FAILED);
}
CMapXLayers layers = m_ctrlMapX.GetLayers();
// Get the USA feature under the cursor
CMapXFeatures ftrs =
layers.Item("USA").SearchAtPoint(LPDISPATCH(pnt));
// work on only the first feature
CMapXFeatureftr = ftrs.Item(1);
// get the style object from the feature
CMapXStylestyle = ftr.GetStyle();
style.SetRegionBackColor(255);
// update the feature in the layer
ftr.Update();
}
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
catch (COleException *e) {
e->ReportError();
e->Delete();
}
}
// place a new symbol at the point clicked on
else if (ToolNum == MAP_TOOL_NEWPOINT) {
try {
CMapXLayers layers = m_ctrlMapX.GetLayers();
CMapXFeatureftr;
// Need the dispatch id to use the feature
if (ftr.CreateDispatch(ftr.GetClsid())) {
// Symbol feature
ftr.SetType(miFeatureTypeSymbol);
// Get the point object from the feature
// and call the Set method
ftr.GetPoint().Set(X1, Y1);
// Add it to the layer
layers.Item("USA").AddFeature(ftr);
}
else {
AfxThrowOleException(CO_E_CLASS_CREATE_FAILED);
}
}
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
catch (COleException *e) {
e->ReportError();
e->Delete();
}
}
}
若要处理MapX事件,您首先需要为感兴趣的事件建立eventsink地图。用于事件DISPATCH id 的常数是在MapX.h中为MapX定制事件定义的,并且是在中为 OLE 普通事件定义的。
// From MapX.h
#define MAPX_DISPID_SELECTION_CHANGED 0x1
#define MAPX_DISPID_RESOLVEDATABIND 0x2
#define MAPX_DISPID_TOOLUSED 0x3
#define MAPX_DISPID_REQUESTDATA 0x4
#define MAPX_DISPID_DATAMISMATCH 0x5
#define MAPX_DISPID_MAPVIEWCHANGED 0x6
#define MAPX_DISPID_ANNOTATIONADDED 0x7
#define MAPX_DISPID_ANNOTATIONCHANGED 0x8
#define MAPX_DISPID_THEMEMODIFYREQUESTED 0x9
#define MAPX_DISPID_DRAWUSERLAYER 0x0a
#define MAPX_DISPID_POLYTOOLUSED 0x0b
// From
#define DISPID_CLICK (-600)
#define DISPID_DBLCLICK (-601)
#define DISPID_KEYDOWN (-602)
#define DISPID_KEYPRESS (-603)
#define DISPID_KEYUP (-604)
#define DISPID_MOUSEDOWN (-605)
#define DISPID_MOUSEMOVE (-606)
#define DISPID_MOUSEUP (-607)
#define DISPID_ERROREVENT (-608)
EVENT_SINK中的ON_EVENT 宏也为MapX控件指定一个ID (在该示例中为 IDC_MAP),指定该事件的参数,并且指定事件处理程序方法的名称。
在视图标头文件MapXSampView.h中,将“DECLARE_EVENTSINK_MAP ()”一行放置于“DECLARE_MESSAGE_MAP”行之下。
从CMapXSampleView.cpp:
BEGIN_EVENTSINK_MAP(CMapXSampleView, CView)
ON_EVENT(CMapXSampleView, IDC_MAP, DISPID_MOUSEMOVE,
OnMouseMoveInMap,VTS_I2 VTS_I2 VTS_XPOS_PIXELS VTS_YPOS_PIXELS)
ON_EVENT(CMapXSampleView, IDC_MAP, MAPX_DISPID_MAPVIEWCHANGED,
OnMapViewChanged, VTS_NONE)
ON_EVENT(CMapXSampleView, IDC_MAP, DISPID_MOUSEUP,
OnMouseUpInMap, VTS_I2 VTS_I2 VTS_XPOS_PIXELS VTS_YPOS_PIXELS)
ON_EVENT(CMapXSampleView, IDC_MAP, MAPX_DISPID_TOOLUSED,
OnToolUsed, VTS_I2 VTS_R8 VTS_R8 VTS_R8 VTS_R8 VTS_R8 VTS_BOOL
VTS_BOOL VTS_PBOOL)
ON_EVENT(CMapXSampleView, IDC_MAP,
MAPX_DISPID_THEMEMODIFYREQUESTED, OnThemeModifyRequested,
VTS_DISPATCH)
END_EVENTSINK_MAP()
随后是用于OnToolUsed 事件的事件处理程序代码。来自CMapXSampleView.h 的声明:
void OnToolUsed(short ToolNum, double X1, double Y1, double X2,double Y2, double
Distance, BOOL Shift, BOOL Ctrl, BOOL* EnableDefault);
…以及来自CMapXSampleView.cpp 的实现方式(我们只使用 TRACE 宏将参数输出到调试窗口):
void CMapxSampleView::OnToolUsed(short ToolNum, double X1, double Y1,
double X2, double Y2, double Distance, BOOL Shift, BOOL Ctrl, BOOL* EnableDefault)
{
CString str;
str.Format("Tool=%d, [%f,%f] [%f, %f], dist=%f, %s %sn",ToolNum, X1,Y1,X2,Y2,Distance,
(Shift)?"Shift":"",(Ctrl)?"Ctrl":"");
TRACE(str);
}
DISPID_MOUSEUP事件可用于添加快捷(鼠标右键按钮)菜单。为您的快捷菜单创建菜单资源(如果菜单资源的ID为IDR_CONTEXTMENU)。OnMouseUpInMap 处理程序类似于以下代码:
// if right mouse button, display the context menu
BOOL CMapxSampleView::OnMouseUpInMap(short Button, short Shift,
OLE_XPOS_PIXELS x,OLE_YPOS_PIXELS y)
{
if (Button == 2) { // right button
CMenu menu; // top-level menu
CMenu *pMenu=NULL; // pop-up menu
// Load the menu resource.
menu.LoadMenu(IDR_CONTEXTMENU);
// TrackPopupMenu cannot display the top-level menu, so get
// the handle of the first pop-up menu.
pMenu = menu.GetSubMenu(0);
if (!pMenu) {
return TRUE;
}
SetMenuDefaultItem(pMenu->m_hMenu, ID_VIEW_PROPERTIES,
FALSE);
// Display the floating pop-up menu. Track the right mouse
// button on the assumption that this function is called
// during WM_CONTEXTMENU processing.
POINT pt;
GetCursorPos(&pt);
pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
pt.x, pt.y, this, NULL);
// Destroy the menu.
menu.DestroyMenu();
}
return TRUE;
}
MapX通过报告(引发)COleDispatchException 来报告大多数错误。在调用 MapX 时捕获异常错误是十分重要的,因为MFC的默认异常错误处理程序不捕获它们并且您的应用程序将退出。在消息框中显示对错误的说明也是非常有用的。错误消息的文本将帮助您确定是否正确使用了 MapX 图元,或者是否已发生某一其它问题。
COleDispatchException类还在公共成员m_wCode中包括错误代码,以便您的程序可以标识和处理不同类型的错误。对于错误代码及其说明的列表,请参见联机帮助中的 MapX 错误代码。
如果在尝试调用MapX时具有一般的OLE错误(在您使用过时的MapX.h 或 MapX.cpp 版本时可能发生),则 MFC 将引发 COleException。建议你在调用 MapX 时捕获全部两个异常错误类型。
MapX 也可能在 Error 事件中传递错误(尽管非常少见)。只有在不从MapX属性或方法直接调用的异步处理(像redraw)期间出现某种类型的错误时,才可能发生上述情况。
在此示例的 ThemeModifyRequested 事件的事件处理程序中,我们显示普通的“主题”属性对话框以让用户更改主题颜色等。请注意异常错误处理的方式。
// Note: in objects passed to events, the event handler
// does not change the reference count
// ie: do not call release on the object
void CMapxSampleView::OnThemeModifyRequested(LPDISPATCH Theme)
{
try {
CMapXTheme theme;
COptionalVariant vHelpFile, vHelpID;
// mark as optional since we don't have a helpfile
theme.AttachDispatch(Theme, FALSE); // don't auto release
theme.ThemeDlg(vHelpFile, vHelpID);
// could decide to bring up legend dlg here instead
//CMapXLegend leg(theme.GetLegend());
//leg.LegendDlg(vHelpFile, vHelpID);
}
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
catch (COleException *e) {
e->ReportError();
e->Delete();
}
}