ArcGIS - Engine92+C++实例开发详细教程
更新时间:2024-06-01 16:36:01 阅读量: 综合文库 文档下载
- arcgis推荐度:
- 相关推荐
第一讲 桌面GIS应用程序框架的建立
本讲主要是使用MapControl、PageLayoutControl、ToolbarControl、TOCControl四个控件建立起基本的桌面GIS应用程序框架。最终成果预览如下:
1、新建项目
启动VS2005,选择“文件|新建|项目”,在项目类型中选择Visual C#,再选择Windows应用程序模板,输入名称“3sdnMap”,点击确定。
在解决方案管理器中将“Form1.cs”重命名为“3sdnMap.cs”,在设计视图中,选中窗体,将其属性中的“Text”改为“3sdnMap”。
2、添加控件
选择工具箱中的“菜单和工具栏|MenuStrip”,将其拖入窗体。 选择工具箱中的“ArcGIS Windows Forms”节,将“ToolbarControl”控件拖入窗体,并将其属性中的Dock设置为Top。
选择工具箱中的“菜单和工具栏|StatusStrip”,将其拖入到窗体。
选择工具箱中的“容器|SplitContainer”容器拖入窗体,并将其属性中的Dock设置为Fill。
将TabControl控件拖入Panel1,将Alignment属性设置为Bottom,Dock属性设置为Fill。点击TabPages属性右边的按钮,弹出TabPage集合编辑器,将tabPage1的Name设置为tabPageLayer,Text设置为图层,将tabPage2的Name设置为tabPageProperty,Text设置为属性。如下所示。
选择“图层”选项卡,拖入TOCControl控件,设置Dock属性为Fill。 选择“属性”选项卡,拖入DataGridView控件,设置Dock属性为Fill。
拖入TabControl控件到Panel2,设置Dock属性为Fill。并上述类似的方法,将两个选项卡的Name和Text分别设置为:(tabPageMap、地图),(tabPageLayout,制版)。
选择“地图”选项卡,拖入MapControl控件,设置Dock属性为Fill。
选择“制版”选项卡,拖入PageLayoutControl控件,设置Dock属性为Fill。 最后将LicenseControl控件拖入到窗体的任意地方。 按F5编译运行,可以看到刚才布局好的程序界面了。
3、控件绑定
通过以上步骤添加的控件还只是单独存在,而我们的程序需要各控件间协同工作,因此要进行控件绑定。 分别右击ToolbarControl、TOCControl控件,将Buddy设置为axMapControl1,如下图所示。
这样,工具条和图层控件就与地图控件关联了。
4、添加工具
此时,工具条中还没有任何工具,添加的方法也很简单。右击ToolbarControl,选择“属性|Items”,点击Add,选择Commands选项卡中的Generic,双击Open、SaveAs、Redo、Undo即可将相应工具添加到工具条。
常见的工具有:
Map Navigation中的导航工具,Map Inquiry中的查询工具,Feature Selection中的选择工具,你可以根据需要酌情添加工具。
5、编译运行
按F5即可编译运行程序,至此桌面GIS应用程序框架基本框架已经搭建好了,你可以通过工具条的工具打开地图文档,浏览地图了,效果如开篇所示。
第二讲 菜单的添加及其实现
在上一讲中,我们实现了应用程序基本框架,其中有个小错误,在此先跟大家说明下。在“属性”选项卡中,我们当时添加的是 DataGridView 控件,这个控件是用来显示数据表的,而专门用于属性的查询和设置的控件是 PropertyGrid 控件。因此请你删除“属性”选项卡中的 DataGridView 控件,再把位于“工具箱 | 所有 Windows 窗体 |PropertyGrid ”(如果没有,右击选择“选择项”以添加此控件)控件拖到该选项卡。 在这一讲中,主要讲解菜单的添加和实现。
1、 添加菜单
在设计视图中,单击菜单栏,会出现“请在此处键入”的提示,单击提示就可以键入菜单名称,如“文件”,再单击“文件”,即可输入其下拉子菜单,如下所示:
Tips :
每创建一个菜单,请在其属性面板中设置 Name 属性,而且不要为中文,因此 Name 值将是此菜单响应函数的函数名的一部分,带中文的函数名,总是不好吧。 本讲中,我们将添加新建( New )、打开( Open )、添加数据( AddData )、保存( Save )、另存为( SaveAs )、退出( Exit )这些菜单,()内为相应的 Name 属性值。
Tips:
你可以在属性面板中的 Text 属性中,把菜单名设置为中英文形式,如“打开 O pen ”,带下划线的 O 表示此项菜单的快捷键是字母 O ,设置方法是在相应字母前加上“ & ”字符,如“打开 &Open ”。但这种快捷键只在打开此下拉菜单时才有效,即当你单击“文件”菜单弹出下拉菜单时,按下字母 O 就可以定位到“打开”菜单。 还有一种在程序运行时都有效的全局快捷键,可以在属性面板中的“ ShortCutKeys ”中设置。
你还可以在属性面板中的 Image 属性中设置你喜欢的菜单图标。单击 Image 那一行右边的按钮,弹出如下菜单。选择“项目资源文件”,再单击导入就可以选择你的图标了。
最终效果显示如下:
注意,在解决方案面板中,选中刚才添加的所有图标,在其属性面板中将“生成操作”设置为“嵌入的资源”,这一点很重要!
2、 实现相关菜单
首先添加以下引用:
using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Display; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.SystemUI;
定义指针(写在 public partial class Form1 : Form 下面即可):
private ESRI.ArcGIS.Controls.IMapControl3 m_mapControl = null;
private ESRI.ArcGIS.Controls.IPageLayoutControl2 m_pageLayoutControl = null; private IMapDocument pMapDocument;
在设计视图中的属性面板中,选择 Form1 ,即主窗体,单击事件按钮(闪电形状的那个按钮),打到“ Load ”事件并双击,添加此事件。
在 Form1_Load 函数中初始化这些指针:
// 取得 MapControl 和 PageLayoutControl 的引用
m_mapControl = (IMapControl3)this.axMapControl1.Object;
m_pageLayoutControl = (IPageLayoutControl2)this.axPageLayoutControl1.Object;
依次双击每个菜单项,添加菜单响应函数。实现代码如下:
///
///
private void New_Click(object sender, EventArgs e) {
// 本命令涉及到 MapControl 和 PageLayoutControl 同步问题,将在下一讲中实现 }
///
/// 打开地图文档 Mxd 命令 ///
///
private void Open_Click(object sender, EventArgs e) {
// 本命令涉及到 MapControl 和 PageLayoutControl 同步问题,将在下一讲中实现 }
///
///
private void AddData_Click(object sender, EventArgs e) {
int currentLayerCount = this.axMapControl1.LayerCount; ICommand pCommand = new ControlsAddDataCommandClass(); pCommand.OnCreate(this.axMapControl1.Object); pCommand.OnClick(); }
///
/// 保存地图文档命令 ///
///
private void Save_Click(object sender, EventArgs e) {
// 首先确认当前地图文档是否有效
if(null!=m_pageLayoutControl.DocumentFilename&&m_mapControl.CheckMxFile(m_pageLayoutControl.DocumentFilename)) {
// 创建一个新的地图文档实例
IMapDocument mapDoc = new MapDocumentClass(); // 打开当前地图文档
mapDoc.Open(m_pageLayoutControl.DocumentFilename, string.Empty); // 用 PageLayout 中的文档替换当前文档中的 PageLayout 部分
mapDoc.ReplaceContents((IMxdContents)m_pageLayoutControl.PageLayout); // 保存地图文档
mapDoc.Save(mapDoc.UsesRelativePaths, false); mapDoc.Close(); } }
///
/// 另存为地图文档命令
///
///
private void SaveAs_Click(object sender, EventArgs e) {
// 调用另存为命令
ICommand command = new ControlsSaveAsDocCommandClass(); command.OnCreate(m_controlsSynchronizer.ActiveControl); command.OnClick(); }
///
///
private void Exit_Click(object sender, EventArgs e) {
Application.Exit(); }
3、 编译运行
按 F5 编译运行程序。也许你会发现,菜单命令的实现方式都是类型的。没错,在 AE9.2 中,内置了许多常用的 Command 和 Tool ,如 ControlsAddDataCommandClass 、 ControlsMapZoomInToolClass 、 ControlsMapPanToolClass 等等,这些内置对象在 ESRI.ArcGIS.Controls 命名空间中,你可以对象浏览器中查看。而且这些内置对象的调用方式都类似,如下所示: // 定义
ICommand command = new ControlsSaveAsDocCommandClass(); // 创建
command.OnCreate(m_controlsSynchronizer.ActiveControl); // 调用
command.OnClick();
第三讲 MapControl与PageLayoutControl同步
在ArcMap中,能够很方面地进行MapView和Layout View两种视图的切换,而且二者之间的数据是同步显示的。 关于两种视图同步的实现方法有多种,可以使用ObjectCopy对象进行数据硬拷贝,而比较简单的方法莫过于二者共享一份地图了,这也是最常用的方法。
1、新建同步类ControlsSynchronizer
在解决方案面板中右击项目名,选择“添加|类”,在类别中选择“Visual C#项目项”,在模板中选择“类”,输入类名“ControlsSynchronizer.cs”,将以下代码覆盖自动生成的代码: using System;
using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.IO;
using System.Runtime.InteropServices; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.SystemUI;
namespace _sdnMap
{
///
/// This class is used to synchronize a gven PageLayoutControl and a MapControl.
/// When initialized, the user must pass the reference of these control to the class, bind /// the control together by calling 'BindControls' which in turn sets a joined Map referenced /// by both control; and set all the buddy controls joined between these two controls.
/// When alternating between the MapControl and PageLayoutControl, you should activate the visible control
/// and deactivate the other by calling ActivateXXX.
/// This calss is limited to a situation where the controls are not simultaneously visible. ///
public class ControlsSynchronizer {
#region class members
private IMapControl3 m_mapControl = null;
private IPageLayoutControl2 m_pageLayoutControl = null; private ITool m_mapActiveTool = null;
private ITool m_pageLayoutActiveTool = null; private bool m_IsMapCtrlactive = true;
private ArrayList m_frameworkControls = null; #endregion
#region constructor ///
public ControlsSynchronizer() {
//初始化ArrayList
m_frameworkControls = new ArrayList(); }
///
///
///
public ControlsSynchronizer(IMapControl3 mapControl, IPageLayoutControl2 pageLayoutControl) : this() {
//为类成员赋值
m_mapControl = mapControl;
m_pageLayoutControl = pageLayoutControl; }
#endregion
#region properties ///
/// 取得或设置MapControl ///
public IMapControl3 MapControl {
get { return m_mapControl; } set { m_mapControl = value; } }
///
/// 取得或设置PageLayoutControl ///
public IPageLayoutControl2 PageLayoutControl
{
get { return m_pageLayoutControl; } set { m_pageLayoutControl = value; } }
///
/// 取得当前ActiveView的类型 ///
public string ActiveViewType {
get {
if (m_IsMapCtrlactive) return \ else
return \ } }
///
/// 取得当前活动的Control ///
public object ActiveControl {
get {
if (m_mapControl == null || m_pageLayoutControl == null)
throw new Exception(\or PageLayoutControl are not initialized!\
if (m_IsMapCtrlactive)
return m_mapControl.Object; else
return m_pageLayoutControl.Object; } }
#endregion
#region Methods ///
/// 激活MapControl并解除the PagleLayoutControl ///
public void ActivateMap() {
try {
if (m_pageLayoutControl == null || m_mapControl == null)
throw new Exception(\PageLayoutControl are not initialized!\//缓存当前PageLayout的CurrentTool
if(m_pageLayoutControl.CurrentTool!=null)m_pageLayoutActiveTool= m_pageLayoutControl.CurrentTool; //解除PagleLayout
m_pageLayoutControl.ActiveView.Deactivate(); //激活MapControl
m_mapControl.ActiveView.Activate(m_mapControl.hWnd);
//将之前MapControl最后使用的tool,作为活动的tool,赋给MapControl的CurrentTool
if (m_mapActiveTool != null) m_mapControl.CurrentTool = m_mapActiveTool; m_IsMapCtrlactive = true;
//为每一个的framework controls,设置Buddy control为MapControl this.SetBuddies(m_mapControl.Object); }
catch (Exception ex) {
throw new Exception(string.Format(\ex.Message)); } }
///
/// 激活PagleLayoutControl并减活MapCotrol ///
public void ActivatePageLayout() {
try {
if (m_pageLayoutControl == null || m_mapControl == null) throw new Exception(\MapControl or PageLayoutControl are not initialized!\
//缓存当前MapControl的CurrentTool
if (m_mapControl.CurrentTool != null) m_mapActiveTool = m_mapControl.CurrentTool; //解除MapControl
m_mapControl.ActiveView.Deactivate();
//激活PageLayoutControl
m_pageLayoutControl.ActiveView.Activate(m_pageLayoutControl.hWnd);
//将之前PageLayoutControl最后使用的tool,作为活动的tool,赋给PageLayoutControl的CurrentTool
if (m_pageLayoutActiveTool != null) m_pageLayoutControl.CurrentTool = m_pageLayoutActiveTool;
m_IsMapCtrlactive = false;
//为每一个的framework controls,设置Buddy control为PageLayoutControl this.SetBuddies(m_pageLayoutControl.Object); }
catch (Exception ex) {
throw new Exception(string.Format(\ } }
///
/// 给予一个地图, 置换PageLayoutControl和MapControl的focus map ///
///
if (newMap == null)
throw new Exception(\map for replacement is not initialized!\
if (m_pageLayoutControl == null || m_mapControl == null)
throw new Exception(\MapControl or PageLayoutControl are not initialized!\
//create a new instance of IMaps collection which is needed by the PageLayout //创建一个PageLayout需要用到的,新的IMaps collection的实例 IMaps maps = new Maps();
//add the new map to the Maps collection //把新的地图加到Maps collection里头去 maps.Add(newMap);
bool bIsMapActive = m_IsMapCtrlactive;
//call replace map on the PageLayout in order to replace the focus map
//we must call ActivatePageLayout, since it is the control we call 'ReplaceMaps' //调用PageLayout的replace map来置换focus map
//我们必须调用ActivatePageLayout,因为它是那个我们可以调用\的Control this.ActivatePageLayout();
m_pageLayoutControl.PageLayout.ReplaceMaps(maps); //assign the new map to the MapControl //把新的地图赋给MapControl m_mapControl.Map = newMap; //reset the active tools //重设active tools
m_pageLayoutActiveTool = null; m_mapActiveTool = null;
//make sure that the last active control is activated //确认之前活动的control被激活 if (bIsMapActive) {
this.ActivateMap();
m_mapControl.ActiveView.Refresh(); } else {
this.ActivatePageLayout();
m_pageLayoutControl.ActiveView.Refresh(); } }
///
/// bind the MapControl and PageLayoutControl together by assigning a new joint focus map /// 指定共同的Map来把MapControl和PageLayoutControl绑在一起 ///
///
///
/// public void BindControls(IMapControl3 mapControl, IPageLayoutControl2 pageLayoutControl, bool activateMapFirst) {
if (mapControl == null || pageLayoutControl == null)
throw new Exception(\MapControl or PageLayoutControl are not initialized!\ m_mapControl = MapControl;
m_pageLayoutControl = pageLayoutControl;
this.BindControls(activateMapFirst); }
///
/// bind the MapControl and PageLayoutControl together by assigning a new joint focus map /// 指定共同的Map来把MapControl和PageLayoutControl绑在一起 ///
///
public void BindControls(bool activateMapFirst)
{
if (m_pageLayoutControl == null || m_mapControl == null)
throw new Exception(\MapControl or PageLayoutControl are not initialized!\ //create a new instance of IMap //创造IMap的一个实例
IMap newMap = new MapClass(); newMap.Name = \
//create a new instance of IMaps collection which is needed by the PageLayout //创造一个新的IMaps collection的实例,这是PageLayout所需要的 IMaps maps = new Maps();
//add the new Map instance to the Maps collection //把新的Map实例赋给Maps collection maps.Add(newMap);
//call replace map on the PageLayout in order to replace the focus map //调用PageLayout的replace map来置换focus map m_pageLayoutControl.PageLayout.ReplaceMaps(maps); //assign the new map to the MapControl //把新的map赋给MapControl m_mapControl.Map = newMap; //reset the active tools //重设active tools
m_pageLayoutActiveTool = null; m_mapActiveTool = null;
//make sure that the last active control is activated //确定最后活动的control被激活 if (activateMapFirst) this.ActivateMap(); else
this.ActivatePageLayout(); }
///
///by passing the application's toolbars and TOC to the synchronization class, it saves you the
///management of the buddy control each time the active control changes. This method ads the framework
///control to an array; once the active control changes, the class iterates through the array and
///calles SetBuddyControl on each of the stored framework control. ///
///
public void AddFrameworkControl(object control) {
if (control == null)
throw new Exception(\control is not initialized!\
m_frameworkControls.Add(control); }
///
/// Remove a framework control from the managed list of controls ///
///
public void RemoveFrameworkControl(object control) {
if (control == null)
throw new Exception(\be
removed is not initialized!\
m_frameworkControls.Remove(control); }
///
/// Remove a framework control from the managed list of controls by specifying its index in the list
///
///
public void RemoveFrameworkControlAt(int index) {
if (m_frameworkControls.Count < index) throw new Exception(\is out of range!\
m_frameworkControls.RemoveAt(index); }
///
/// when the active control changes, the class iterates through the array of the framework controls
/// and calles SetBuddyControl on each of the controls. ///
///
try {
if (buddy == null)
throw new Exception(\is not initialized!\
foreach (object obj in m_frameworkControls) {
if (obj is IToolbarControl) {
((IToolbarControl)obj).SetBuddyControl(buddy); }
else if (obj is ITOCControl) {
((ITOCControl)obj).SetBuddyControl(buddy); } } }
catch (Exception ex) {
Throw new Exception(string.Format(\ex.Message)); } }
#endregion } }
2、新建Maps类
在同步类中,要用到Maps类,用于管理地图对象。与新建同步类ControlsSynchronizer类似,我们新建一Maps类,其所有代码如下所示: using System;
using System.Collections;
using System.Collections.Generic; using System.Text;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto; namespace _sdnMap {
[Guid(\ [ClassInterface(ClassInterfaceType.None)] [ProgId(\
public class Maps : IMaps, IDisposable {
//class member - using internally an ArrayList to manage the Maps collection private ArrayList m_array = null; #region class constructor public Maps() {
m_array = new ArrayList(); }
#endregion
#region IDisposable Members
///
/// Dispose the collection ///
public void Dispose() {
if (m_array != null) {
m_array.Clear(); m_array = null; } }
#endregion
#region IMaps Members ///
/// Remove the Map at the given index ///
///
if (Index > m_array.Count || Index < 0)
throw new Exception(\ m_array.RemoveAt(Index); }
///
/// Reset the Maps array ///
public void Reset() {
m_array.Clear(); }
///
/// Get the number of Maps in the collection /// public int Count
{
get {
return m_array.Count; } }
///
/// Return the Map at the given index ///
///
public IMap get_Item(int Index) {
if (Index > m_array.Count || Index < 0)
throw new Exception(\ return m_array[Index] as IMap; }
///
/// Remove the instance of the given Map ///
///
m_array.Remove(Map); }
///
/// Create a new Map, add it to the collection and return it to the caller ///
///
IMap newMap = new MapClass(); m_array.Add(newMap); return newMap; }
///
/// Add the given Map to the collection ///
///
if (Map == null)
throw new Exception(\ m_array.Add(Map); }
#endregion } }
3、新建打开文档类OpenNewMapDocument
由于从工具栏自带的打开按钮打开地图文档的时候,不会自动进行两种视图之间的同步,所以我们要自己派生一个OpenNewMapDocument类,用于打开地图文档。 右击项目名,选择“添加|类”,再选择ArcGIS类别中的BaseCommand模板,输入类名为“OpenNewMapDocument.cs”。 首先添加引用:
using System.Windows.Forms; using ESRI.ArcGIS.Carto;
//再添加如下成员变量:
private ControlsSynchronizer m_controlsSynchronizer = null; //修改默认的构造函数如下所示: //添加参数
public OpenNewMapDocument(ControlsSynchronizer controlsSynchronizer) {
//
// TODO: Define values for the public properties // //设定相关属性值
base.m_category = \ base.m_caption = \
base.m_message = \should work in ArcMap/MapControl/PageLayoutControl\//localizable text
base.m_toolTip = \
base.m_name = \ //unique id, non-localizable (e.g. \
//初始化m_controlsSynchronizer
m_controlsSynchronizer = controlsSynchronizer; try {
//
// TODO: change bitmap name if necessary //
string bitmapResourceName = GetType().Name + \
base.m_bitmap = new Bitmap(GetType(), bitmapResourceName); }
catch (Exception ex) {
System.Diagnostics.Trace.WriteLine(ex.Message, \ } }
再在OnClick函数中添加如下代码: public override void OnClick() {
// TODO: Add OpenNewMapDocument.OnClick implementation OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = \ dlg.Multiselect = false;
dlg.Title = \
if (dlg.ShowDialog() == DialogResult.OK) {
string docName = dlg.FileName;
IMapDocument mapDoc = new MapDocumentClass();
if (mapDoc.get_IsPresent(docName) && !mapDoc.get_IsPasswordProtected(docName)) {
mapDoc.Open(docName, string.Empty); IMap map = mapDoc.get_Map(0);
m_controlsSynchronizer.ReplaceMap(map); mapDoc.Close(); } } }
在添加类时,模板会自动添加一个名为“OpenNewMapDocument.bmp”的图标,你可以自己修改或者替换为打开的
文件夹的图标。
4、两种视图的同步
在3sdnMap.cs中添加成员变量,即同步类对象:
private ControlsSynchronizer m_controlsSynchronizer = null;
在Form1_Load函数中进行初始化工作:
//初始化controls synchronization calss m_controlsSynchronizer = new
ControlsSynchronizer(m_mapControl, m_pageLayoutControl);
//把MapControl和PageLayoutControl绑定起来(两个都指向同一个Map),然后设置MapControl为活动的Control
m_controlsSynchronizer.BindControls(true);
//为了在切换MapControl和PageLayoutControl视图同步,要添加Framework Control m_controlsSynchronizer.AddFrameworkControl(axToolbarControl1.Object); m_controlsSynchronizer.AddFrameworkControl(this.axTOCControl1.Object); // 添加打开命令按钮到工具条
OpenNewMapDocument openMapDoc = new OpenNewMapDocument(m_controlsSynchronizer); axToolbarControl1.AddItem(openMapDoc, -1, 0, false, -1, esriCommandStyles.esriCommandStyleIconOnly); 因为我们自动派生了打开文档类,并自己将其添加到工具条,所以我们就不需要工具条原来的“打开”按钮了,可以ToolbarControl的属性中将其删除。 下面,我们可完成上一讲遗留的功能了。 ///
/// 新建地图命令 ///
///
private void New_Click(object sender, EventArgs e) {
//询问是否保存当前地图 DialogResult res = MessageBox.Show(\是否保存当前地图?\\提示\MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (res == DialogResult.Yes) {
//如果要保存,调用另存为对话框
ICommand command = new ControlsSaveAsDocCommandClass(); if (m_mapControl != null)
command.OnCreate(m_controlsSynchronizer.MapControl.Object); else
command.OnCreate(m_controlsSynchronizer.PageLayoutControl.Object); command.OnClick(); }
//创建新的地图实例
IMap map = new MapClass(); map.Name = \
m_controlsSynchronizer.MapControl.DocumentFilename = string.Empty; //更新新建地图实例的共享地图文档
m_controlsSynchronizer.ReplaceMap(map); }
///
/// 打开地图文档Mxd命令 ///
///
private void Open_Click(object sender, EventArgs e) {
if (this.axMapControl1.LayerCount > 0) {
DialogResult result = MessageBox.Show(\是否保存当前地图?\警告\MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (result == DialogResult.Cancel) return;
if (result == DialogResult.Yes) this.Save_Click(null, null); }
OpenNewMapDocument openMapDoc = new OpenNewMapDocument(m_controlsSynchronizer);
openMapDoc.OnCreate(m_controlsSynchronizer.MapControl.Object); openMapDoc.OnClick(); }
在添加数据AddData时,我们也要进行地图共享,故在AddData_Click函数后面添加如下代码:
IMap pMap = this.axMapControl1.Map;
this.m_controlsSynchronizer.ReplaceMap(pMap);
在另存为地图文档时,有可能会丢失数据,因此我们需要提示用户以确认操作,故需修改SaveAs_Click函数,如下所示:
///
/// 另存为地图文档命令 ///
///
private void SaveAs_Click(object sender, EventArgs e) {
//如果当前视图为MapControl时,提示用户另存为操作将丢失PageLayoutControl中的设置 if (m_controlsSynchronizer.ActiveControl is IMapControl3) {
if (MessageBox.Show(\另存为地图文档将丢失制版视图的设置\\r\\n您要继续吗?\提示\MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) return; }
//调用另存为命令
ICommand command = new ControlsSaveAsDocCommandClass(); command.OnCreate(m_controlsSynchronizer.ActiveControl); command.OnClick(); }
在切换视图时,我们要激活相关的视图,故在设计视图的属性面板中选择tabControl2控件,再选择事件按钮,找到“SelectedIndexChanged”事件双击添加之。其实现代码如下所示: ///
/// 切换地图和制版视图 ///
///
private void tabControl2_SelectedIndexChanged(object sender, EventArgs e) {
if (this.tabControl2.SelectedIndex == 0) {
//激活MapControl
m_controlsSynchronizer.ActivateMap(); } else
{
//激活PageLayoutControl
m_controlsSynchronizer.ActivatePageLayout(); } } 5、编译运行
按F5编译运行程序,至此我们完成了MapControl和PageLayoutControl两种视图的同步工作。
第四讲 状态栏信息的添加与实现
在上一讲中,我们完成了 MapControl 和 PageLayoutControl 两种视图的同步工作,本讲我们将完成状态栏信息的添加与实现。
应用程序的状态栏一般用来显示程序的当前状态,当前所使用的工具。 GIS 应用程序一般也在状态栏显示当前光标的坐标、比例尺等信息。
学习完本讲内容,您将学会状态栏编程的基本方法,并且能够在我们的程序的状态栏中添加且显示以下信息: 当前所用工具信息 当前比例尺 当前坐标
1、 添加状态栏项目
在设计视图中,点击窗体中的状态栏,在其属性面板中找到“ Items ”项,单击其右边的按钮,在下拉框中选择“ StatusLabel ”,单击“添加按钮”,依次添加四个 StatusLabel ,依次修改属性参数如下表所示:
设置好之后如下所示:
Tips : 我们
设
计
出
的
状
态
栏
最
终
如
下
所
示
:
Spring 属性表示可以按状态栏剩余空间自动伸缩。所以加入 Blank 项目,只是为了占个位子,以达到 ScaleLabel 和 CoordinateLabel 项目右对齐而 MessageLabel 项目左对齐的目的。
2、 显示当前所用工具信息
首先添加 axToolbarControl1 的 OnMouseMove 事件 ( 相信大家看了以上的教程,已经知道怎么添加事件了吧,还不知道的建议再温习下前几讲的内容 ) 。在其事件响应函数代码如下: private void axToolbarControl1_OnMouseMove(object sender, IToolbarControlEvents_OnMouseMoveEvent e) {
// 取得鼠标所在工具的索引号
int index = axToolbarControl1.HitTest(e.x, e.y, false); if (index != -1) {
// 取得鼠标所在工具的 ToolbarItem
IToolbarItem toolbarItem = axToolbarControl1.GetItem(index); // 设置状态栏信息
MessageLabel.Text = toolbarItem.Command.Message; } else {
MessageLabel.Text = \就绪 \} }
3、 显示当前比例尺
添加 axMapControl1 的 OnMouseMove 事件,其代码如下:
private void axMapControl1_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e) {
// 显示当前比例尺
ScaleLabel.Text = \比例尺 1:\}
4、 显示当前坐标
显示当前坐标也是 axMapControl1 的 OnMouseMove 事件中响应,故只要在 axMapControl1_OnMouseMove 函数中添加如下代码即可: // 显示当前坐标
CoordinateLabel.Text=\当前坐标X =\\this.axMapControl1.MapUnits;
按 F5 编译运行,可以看到,我们的程序已经能够正常工作了。但是细心的你可能会发现,当前坐标的后面的坐标单位为“ esriUnknownUnits ”或“ esriMeters ”之类,即系统在正常单位的前面加上了“ esri ”,追求完美的我们自然看得不舒服。那就进行简单的替换吧。 首先定义个全局坐标单位变量 sMapUnits ,如下所示:
private string sMapUnits;
//再 Form1_Load 函数中进行初始化: sMapUnits = \
添加 axMapControl1 控件的 OnMapReplaced 事件,在事件响应函数中进行坐标单位替换,代码如下:
private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e) {
esriUnits mapUnits = axMapControl1.MapUnits; switch (mapUnits) {
case esriUnits.esriCentimeters: sMapUnits = \break;
case esriUnits.esriDecimalDegrees: sMapUnits = \break;
case esriUnits.esriDecimeters: sMapUnits = \break;
case esriUnits.esriFeet: sMapUnits = \break;
case esriUnits.esriInches: sMapUnits = \break;
case esriUnits.esriKilometers: sMapUnits = \break;
case esriUnits.esriMeters: sMapUnits = \break;
case esriUnits.esriMiles: sMapUnits = \break;
case esriUnits.esriMillimeters: sMapUnits = \break;
case esriUnits.esriNauticalMiles: sMapUnits = \break;
case esriUnits.esriPoints: sMapUnits = \break;
case esriUnits.esriUnknownUnits: sMapUnits = \break;
case esriUnits.esriYards: sMapUnits = \break; } }
5、 编译运行
按 F5 编译运行程序。如果你足够细心的话,相信你已经成功了! 在本讲中,介绍中 StatusStrip 控件的基本使用方法和 AE 中当所用工具信息、当前比例尺和当前坐标的显示调用方法。
第五讲 鹰眼的实现
在上一讲中,我们实现了状态栏的相关信息显示,在这一讲中我们将要实现鹰眼功能。
所谓的鹰眼,就是一个缩略地图,上面有一个矩形框,矩形框区域就是当前显示的地图区域,拖动矩形框可以改变当前地图显示的位置,改变矩形框的大小,可以改变当前地图的显示区域大小,从起到导航的作用。鹰眼是地图浏览中常用的功能之一。
关于鹰眼的实现方式,最常用的是用一个 MapControl 控件显示地图全图,并在上面画一个红色矩形框表示当前地图的显示范围,并实现鹰眼 MapControl 与主窗体的 MapControl 互动。本讲最终效果如下所示:
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 \ else return \ } }
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; } } } }
移除图层类RemoveLayer代码:
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; namespace _sdnMap {
///
public sealed class RemoveLayer : BaseCommand {
private IMapControl3 m_mapControl; public RemoveLayer() {
base.m_caption = \ }
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; } } }
放大至整个图层类ZoomToLayer:
using ESRI.ArcGIS.ADF.BaseClasses; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; namespace _sdnMap {
///
/// 放大至整个图层 ///
public sealed class ZoomToLayer : BaseCommand {
private IMapControl3 m_mapControl; public ZoomToLayer() {
base.m_caption = \ }
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; } } }
以上三个工具或命令的实现代码比较简单,在此不过多的分析,请读者自行理解。
下面在Form1_Load函数中进行菜单项的添加,代码如下: //添加自定义菜单项到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(\//以二级菜单的形式添加内置的“地图浏览”菜单
m_menuMap.AddSubMenu(\//添加自定义菜单项到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);
3、弹出右键菜单
顾名思义,右键菜单是在鼠标右键按下的时候弹出,所以我们要添加TOCControl1控件的OnMouseDown事件,实现代码如下:
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);
//设置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); }
同样的方法,我们也可以实现主地图控件的右键菜单,以方便地图浏览。添加MapControl1控件的OnMouseDown事件,实现代码如下:
///
/// 主地图控件的右键响应函数 ///
///
private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e) {
if (e.button == 2) {
//弹出右键菜单
m_menuMap.PopupMenu(e.x,e.y,m_mapControl.hWnd); } }
4、编译运行
按F5编译运行程序,你会发现,原来右键菜单实现起来是这么的简单啊!
下一讲中,我将给大家带的是TOCControl控件中图层拖拽(Drag and Drop)的实现。
第七讲 图层符号选择器的实现(1)
在上一讲中,我们实现了右键菜单(ContextMenu)的添加与实现,在最后我预留给下一讲的问题是TOCControl控件图层拖拽的实现。后来发现此功能的实现异常简单,只要在TOCControl的属性页中,勾选“Enable Layer Drag and Drop”即可。 (教程Bug及优化方案1查看这里:http://www.3sdn.net/gis2dev/ae/2009-04-11/437.html) 这一讲,我们要实现的是图层符号选择器,与ArcMap中的Symbol Selector的类似。本讲较前几讲而言,些许有些复杂,不过只要仔细琢磨,认真操作,你就很容易实现如下所示的符号选择器。因为本讲篇幅较长,故我将其分成两个阶段,本文是第一阶段。
图1: 图2:
在AE开发中,符号选择器有两种实现方式。一是在程序中直接调用ArcMap中的符号选择器,如图2所示: 二是自定义符号选择器,如图1所示。 由于第一种方式前提是必须安装ArcGIS Desktop,其界面还是英文的,而对二次开发来说,大部分用户希望应该是中文界面。因此开发人员通常选择第二种方式,本讲也着重讲解第二种方式。 通过对《ArcGIS Engine+C#实例开发教程》前六讲的学习,我已经假定你已经基本熟悉C#语言和VS2005的操作,故在下面的教程中,我不准备说明每一步骤的具体操作方法,而只是说明操作步骤,以节省时间和篇幅。
1.直接调用ArcMap中的符号选择器
(1)添加ESRI.ArcGIS.DisplayUI的引用。分别在解决方案管理器和代码中添加引用。 (2)添加TOCControl的Double_Click事件。 (3)实现TOCControl的Double_Click事件。
因为种方法不是本讲的重点,故不对代码进行分析,有兴趣的读者请自行理解或结合后面的内容理解。代码如下: private void axTOCControl1_OnDoubleClick(object sender, ITOCControlEvents_OnDoubleClickEvent e) {
esriTOCControlItem toccItem = esriTOCControlItem.esriTOCControlItemNone; ILayer iLayer = null;
IBasicMap iBasicMap = null; object unk = null; object data = null; if (e.button == 1) {
axTOCControl1.HitTest(e.x, e.y, ref toccItem, ref iBasicMap, ref iLayer, ref unk, ref data);
System.Drawing.Point pos = new System.Drawing.Point(e.x, e.y); if (toccItem == esriTOCControlItem.esriTOCControlItemLegendClass) {
ESRI.ArcGIS.Carto.ILegendClass pLC = new LegendClassClass(); ESRI.ArcGIS.Carto.ILegendGroup pLG = new LegendGroupClass(); if (unk is ILegendGroup) {
pLG = (ILegendGroup)unk; }
pLC = pLG.get_Class((int)data); ISymbol pSym;
pSym = pLC.Symbol;
ESRI.ArcGIS.DisplayUI.ISymbolSelector pSS = new
ESRI.ArcGIS.DisplayUI.SymbolSelectorClass(); bool bOK = false; pSS.AddSymbol(pSym);
bOK = pSS.SelectSymbol(0); if (bOK) {
pLC.Symbol = pSS.GetSymbolAt(0); }
this.axMapControl1.ActiveView.Refresh(); this.axTOCControl1.Refresh(); } } }
(4)编译运行即可。
2.自定义符号选择器
AE9.2提供了SymbologyControl控件,极大的方便了图层符号选择器的制作。本讲实现的符号选择器有如下功能。 用户双击TOCControl控件中图层的符号时,弹出选择符号对话框,对话框能够根据图层类型自动加载相应的符号,如点、线、面。用户可以调整符号的颜色、线宽、角度等参数。还可以打开自定义的符号文件(*.ServerStyle),加载更多的符号。
2.1 新建符号选择器窗体 新建Winodws窗体,命名为SymbolSelectorFrm,修改窗体的Text属性为“选择符号”。并添加SymboloryControl、PictureBox、Button、Label、NumericUpDown、GroupBox、ColorDialog、OpenFileDialog、ContextMenuStrip控件。控件布局如下所示:
图3:
2.2 设置控件属性
设置相应控件的相关属性,如下表所示(空则不用修改):
2.3 添加引用
在解决方案资源管理器中添加ArcGIS Engine的ESRI.ArcGIS.Geodatabase引用,在SymbolSelectorFrm.cs文件中添加如下引用代码:
using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Display; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.SystemUI; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.Geodatabase;
2.4 初始化
(1) 添加SymbolSelectorFrm的全局变量,代码如下: private IStyleGalleryItem pStyleGalleryItem; private ILegendClass pLegendClass; private ILayer pLayer; public ISymbol pSymbol;
public Image pSymbolImage;
(2) 修改SymbolSelectorFrm的构造函数,传入图层和图例接口。代码如下: ///
/// 构造函数,初始化全局变量 ///
/// ///
public SymbolSelectorFrm(ILegendClass tempLegendClass, ILayer tempLayer) {
InitializeComponent();
this.pLegendClass = tempLegendClass; this.pLayer = tempLayer; }
(3) 添加SymbolControl的SymbologyStyleClass设置函数SetFeatureClassStyle(),代码如下: ///
/// 初始化SymbologyControl的StyleClass,图层如果已有符号,则把符号添加到SymbologyControl中的第一个符号,并选中 ///
///
private void SetFeatureClassStyle(esriSymbologyStyleClass symbologyStyleClass) {
this.axSymbologyControl.StyleClass = symbologyStyleClass; ISymbologyStyleClass pSymbologyStyleClass = this.axSymbologyControl.GetStyleClass(symbologyStyleClass); if (this.pLegendClass != null) {
IStyleGalleryItem currentStyleGalleryItem = new ServerStyleGalleryItem(); currentStyleGalleryItem.Name = \当前符号\
currentStyleGalleryItem.Item = pLegendClass.Symbol;
pSymbologyStyleClass.AddItem(currentStyleGalleryItem,0); this.pStyleGalleryItem = currentStyleGalleryItem; }
pSymbologyStyleClass.SelectItem(0); }
(4) 添加注册表读取函数ReadRegistry(),此函数从注册表中读取ArcGIS的安装路径,代码如下: ///
/// 从注册表中取得指定软件的路径 ///
///
private string ReadRegistry(string sKey) {
//Open the subkey for reading
Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(sKey, true); if (rk == null) return \
// Get the data from a specified item in the key. return (string)rk.GetValue(\}
(5) 添加SymbolSelectorFrm的Load事件。根据图层类型为SymbologyControl导入相应的符号样式文件,如点、线、面,并设置控件的可视性。代码如下:
private void SymbolSelectorFrm_Load(object sender, EventArgs e) {
//取得ArcGIS安装路径
string sInstall = ReadRegistry(\//载入ESRI.ServerStyle文件到SymbologyControl
this.axSymbologyControl.LoadStyleFile(sInstall + \
//确定图层的类型(点线面),设置好SymbologyControl的StyleClass,设置好各控件的可见性(visible) IGeoFeatureLayer pGeoFeatureLayer = (IGeoFeatureLayer)pLayer; switch (((IFeatureLayer)pLayer).FeatureClass.ShapeType) {
case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint:
this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassMarkerSymbols); this.lblAngle.Visible = true; this.nudAngle.Visible = true; this.lblSize.Visible = true; this.nudSize.Visible = true; this.lblWidth.Visible = false; this.nudWidth.Visible = false;
this.lblOutlineColor.Visible = false; this.btnOutlineColor.Visible = false; break;
case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline:
this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassLineSymbols); this.lblAngle.Visible = false; this.nudAngle.Visible = false; this.lblSize.Visible = false; this.nudSize.Visible = false; this.lblWidth.Visible = true; this.nudWidth.Visible = true;
this.lblOutlineColor.Visible = false; this.btnOutlineColor.Visible = false; break;
case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon:
this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassFillSymbols); this.lblAngle.Visible = false; this.nudAngle.Visible = false; this.lblSize.Visible = false; this.nudSize.Visible = false; this.lblWidth.Visible = true; this.nudWidth.Visible = true;
this.lblOutlineColor.Visible = true; this.btnOutlineColor.Visible = true; break;
case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryMultiPatch:
this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassFillSymbols); this.lblAngle.Visible = false; this.nudAngle.Visible = false; this.lblSize.Visible = false; this.nudSize.Visible = false; this.lblWidth.Visible = true; this.nudWidth.Visible = true;
this.lblOutlineColor.Visible = true; this.btnOutlineColor.Visible = true; break; default:
this.Close(); break; }
}
(6) 双击确定按钮和取消按钮,分别添加如下代码: ///
///
private void btnOK_Click(object sender, EventArgs e) {
//取得选定的符号
this.pSymbol = (ISymbol)pStyleGalleryItem.Item; //更新预览图像
this.pSymbolImage = this.ptbPreview.Image; //关闭窗体 this.Close(); }
///
///
private void btnCancel_Click(object sender, EventArgs e) {
this.Close(); }
(7) 为了操作上的方便,我们添加SymbologyControl的DoubleClick事件,当双击符号时同按下确定按钮一样,选定符号并关闭符号选择器窗体。代码如下: ///
/// 双击符号同单击确定按钮,关闭符号选择器。 ///
///
this.btnOK.PerformClick(); }
(8) 再添加符号预览函数,当用户选定某一符号时,符号可以显示在PictureBox控件中,方便预览,函数代码如下: ///
/// 把选中并设置好的符号在picturebox控件中预览 ///
private void PreviewImage() {
stdole.IPictureDisp picture = this.axSymbologyControl.GetStyleClass(this.axSymbologyControl.StyleClass).PreviewItem(pStyleGalleryItem, this.ptbPreview.Width, this.ptbPreview.Height); System.Drawing.Image image = System.Drawing.Image.FromHbitmap(new System.IntPtr(picture.Handle)); this.ptbPreview.Image = image; }
(9) 当SymbologyControl的样式改变时,需要重新设置符号参数调整控件的可视性,故要添加
SymbologyControl的OnStyleClassChanged事件,事件代码与Load事件类似,如下: ///
/// 当样式(Style)改变时,重新设置符号类型和控件的可视性 ///
///
switch ((esriSymbologyStyleClass)(e.symbologyStyleClass)) {
case esriSymbologyStyleClass.esriStyleClassMarkerSymbols: this.lblAngle.Visible = true; this.nudAngle.Visible = true; this.lblSize.Visible = true; this.nudSize.Visible = true; this.lblWidth.Visible = false; this.nudWidth.Visible = false;
this.lblOutlineColor.Visible = false; this.btnOutlineColor.Visible = false; break;
case esriSymbologyStyleClass.esriStyleClassLineSymbols: this.lblAngle.Visible = false; this.nudAngle.Visible = false; this.lblSize.Visible = false; this.nudSize.Visible = false; this.lblWidth.Visible = true; this.nudWidth.Visible = true;
this.lblOutlineColor.Visible = false; this.btnOutlineColor.Visible = false; break;
case esriSymbologyStyleClass.esriStyleClassFillSymbols: this.lblAngle.Visible = false; this.nudAngle.Visible = false; this.lblSize.Visible = false; this.nudSize.Visible = false; this.lblWidth.Visible = true; this.nudWidth.Visible = true;
this.lblOutlineColor.Visible = true; this.btnOutlineColor.Visible = true; break; } }
2.5 调用自定义符号选择器
通过以上操作,本符号选择器雏形已经完成,我们可以3sdnMap主窗体中调用并进行测试。如果您已经完成“直接调用ArcMap中的符号选择器”这一节,请注释axTOCControl1_OnDoubleClick事件响应函数里的代码,并添加如下代码。如果您是直接学习自定义符号选择器这一节的,请先添加axTOCControl1控件的OnDoubleClick事件,再添加如下事件响应函数代码: ///
/// 双击TOCControl控件时触发的事件 ///
///
private void axTOCControl1_OnDoubleClick(object sender, ITOCControlEvents_OnDoubleClickEvent e) {
esriTOCControlItem itemType = esriTOCControlItem.esriTOCControlItemNone; IBasicMap basicMap = null; ILayer layer = null; object unk = null; object data = null;
axTOCControl1.HitTest(e.x, e.y, ref itemType, ref basicMap, ref layer, ref unk, ref data); if (e.button == 1) {
if(itemType==esriTOCControlItem.esriTOCControlItemLegendClass) { //取得图例
ILegendClass pLegendClass = ((ILegendGroup)unk).get_Class((int)data); //创建符号选择器SymbolSelector实例
SymbolSelectorFrm SymbolSelectorFrm = new SymbolSelectorFrm(pLegendClass, layer); if (SymbolSelectorFrm.ShowDialog() == DialogResult.OK) {
//局部更新主Map控件
m_mapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography,null, null);
//设置新的符号
pLegendClass.Symbol = SymbolSelectorFrm.pSymbol; //更新主Map控件和图层控件
this.axMapControl1.ActiveView.Refresh(); this.axTOCControl1.Refresh(); } } }
按F5编译运行,相信你已经看到自己新手打造的符号选择器已经出现在眼前了。当然,它还比较简陋,下面我们将一起把它做得更完美些。
第七讲 图层符号选择器的实现(2)
在第七讲 图层符号选择器的实现的第一阶段中,我们完成了符号选择器窗体的创建与调用。在第二阶段中,我们继续完成符号参数的调整与“更多符号”的加载。
2.6 符号参数调整
在地图整饰中,符号参数的调整是必须的功能。下面我们将实现符号颜色、外框颜色、线宽、角度等参数的调整。 (1) 添加SymbologyControl的OnItemSelected事件,此事件在鼠标选中符号时触发,此时显示出选定符号的初始参数,事件响应函数代码如下: ///
/// 选中符号时触发的事件 ///
///
pStyleGalleryItem = (IStyleGalleryItem)e.styleGalleryItem; Color color;
switch (this.axSymbologyControl.StyleClass) {
//点符号
case esriSymbologyStyleClass.esriStyleClassMarkerSymbols:
color = this.ConvertIRgbColorToColor(((IMarkerSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
//设置点符号角度和大小初始值
this.nudAngle.Value = (decimal)((IMarkerSymbol)this.pStyleGalleryItem.Item).Angle; this.nudSize.Value = (decimal)((IMarkerSymbol)this.pStyleGalleryItem.Item).Size; break; //线符号
case esriSymbologyStyleClass.esriStyleClassLineSymbols:
color = this.ConvertIRgbColorToColor(((ILineSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
//设置线宽初始值
this.nudWidth.Value = (decimal)((ILineSymbol)this.pStyleGalleryItem.Item).Width; break; //面符号
case esriSymbologyStyleClass.esriStyleClassFillSymbols:
color = this.ConvertIRgbColorToColor(((IFillSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
this.btnOutlineColor.BackColor = this.ConvertIRgbColorToColor(((IFillSymbol)pStyleGalleryItem.Item).Outline.Color as IRgbColor); //设置外框线宽度初始值 this.nudWidth.Value = (decimal)((IFillSymbol)this.pStyleGalleryItem.Item).Outline.Width; break; default:
color = Color.Black; break; }
//设置按钮背景色
this.btnColor.BackColor = color; //预览符号
this.PreviewImage(); }
(2) 调整点符号的大小
添加nudSize控件的ValueChanged事件,即在控件的值改变时响应此事件,然后重新设置点符号的大小。代码如下:
///
/// 调整符号大小-点符号 ///
///
private void nudSize_ValueChanged(object sender, EventArgs e) {
((IMarkerSymbol)this.pStyleGalleryItem.Item).Size = (double)this.nudSize.Value; this.PreviewImage(); }
(3) 调整点符号的角度
添加nudAngle控件的ValueChanged事件,以重新设置点符号的角度。代码如下: ///
/// 调整符号角度-点符号 ///
///
private void nudAngle_ValueChanged(object sender, EventArgs e) {
((IMarkerSymbol)this.pStyleGalleryItem.Item).Angle = (double)this.nudAngle.Value; this.PreviewImage();
}
(4) 调整线符号和面符号的线宽
添加nudWidth控件的ValueChanged事件,以重新设置线符号的线宽和面符号的外框线的线宽。代码如下: ///
/// 调整符号宽度-限于线符号和面符号 ///
///
private void nudWidth_ValueChanged(object sender, EventArgs e) {
switch (this.axSymbologyControl.StyleClass) {
case esriSymbologyStyleClass.esriStyleClassLineSymbols: ((ILineSymbol)this.pStyleGalleryItem.Item).Width = Convert.ToDouble(this.nudWidth.Value); break;
case esriSymbologyStyleClass.esriStyleClassFillSymbols: //取得面符号的轮廓线符号
ILineSymbol pLineSymbol = ((IFillSymbol)this.pStyleGalleryItem.Item).Outline; pLineSymbol.Width = Convert.ToDouble(this.nudWidth.Value);
((IFillSymbol)this.pStyleGalleryItem.Item).Outline = pLineSymbol; break; }
this.PreviewImage(); }
(5) 颜色转换 在ArcGIS Engine中,颜色由IRgbColor接口实现,而在.NET框架中,颜色则由Color结构表示。故在调整颜色参数之前,我们必须完成以上两种不同颜色表示方式的转换。关于这两种颜色结构的具体信息,请大家自行查阅相关资料。下面添加两个颜色转换函数。
ArcGIS Engine中的IRgbColor接口转换至.NET中的Color结构的函数: ///
/// 将ArcGIS Engine中的IRgbColor接口转换至.NET中的Color结构 ///
///
///
return ColorTranslator.FromOle(pRgbColor.RGB); }
.NET中的Color结构转换至于ArcGIS Engine中的IColor接口的函数:
///
/// 将.NET中的Color结构转换至于ArcGIS Engine中的IColor接口 ///
/// ///
public IColor ConvertColorToIColor(Color color) {
IColor pColor = new RgbColorClass();
pColor.RGB = color.B * 65536 + color.G * 256 + color.R; return pColor; }
(6) 调整所有符号的颜色
选择颜色时,我们调用.NET的颜色对话框ColorDialog,选定颜色后,修改颜色按钮的背景色为选定的颜色,以方便预览。双击btnColor按钮,添加如下代码: ///
///
private void btnColor_Click(object sender, EventArgs e) {
//调用系统颜色对话框
if (this.colorDialog.ShowDialog() == DialogResult.OK) {
//将颜色按钮的背景颜色设置为用户选定的颜色
this.btnColor.BackColor = this.colorDialog.Color; //设置符号颜色为用户选定的颜色
switch (this.axSymbologyControl.StyleClass) {
//点符号
case esriSymbologyStyleClass.esriStyleClassMarkerSymbols: ((IMarkerSymbol)this.pStyleGalleryItem.Item).Color this.ConvertColorToIColor(this.colorDialog.Color); break; //线符号
case esriSymbologyStyleClass.esriStyleClassLineSymbols: ((ILineSymbol)this.pStyleGalleryItem.Item).Color this.ConvertColorToIColor(this.colorDialog.Color); break; //面符号
case esriSymbologyStyleClass.esriStyleClassFillSymbols: ((IFillSymbol)this.pStyleGalleryItem.Item).Color this.ConvertColorToIColor(this.colorDialog.Color); break; }
//更新符号预览
this.PreviewImage(); } }
(7) 调整面符号的外框线颜色
同上一步类似,双击btnOutlineColor按钮,添加如下代码: ///
///
private void btnOutlineColor_Click(object sender, EventArgs e) {
if (this.colorDialog.ShowDialog() == DialogResult.OK) {
//取得面符号中的外框线符号
ILineSymbol pLineSymbol = ((IFillSymbol)this.pStyleGalleryItem.Item).Outline; //设置外框线颜色
pLineSymbol.Color = this.ConvertColorToIColor(this.colorDialog.Color);
= = =
正在阅读:
ArcGIS - Engine92+C++实例开发详细教程06-01
小学骨干校长培训报告12-22
煤矿调度员的工作培训资料06-08
苏教版三年级上数学易错题01-05
数字电子技术基础期末复习试题04-02
人与自然的观后感04-01
新建 Microsoft PowerPoint 演示文稿05-25
防范和应对强对流天气应急预案 204-23
写给老公的情书02-07
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 实例
- 教程
- ArcGIS
- Engine
- 开发
- 详细
- 92
- AHP层级分析法简介
- 事故应急救援综合和专项预案汇总
- 5S实施指南-内容
- 以岸英为榜样+做最好的自己 - 图文
- 2016华医 临床实践技能操作
- 严新气功修炼语录
- 昆明55分区的规划细则
- 称骨算命
- 最新-山东省卫生计生系统人员针对性普法考试答案(2015-10-09-ne
- 亲子朗诵稿:爱与梦想
- 语文学科前沿发展动态综述
- 外研版英语必修三 Module 3 The Violence of Nature
- 中国换热器行业调查分析及发展趋势预测报告(2016版)
- 2014-2015学年 外研八年级上学期Module11试题
- 2014年的房价到底会不会跌?
- 雨污水管道下井施工安全专项方案
- 乐观的人生态度
- 中国古代文论复习及参考答案
- 创先争优活动第二阶段总结
- 蜡