您的位置:首页 > 其它

AE学习笔记之右键菜单的添加与实现

2016-10-11 14:46 645 查看
        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对象 

三、在Form1的Lord响应函数中初始化图层菜单,这一步在鼠标右键的响应函数中做初始化也一样。先后问题而已。
//右键菜单项的初始化
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;

这一句不太懂。

运行结果:





附录:axTOCControl.HitTest方法介绍

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---------------------------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: