AE學習筆記之右鍵選單的新增與實現
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,操作地圖
三、在Form1的Lord響應函式中初始化圖層選單,這一步在滑鼠右鍵的響應函式中做初始化也一樣。先後問題而已。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---------------------------------------------------