ArcGIS Engine 中自定义了一些添加命令、工具和菜单的基类,在需要写相应函数的时候可以直接很方便的添加。
我在前面的文章里面有一节讲述过如何添加控件命令:http://blog.csdn.net/my_lord_/article/details/52599153 。本节讲述一下右键菜单的实现,右键菜单也就是单击鼠标右键时弹出的一个菜单项。主体也就是新建一个IToolbarMenu m_MenuMap 接口,将自定义的命令添加进去,最后在鼠标右键的响应函数中弹出即可。具体流程与代码如下:
1、添加变量,在Form1的类中。
#region Right Button Menu Class Memble
//TOCControl控件变量
private ITOCControl2 m_TocControl = null;
//TOCControl中Map菜单
private IToolbarMenu m_MenuMap = null;
//TOCControl中图层菜单
private IToolbarMenu m_MenuLayer = null;
#endregion
2、添加命令函数。
命令函数的具体添加过程就不再这里复述了,不太清楚地可以翻一下我前面的文章。这里贴上一些代码:
ZoomToLayer 命令:
/// <summary>
/// 放大至整个图层
/// </summary>
public sealed class ZoomToLayer : BaseCommand
{
private IMapControl3 m_mapControl;
public ZoomToLayer()
{
base.m_caption = "Zoom To Layer";
}
public override void OnClick()
{
ILayer layer = (ILayer)m_mapControl.CustomProperty;
m_mapControl.Extent = layer.AreaOfInterest;
}
public override void OnCreate(object hook)
{
m_mapControl = (IMapControl3)hook;
}
}
RemoveLayer 命令:
/// <summary>
/// 删除图层
/// </summary>
public sealed class RemoveLayer : BaseCommand
{
private IMapControl3 m_mapControl;
public RemoveLayer()
{
base.m_caption = "Remove Layer";
}
public override void OnClick()
{
ILayer layer = (ILayer)m_mapControl.CustomProperty;
m_mapControl.Map.DeleteLayer(layer);
}
public override void OnCreate(object hook)
{
m_mapControl = (IMapControl3)hook;
}
}
LayerVisibility 命令:
/// <summary>
/// 图层可视控制
/// </summary>
public sealed class LayerVisibility : BaseCommand, ICommandSubType
{
private IHookHelper m_hookHelper = new HookHelperClass();
private long m_subType;
public LayerVisibility()
{
}
public override void OnClick()
{
for (int i = 0; i <= m_hookHelper.FocusMap.LayerCount - 1; i++)
{
if (m_subType == 1) m_hookHelper.FocusMap.get_Layer(i).Visible = true;
if (m_subType == 2) m_hookHelper.FocusMap.get_Layer(i).Visible = false;
}
m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
public override void OnCreate(object hook)
{
m_hookHelper.Hook = hook;
}
public int GetCount()
{
return 2;
}
public void SetSubType(int SubType)
{
m_subType = SubType;
}
public override string Caption
{
get
{
if (m_subType == 1) return "Turn All Layers On";
else return "Turn All Layers Off";
}
}
public override bool Enabled
{
get
{
bool enabled = false; int i;
if (m_subType == 1)
{
for (i = 0; i <= m_hookHelper.FocusMap.LayerCount - 1; i++)
{
if (m_hookHelper.ActiveView.FocusMap.get_Layer(i).Visible == false)
{
enabled = true;
break;
}
}
}
else
{
for (i = 0; i <= m_hookHelper.FocusMap.LayerCount - 1; i++)
{
if (m_hookHelper.ActiveView.FocusMap.get_Layer(i).Visible == true)
{
enabled = true;
break;
}
}
}
return enabled;
}
}
}
这个里面做了几个处理,在这里描述一下:首先,这个命令的作用就是如果SubType为1时,设置Caption为Turn All Layer On ,2的话就是Turn All Layer Off就是打开图层和关闭图层。
其中,caption名字的变化是定义了一个Caption属性来修改。SubType值是通过在m_MenuMap.AddItem时根据第二个参数来定义。具体的细节我也不太懂,以后弄明白了再补充。
在这里在讲述一下IHOOKHelper接口:
IHookHelper 主要在用在自定义类型于AE带的的ICommand或ITool等,
1.实例化IHookHelper 对象:
IHookHelper m_hookHelper = new HookHelperClass();
m_hookHelper.Hook = this.axMapControl1.Object ;这样就可以把AxMapControl传递给其它要用到的地方。
2.通过IHookHelper,获取地图控件和主窗体:
IntPtr pHandle = new IntPtr (m_hookHelper.ActiveView.ScreenDisplay.hWnd);
axMapControl1 = System.Windows.Forms.Form.FromHandle(pHandle) as AxMapControl;//对这个地图控件对象操作,会直接反应到主窗体的地图控件上
Form. MainForm. = Form.FromHandle(pHandle).FindForm();//这里的主窗体对象之后运行时能起作用,MainForm. 不能直接访问到主窗体里的变量。
3.通过IHookHelper,获取IActiveView和IMap对象
再通过IHookHelper.ActiveView和IHookHelper.FocusMap属性来获取IActiveView和IMap对象,通过这两个接口进行更一步的操作.
4.通过IHookHelper,操作地图
IHookActions hookActions= m_hookHelper as IHookHelper;
获取IHookActions,再通过IHookActions进行Flash,Pan,ZoomTo操作.HOOK实际是一个对象传出的自身的引用或者叫指针或者叫句柄。
例如一个程序,加载一个dll内的对象时通过把Hook传递给要调用的对象,
这样dll内的对象就得到了应用程序传递给他的这个hook,
对象可以通过这个hook查看程序内部的结构。
实际实现时就是对象间传递指向自身的指针传递给另一个对象。
IHookHelper m_hookHelper=new HookHelperClass();
m_hookHelper.Hook=axMapControl1.Object;
//这样就获得了axMapControl1控件的一个引用
然后通过m_hookHelper.ActiveView可以获得原axMapControl1的ActiveView项,
用m_hookHelper.FocusMap可以获得IMap对象
//右键菜单项的初始化
m_MenuMap = new ESRI.ArcGIS.Controls.ToolbarMenuClass();
m_MenuLayer = new ESRI.ArcGIS.Controls.ToolbarMenuClass();
m_TocControl = (ITOCControl2)this.axTOCControl1.Object;
//添加自定义菜单项到TOCCOntrol的Map菜单中
//打开文档菜单
m_MenuMap.AddItem(new OpenNewMapDocument(m_controlsSynchronizer), -1, 0, false, esriCommandStyles.esriCommandStyleIconAndText);
//添加数据菜单
m_MenuMap.AddItem(new ControlsAddDataCommandClass(), -1, 1, false, esriCommandStyles.esriCommandStyleIconAndText);
//打开全部图层菜单
m_MenuMap.AddItem(new LayerVisibility(), 1, 2, false, esriCommandStyles.esriCommandStyleTextOnly);
//关闭全部图层菜单
m_MenuMap.AddItem(new LayerVisibility(), 2, 3, false, esriCommandStyles.esriCommandStyleTextOnly);
//以二级菜单的形式添加内置的“选择”菜单
m_MenuMap.AddSubMenu("esriControls.ControlsFeatureSelectionMenu", 4, true);
//以二级菜单的形式添加内置的“地图浏览”菜单
m_MenuMap.AddSubMenu("esriControls.ControlsMapViewMenu", 5, true);
//添加自定义菜单项到TOCCOntrol的图层菜单中
m_MenuLayer = new ToolbarMenuClass();
//添加“移除图层”菜单项
m_MenuLayer.AddItem(new RemoveLayer(), -1, 0, false, esriCommandStyles.esriCommandStyleTextOnly);
//添加“放大到整个图层”菜单项
m_MenuLayer.AddItem(new ZoomToLayer(), -1, 1, true, esriCommandStyles.esriCommandStyleTextOnly);
//设置菜单的Hook
m_MenuLayer.SetHook(m_mapControl);
m_MenuMap.SetHook(m_mapControl);
//右键菜单项的初始化--end
在最后一步中设置菜单Hook的时候是对菜单中所有添加的项进行设置,当然也可以自己调用每个命令的Oncreat进行传递Hook。代码如下:
ICommand m_Command=new ControlsMapZoomInToolClass();//自带的一个放大功能的类
m_Command。OnCreate(m_mapControl.Object);
m_mapCiontrol.CurrentTool=(ITool)m_Command;//对于需要点击的命令响应OnClick()。
四、鼠标右键响应函数
private void axTOCControl1_OnMouseDown(object sender, ITOCControlEvents_OnMouseDownEvent e)
{
//如果不是右键按下直接返回
if (e.button != 2) return;
esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;
IBasicMap map = null;
ILayer layer = null;
object other = null;
object index = null;
//判断所选菜单的类型
m_TocControl.HitTest(e.x, e.y, ref item, ref map, ref layer, ref other, ref index);
//确定选定的菜单类型,Map或是图层菜单
if (item == esriTOCControlItem.esriTOCControlItemMap)
m_TocControl.SelectItem(map, null);
else
m_TocControl.SelectItem(layer, null);
m_MenuLayer.SetHook(m_mapControl);
m_MenuMap.SetHook(m_mapControl);
//设置CustomProperty为layer (用于自定义的Layer命令)
m_mapControl.CustomProperty = layer;
//弹出右键菜单
if (item == esriTOCControlItem.esriTOCControlItemMap)
m_MenuMap.PopupMenu(e.x, e.y, m_TocControl.hWnd);
if (item == esriTOCControlItem.esriTOCControlItemLayer)
m_MenuLayer.PopupMenu(e.x, e.y, m_TocControl.hWnd);
}
}
这里有一个不太明白的地方:
//设置CustomProperty为layer (用于自定义的Layer命令)
m_mapControl.CustomProperty = layer;
这一句不太懂。
运行结果:
public void HitTest ( int X, int Y, ref esriTOCControlItem ItemType, ref IBasicMap BasicMap, ref ILayer Layer, ref object Unk, ref object Data );
各参数的含义如下:
X,Y :鼠标点击的坐标;
ITemType: esriTOCControlItem枚举常量
BasicMap:绑定MapControl的IBasicMap接口
Layer:被点击的图层
Unk:TOCControl的LegendGroup对象
Data:LegendClass在LegendGroup中的Index。
esriTOCControlItem枚举常量用于描述TocControl上的Item的类型,其定义如下:
esriTOCControlItemNone 0 没有对象
esriTOCControlItemMap 1 Map对象
esriTOCControlItemLayer 2 Layer对象
esriTOCControlItemHeading 3 对象的标题
esriTOCControlItemLegendClass 4 LegendClass对象
----------------------------------------------------------end---------------------------------------------------