1. 程式人生 > >AE學習筆記之右鍵選單的新增與實現

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,操作地圖

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;

這一句不太懂。

執行結果:


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---------------------------------------------------