目录
01 前言
02 鹰眼图的控制功能
03 显示当前鼠标的地理坐标
01 前言
说是拓展,不过是忘记了实验还有附加实验.这里补上.
前文不再赘述,上一节查看:ArcGIS Engine:视图菜单的创建和鹰眼图的实现_炒茄子的博客-CSDN博客
这里加上三个功能:
为程序增加鹰眼(缩略图)显示功能,并扩展鹰眼功能
1)增加鹰眼图控制功能:
在鹰眼图中点击鼠标,跳转主图到鼠标点击位置;
在鹰眼图中绘制矩形,跳转主图到该矩形范围;
2)增加地图控件操作
响应鼠标在地图上移动事件,将当前地理坐标显示在状态栏;
02 鹰眼图的控制功能
其实本质上鹰眼图中两个功能:点击鼠标和绘制矩形是捆绑在一块的功能我个人认为.
我们说一说点击鼠标, 然后主视图转到鼠标点击位置,这实际上就是监控鼠标按下时在鹰眼图对应的位置,然后找到主视图上对应位置将其显示在最中心。
而绘制矩形,看起来好像比较难,实际上就是继续监控鼠标松开(按下就是前面的点击鼠标,现在是松开)时在鹰眼图的位置,那么这里绘制矩形就是依据按下和松开两个位置构建一个矩形,然后这个矩形范围作为主视图显示的范围。
那么就需要监控两个事件,第一就是鼠标在鹰眼图按下时;第二就是鼠标在鹰眼图松开时;
但是每一个事件触发时我们应该做什么呢?按正常来想,我们应该是按下的时候(鼠标按下事件触发)完成第一个功能;然后松开的时候(鼠标松开事件触发,同时会利用前面鼠标按下事件触发时那个点位的信息)完成第二个功能。
但是实际上可能会这么:当用户按下鼠标,第一个功能触发,当用户松开鼠标第二个功能触发,所以两个功能会同时触发。所以我将做一些更改:
当鼠标按下,仅仅记录点位信息;
当鼠标松开,记录松开点位信息并判断与前面按下点位信息是否一致,如果一致执行第一个功能,否则执行第二个功能。
具体操作如下:
类似的,对于鼠标松开事件:
两个功能的实现代码:
IPoint down_point; // 类成员变量
public void EyeMapControl_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
{
// 当鼠标在鹰眼图上按下时,触发本事件
// 该函数用于将主视图的显示从当前位置平移到鹰眼图中的鼠标点击的位置(平移操作放到了鼠标松开事件函数中, 因为要与鼠标绘制矩形然后主视图平移过去的功能区分)
down_point = new PointClass(); // 实例化一个点对象
down_point.X = e.mapX; // 记录当前鼠标的X坐标
down_point.Y = e.mapY; // 记录当前鼠标的Y坐标
}
private void EyeMapControl_OnMouseUp(object sender, IMapControlEvents2_OnMouseUpEvent e)
{
// 当鼠标在鹰眼图上松开时,触发本事件
IPoint up_point = new PointClass(); // 实例化一个点对象
up_point.X = e.mapX;
up_point.Y = e.mapY;
// 如果按下的鼠标为null说明用户在其它位置按下鼠标, 然后在鹰眼图中松开鼠标, 这不应该进行平移, 可能是误触
if (down_point == null)
{
return;
}
if ((down_point.X == up_point.X) && (down_point.Y == up_point.Y))
{
// 如果按下和松开鼠标点位一致那么说明仅仅是点击
MainMapControl.CenterAt(down_point); // 将中心点移动到click_point点对象所在位置.
}
else
{ // 如果不一致, 说明用户拉框了.我们将
IEnvelope env = new EnvelopeClass(); // 实例化一个包络线对象
double x_min = Math.Min(down_point.X, up_point.X);
double x_max = Math.Max(down_point.X, up_point.X);
double y_min = Math.Min(down_point.Y, up_point.Y);
double y_max = Math.Max(down_point.Y, up_point.Y);
env.PutCoords(x_min, y_min, x_max, y_max);
MainMapControl.Extent = env;
}
MainMapControl.ActiveView.Refresh(); // 刷新
down_point = null; // 将鼠标按下的点位信息清除, 为下次准备
}
03 显示当前鼠标的地理坐标
这里就更简单了,当前鼠标的地理坐标,应该是显示当前鼠标在主视图上所在位置的坐标,所以只需要有一个事件监控鼠标移动就好了。
操作如下:
我始终担心,我的状态栏名是CoordStatusLabel,但是你们的不一定是,你们可以在这里查看自己的状态栏名称:
代码:
// 当鼠标在主视图中移动时, 触发此事件
// 该函数用于在状态栏中显示当前鼠标对应的地理坐标信息
double x = e.mapX;
double y = e.mapY;
string units = MainMapControl.MapUnits.ToString().Substring(4); // 去掉esri四个字符
//CoordStatusLabel.Text = string.Format("X: {0: .4f}; Y: {1: .4f}", x, y);
CoordStatusLabel.Text = string.Format("X: {0:.0000}; Y: {1:.0000}; 单位: {2}", x, y, units);
所有完整代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ESRI.ArcGIS.Controls; // 使用其中的工具类(例如平移工具Pan等)
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Carto; // 使用ILayer类
using ESRI.ArcGIS.Display;
namespace Ex2Twinborn
{
public partial class MainForm : Form
{
public MainForm()
{
ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop); // 解决版本不清晰问题
InitializeComponent();
}
private void 放大ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 该函数用于将鼠标状态切换为放大工具
ControlsMapZoomInToolClass zoom_in = new ControlsMapZoomInToolClass(); // 实例化一个工具
zoom_in.OnCreate(MainMapControl.Object); // 告诉放大工具,它应该服务于谁,==> Map
MainMapControl.CurrentTool = zoom_in; // 将Map控件的当前使用工具切换为放大
}
private void 缩小ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 当前函数用于将鼠标状态切换为缩小工具
ControlsMapZoomOutToolClass zoom_out = new ControlsMapZoomOutToolClass();
zoom_out.OnCreate(MainMapControl.Object); // 将缩小工具的服务对象进行绑定
MainMapControl.CurrentTool = zoom_out; // 将Map控件的当前使用工具切换为缩小
}
private void 平移ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 该函数用于将当前鼠标状态切换为平移工具
ControlsMapPanToolClass pan = new ControlsMapPanToolClass(); // 如果不能正常运行, 请将引用下关于ESRI的所有引用的属性-嵌入互操作类型更改为false.
pan.OnCreate(MainMapControl.Object); // 告诉pan工具,你是在Map控件上进行工作的
MainMapControl.CurrentTool = pan; // 将Map控件当前的使用工具更改为平移工具
}
private void 全图ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 该函数用于将当前Map进行全图显示-方法1
MainMapControl.Extent = MainMapControl.FullExtent;
MainMapControl.Refresh();
方法2
//ControlsMapFullExtentCommandClass full_extent = new ControlsMapFullExtentCommandClass();
//full_extent.OnCreate(MainMapControl.Object);
//full_extent.OnClick();
}
private void MainMapControl_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
{
// 当主视图(MainMapControl)的内容被替换了(实际上此处仅仅是针对mxd文档被替换,对于一般数据的加载实际上不会触发此函数), 那么执行该部分函数
// 该函数用于将主视图上的所有图层同步加载到鹰眼图中
for (int ix=0; ix < MainMapControl.LayerCount; ix++)
{
ILayer layer = MainMapControl.get_Layer(ix);
EyeMapControl.AddLayer(layer);
}
EyeMapControl.Extent = EyeMapControl.FullExtent; // 全图显示
EyeMapControl.Refresh();
EyeMapControl.AutoMouseWheel = false; // 不允许有滚动条
}
private void MainMapControl_OnExtentUpdated(object sender, IMapControlEvents2_OnExtentUpdatedEvent e)
{
// 当主视图的Extent范围发生变化, 那么触发此事件
// 该函数用于更新鹰眼图中的矩形框(矩形框范围为主视图的Extent)
IRectangleElement pRectangleElement = new RectangleElement() as IRectangleElement; // 新建一个矩形框并更换类型
IElement pEle = pRectangleElement as IElement; // 再次更换类型
IEnvelope pEnv = e.newEnvelope as IEnvelope; // 获取主视图的范围边框并更换类型为包络线==> IEnvelope
pEle.Geometry = pEnv; // 设置刚刚创建的矩形边框的几何形状为刚刚主视图的范围的边框.
IRgbColor pColor = new RgbColor(); // 实例化一个颜色对象
pColor.Red = 200; // 红色分量为200, 255表示完全红色
pColor.Transparency = 255; // 颜色的透明度, 255表示完全不透明
ILineSymbol pLineSymbol = new SimpleLineSymbol(); // 实例化一个线对象
pLineSymbol.Width = 2; // 线的宽度为2
pLineSymbol.Color = pColor; // 线的颜色为刚刚设置的不饱和但完全不透明的红色
IFillSymbol pFillSymbol = new SimpleFillSymbol(); // 创建一个填充符号
pColor.Transparency = 0; // 刚刚的颜色透明度修改为0也就是完全透明度
pFillSymbol.Color = pColor; // 填充色设置为刚刚的颜色, 实际上就是透明度的没有任何填充
pFillSymbol.Outline = pLineSymbol; // 但是填充符号的外边框(它是线)设置为刚刚的线对象
IFillShapeElement pFillShapeElement = pRectangleElement as IFillShapeElement;
pFillShapeElement.Symbol = pFillSymbol;
IGraphicsContainer pGC = EyeMapControl.Map as IGraphicsContainer; // 创建一个
pGC.DeleteAllElements(); // 清除之前所有的图形\注记等等避免与后面新的图形发生冲突或者重叠.
pGC.AddElement(pEle, 0); // 添加矩形框在最底层
IActiveView pActiveView = EyeMapControl.Map as IActiveView;
pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
// 刷新的图层是图形层(不包括加载的数据等)、刷新的对象(null表示图形层的所有对象)、刷新的空间范围(null表示整个鹰眼图范围)
}
private void MainMapControl_OnMapReplaced_1(object sender, IMapControlEvents2_OnMapReplacedEvent e)
{
// 当主视图(MainMapControl)的内容被替换了(实际上此处仅仅是针对mxd文档被替换,对于一般数据的加载实际上不会触发此函数), 那么执行该部分函数
// 该函数用于将主视图上的所有图层同步加载到鹰眼图中
for (int ix = 0; ix < MainMapControl.LayerCount; ix++)
{
ILayer layer = MainMapControl.get_Layer(ix);
EyeMapControl.AddLayer(layer);
}
EyeMapControl.Extent = EyeMapControl.FullExtent; // 全图显示
EyeMapControl.Refresh();
EyeMapControl.AutoMouseWheel = false; // 不允许有滚动条
}
IPoint down_point; // 类成员变量
public void EyeMapControl_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
{
// 当鼠标在鹰眼图上按下时,触发本事件
// 该函数用于将主视图的显示从当前位置平移到鹰眼图中的鼠标点击的位置(平移操作放到了鼠标松开事件函数中, 因为要与鼠标绘制矩形然后主视图平移过去的功能区分)
down_point = new PointClass(); // 实例化一个点对象
down_point.X = e.mapX; // 记录当前鼠标的X坐标
down_point.Y = e.mapY; // 记录当前鼠标的Y坐标
}
private void EyeMapControl_OnMouseUp(object sender, IMapControlEvents2_OnMouseUpEvent e)
{
// 当鼠标在鹰眼图上松开时,触发本事件
IPoint up_point = new PointClass(); // 实例化一个点对象
up_point.X = e.mapX;
up_point.Y = e.mapY;
// 如果按下的鼠标为null说明用户在其它位置按下鼠标, 然后在鹰眼图中松开鼠标, 这不应该进行平移, 可能是误触
if (down_point == null)
{
return;
}
if ((down_point.X == up_point.X) && (down_point.Y == up_point.Y))
{
// 如果按下和松开鼠标点位一致那么说明仅仅是点击
MainMapControl.CenterAt(down_point); // 将中心点移动到click_point点对象所在位置.
}
else
{ // 如果不一致, 说明用户拉框了.我们将
IEnvelope env = new EnvelopeClass(); // 实例化一个包络线对象
double x_min = Math.Min(down_point.X, up_point.X);
double x_max = Math.Max(down_point.X, up_point.X);
double y_min = Math.Min(down_point.Y, up_point.Y);
double y_max = Math.Max(down_point.Y, up_point.Y);
env.PutCoords(x_min, y_min, x_max, y_max);
MainMapControl.Extent = env;
}
MainMapControl.ActiveView.Refresh(); // 刷新
down_point = null; // 将鼠标按下的点位信息清除, 为下次准备
}
private void MainMapControl_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
{
// 当鼠标在主视图中移动时, 触发此事件
// 该函数用于在状态栏中显示当前鼠标对应的地理坐标信息
double x = e.mapX;
double y = e.mapY;
string units = MainMapControl.MapUnits.ToString().Substring(4); // 去掉esri四个字符
//CoordStatusLabel.Text = string.Format("X: {0: .4f}; Y: {1: .4f}", x, y);
CoordStatusLabel.Text = string.Format("X: {0:.0000}; Y: {1:.0000}; 单位: {2}", x, y, units);
}
}
}
最终效果: