基本上从开始学习AE就做鹰眼程序,学了这么长时间了,在开发过程中也写过几个鹰眼的类,但多多少少都不是太完美,今天有了一个再写一个的冲动,就写了一个,解决了以前那几个中的不足,特来分享
该鹰眼实现的主要功能:
1.鼠标左键在鹰眼地图窗口上点击,可以重新定位矩形框位置,主地图相应更新
2.鼠标移动到鹰眼地图窗口的矩形框内之后,鼠标变为手型样式
3.鼠标移动到鹰眼地图窗口的矩形框内之后,左键按住不放可以实现拖动矩形框定位,主地图相应更新
4.鼠标右键拉框绘制矩形框,重新定位,主地图相应更新
5.主地图加载数据和打开地图文档都可以正常更新
6.鹰眼的基本功能
在编写过程中遇到的最大问题:
主地图窗口加载和打开地图文档之后,鹰眼更新但不显示,或者显示异常。
找到的原因:两个地图对象中的空间坐标系统不一致
解决的办法:pSmallMap.SpatialReference = pMainMap.SpatialReference;
关于怎么使用:
加入该类之后,在你的主程序的代码中声明该类的全局变量,在form_Load函数中进行实例化,将你的鹰眼和主地图窗口实例的object作为形参传入。
例如:
- namespace YingYan
- {
- public partial class Form1 : Form
- {
- private EagleEye.EagleEye eagleEye;
- public Form1()
- {
- InitializeComponent();
- }
- private void Form1_Load(object sender, EventArgs e)
- {
- eagleEye = new EagleEye.EagleEye(axMapControl1.Object as IMapControlDefault, axMapControl2.Object as IMapControlDefault);
- }
- }
- }
复制代码
###########################################################
下面给出该类详细的代码
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Diagnostics;
- using ESRI.ArcGIS.Controls;
- using ESRI.ArcGIS.Display;
- using ESRI.ArcGIS.Carto;
- using ESRI.ArcGIS.Geometry;
- using ESRI.ArcGIS.Geodatabase;
- namespace EagleEye
- {
- public class EagleEye
- {
- private IMapControlDefault mainMapControl; //主 MapControl 地图窗口
- private IMapControlDefault smallMapControl; //鹰眼 MapControl 地图窗口
- private IMap pMainMap; //主地图
- private IMap pSmallMap; //鹰眼地图
- private IActiveView pMainAV; //主地图 ActiveView
- private IActiveView pSmallAV; //鹰眼地图 ActiveView
- private IGraphicsContainer pSmallGpContainer; //鹰眼地图 GraphicsContainer
- private IEnvelope pEnv; //记录地图的 Extent
- private bool bCanDrag; //鹰眼地图上的矩形框可移动的标志
- private IPoint pPoint; //在移动鹰眼地图上的矩形框的时候使用
- private Stopwatch pTimer; //记录在左键按下到弹起的时间,根据间隔判断是不是长按左键,然后执行不同的动作
- public IMapControlDefault MainMapControl
- {
- set { mainMapControl = value; }
- }
- public IMapControlDefault SmallMapControl
- {
- set { smallMapControl = value; }
- }
- //构造函数
- public EagleEye(IMapControlDefault mainMapControl, IMapControlDefault smallMapControl)
- {
- this.mainMapControl = mainMapControl;
- this.smallMapControl = smallMapControl;
- pMainMap = mainMapControl.Map;
- pSmallMap = smallMapControl.Map;
- pMainAV = mainMapControl.ActiveView;
- pSmallAV = smallMapControl.ActiveView;
- pSmallGpContainer = pSmallMap as IGraphicsContainer;
- bCanDrag = false;
- //为主地图窗口 mainMapControl 添加事件
- ((ESRI.ArcGIS.Controls.IMapControlEvents2_Event)mainMapControl).OnExtentUpdated +=
- new IMapControlEvents2_OnExtentUpdatedEventHandler(mainMapControl_OnExtentUpdated);
- ((ESRI.ArcGIS.Controls.IMapControlEvents2_Event)mainMapControl).OnMapReplaced +=
- new IMapControlEvents2_OnMapReplacedEventHandler(mainMapControl_OnMapReplaced);
- ((ESRI.ArcGIS.Carto.IActiveViewEvents_Event)mainMapControl.ActiveView).ItemAdded +=
- new ESRI.ArcGIS.Carto.IActiveViewEvents_ItemAddedEventHandler(mainMapControl_ItemAdded);
- ((ESRI.ArcGIS.Carto.IActiveViewEvents_Event)mainMapControl.ActiveView).ContentsCleared +=
- new ESRI.ArcGIS.Carto.IActiveViewEvents_ContentsClearedEventHandler(mainMapControl_ContentsCleared);
- //为鹰眼地图窗口 smallMapControl 添加事件
- ((ESRI.ArcGIS.Controls.IMapControlEvents2_Event)smallMapControl).OnMouseDown +=
- new IMapControlEvents2_OnMouseDownEventHandler(smallMapControl_OnMouseDown);
- ((ESRI.ArcGIS.Controls.IMapControlEvents2_Event)smallMapControl).OnMouseMove +=
- new IMapControlEvents2_OnMouseMoveEventHandler(smallMapControl_OnMouseMove);
- ((ESRI.ArcGIS.Controls.IMapControlEvents2_Event)smallMapControl).OnMouseUp +=
- new IMapControlEvents2_OnMouseUpEventHandler(smallMapControl_OnMouseUp);
- //初次在鹰眼地图上画矩形框
- pSmallAV.Extent = pMainAV.FullExtent;
- pEnv = pSmallAV.Extent;
- DrawRectangle(pEnv);
- }
- #region 鹰眼地图窗口的响应事件函数
- void smallMapControl_OnMouseUp(int button, int shift, int X, int Y, double mapX, double mapY)
- {
- if (button == 1)
- {
- pTimer.Stop(); //停止计时
- if (pTimer.Elapsed.Milliseconds <= 150)
- {
- //鼠标按下到弹起时间小于150毫秒,说明是单纯的点击,则
- mainMapControl.CenterAt(pPoint);
- }
- else
- {
- //时间大于150毫秒,说明是长按,应该就是发生了拖动的动作,则
- if (bCanDrag) //判断是否可拖动
- {
- double Dx, Dy; //记录鼠标移动的距离
- Dx = mapX - pPoint.X;
- Dy = mapY - pPoint.Y;
- pEnv.Offset(Dx, Dy); //根据偏移量更改 pEnv 位置
- pPoint.PutCoords(mapX, mapY);
- IPoint pTempPoint = new PointClass();
- pTempPoint.PutCoords(pEnv.XMin + pEnv.Width/2,pEnv.YMin + pEnv.Height/2);
- mainMapControl.CenterAt(pTempPoint);
- }
- }
- bCanDrag = false;
- }
- }
- void smallMapControl_OnMouseMove(int button, int shift, int X, int Y, double mapX, double mapY)
- {
- if (mapX > pEnv.XMin && mapY > pEnv.YMin && mapX < pEnv.XMax && mapY < pEnv.YMax)
- //如果鼠标移动到矩形框中,鼠标换成小手,表示可以拖动
- {
- //新建图标,我这里是将此类封装为dll了,所以我将图标资源作为嵌入的资源处理
- System.Drawing.Icon icon = new System.Drawing.Icon(this.GetType().Assembly.GetManifestResourceStream("EagleEye.MyIcon.ico"));
- smallMapControl.MouseIcon = (stdole.IPictureDisp)ESRI.ArcGIS.ADF.COMSupport.OLE.GetIPictureDispFromIcon(icon);
- smallMapControl.MousePointer = esriControlsMousePointer.esriPointerCustom;
- if (button == 2)
- //如果在内部按下鼠标右键,将鼠标换回原来的
- smallMapControl.MousePointer = esriControlsMousePointer.esriPointerDefault;
- }
- else
- {
- //在其他位置将鼠标设为默认的样式
- smallMapControl.MousePointer = esriControlsMousePointer.esriPointerDefault;
- }
- if (bCanDrag)
- {
- double Dx, Dy; //记录鼠标移动的距离
- Dx = mapX - pPoint.X;
- Dy = mapY - pPoint.Y;
- pEnv.Offset(Dx, Dy); //根据偏移量更改 pEnv 位置
- pPoint.PutCoords(mapX, mapY);
- DrawRectangle(pEnv);
- }
- }
- void smallMapControl_OnMouseDown(int button, int shift, int X, int Y, double mapX, double mapY)
- {
- if (button == 1) //左键按下
- {
- if (mapX > pEnv.XMin && mapY > pEnv.YMin && mapX < pEnv.XMax && mapY < pEnv.YMax)
- bCanDrag = true; //如果指针落在鹰眼的矩形框中,标记可移动
- pTimer = new Stopwatch(); //开始计时,到鼠标弹起时结束计时
- pPoint = new PointClass();
- pPoint.PutCoords(mapX, mapY); //记录点击的第一个点的坐标
- pTimer.Start();
- }
- else if (button == 2) //右键按下
- {
- //在鹰眼地图上面拉个矩形框,然后根据矩形框的范围和位置更改主地图显示范围
- //这里说明一下为什么还用 mainMapControl.CenterAt(pTempPoint); 这个语句
- //我是为了更新主地图 OnExtentUpdated 事件中的 newEnvelope,
- //单独的给 Extent 赋值,newEnvelope 是拉框的范围,我们知道我们拉框的时候
- //不可能把宽高比例和地图中的宽高比例弄的刚好一样,那么就利用 CenterAt()
- //让它自己重新调整 newEnvelope,那么我们依赖 newEnvelope 在鹰眼地图中画
- //矩形框的比例就和地图的宽高比例一致了,当然也可以用其他的办法
- //其他地方的调整我也是用的这样的方法
- IEnvelope pEnvelope = ((MapControl)smallMapControl).TrackRectangle();
- IPoint pTempPoint = new PointClass();
- pTempPoint.PutCoords(pEnvelope.XMin + pEnvelope.Width / 2, pEnvelope.YMin + pEnvelope.Height / 2);
- mainMapControl.Extent = pEnvelope;
- mainMapControl.CenterAt(pTempPoint);
- }
- }
- #endregion
- #region 主地图窗口的响应事件函数
- //地图中所有的数据删除后
- void mainMapControl_ContentsCleared()
- {
- pSmallMap.ClearLayers(); //清空鹰眼地图中所有的图层
- //刷新地图
- pSmallAV.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, pSmallAV.Extent);
- pSmallAV.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, pSmallAV.Extent);
- }
- //往主地图中添加数据时发生
- void mainMapControl_ItemAdded(object Item)
- {
- pSmallMap.ClearLayers(); //清空鹰眼地图中所有的图层
- IFeatureLayer pFeatureLayer;
- IFeatureClass pFeatureCls;
- int count = mainMapControl.LayerCount;
- //获得主地图中的图层数,然后遍历,往鹰眼地图中添加数据
- //由于鹰眼地图较小,所以过滤点图层不添加
- for (int i = count - 1; i >= 0; i--)
- {
- pFeatureLayer = pMainMap.get_Layer(i) as IFeatureLayer;
- if (pFeatureLayer != null)
- {
- pFeatureCls = pFeatureLayer.FeatureClass;
- if (pFeatureCls.ShapeType != esriGeometryType.esriGeometryMultipoint
- && pFeatureCls.ShapeType != esriGeometryType.esriGeometryPoint)
- {
- pSmallMap.AddLayer(pFeatureLayer);
- }
- }
- }
- pSmallMap.SpatialReference = pMainMap.SpatialReference; //设置鹰眼和主地图的坐标系统一致
- pSmallAV.Extent = mainMapControl.FullExtent; //设置鹰眼地图全图显示
- pEnv = mainMapControl.Extent as IEnvelope;
- DrawRectangle(pEnv);
- //刷新鹰眼地图
- pSmallAV.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, pSmallAV.Extent);
- pSmallAV.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, pSmallAV.Extent);
- }
- //主地图窗口更换地图文档后发生
- void mainMapControl_OnMapReplaced(object newMap)
- {
- if (pSmallMap.LayerCount > 0)
- //如果鹰眼地图中存在图层则删除它们
- {
- pSmallMap.ClearLayers();
- }
- pSmallMap.SpatialReference = pMainMap.SpatialReference; //这个很关键
- IFeatureLayer pFeatureLayer = null;
- ESRI.ArcGIS.Geodatabase.IFeatureClass pFeatCls;
- int count = mainMapControl.LayerCount;
- //获得主地图中的图层数,然后遍历,往鹰眼地图中添加数据
- //由于鹰眼地图较小,所以过滤点图层不添加
- for (int i = count - 1; i >= 0; i--)
- {
- pFeatureLayer = mainMapControl.get_Layer(i) as IFeatureLayer;
- if (pFeatureLayer != null)
- {
- pFeatCls = pFeatureLayer.FeatureClass;
- if (pFeatCls.ShapeType != esriGeometryType.esriGeometryPoint &&
- pFeatCls.ShapeType != esriGeometryType.esriGeometryMultipoint)
- {
- pSmallMap.AddLayer(pFeatureLayer);
- }
- }
- }
- pSmallAV.Extent = mainMapControl.FullExtent;
- pEnv = mainMapControl.Extent as IEnvelope;
- DrawRectangle(pEnv);
- pSmallAV.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, pSmallAV.Extent);
- pSmallAV.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, pSmallAV.Extent);
- }
- void mainMapControl_OnExtentUpdated(object displayTransformation, bool sizeChanged, object newEnvelope)
- {
- pEnv = newEnvelope as IEnvelope;
- DrawRectangle(pEnv);
- }
- #endregion
- //在鹰眼地图上面画矩形框
- private void DrawRectangle(IEnvelope pEnvelope)
- {
- pSmallGpContainer.DeleteAllElements(); //清除之前绘制的矩形框
- IRectangleElement pRectangleEle = new RectangleElementClass();
- IElement pEle = pRectangleEle as IElement;
- pEle.Geometry = pEnvelope;
- IRgbColor pColor = new RgbColorClass();
- pColor.Red = 255;
- pColor.Green = 0;
- pColor.Blue = 0;
- pColor.Transparency = 255;
- ILineSymbol pOutLine = new SimpleLineSymbolClass();
- pOutLine.Width = 1.5;
- pOutLine.Color = pColor;
- pColor = new RgbColorClass();
- pColor.Transparency = 0;
- IFillSymbol pFillSymbol = new SimpleFillSymbolClass();
- pFillSymbol.Color = pColor;
- pFillSymbol.Outline = pOutLine;
- IFillShapeElement pFillShapeEle = pEle as IFillShapeElement;
- pFillShapeEle.Symbol = pFillSymbol;
- pSmallGpContainer.AddElement(pFillShapeEle as IElement, 0);
- pSmallAV.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, pSmallAV.Extent);
- }
- }
- }
复制代码
自己测试了,自己能见到的bug都修复了,如果大家还发现什么bug,欢迎指出,感激不尽,这样就会更完美了。
|