ArcGIS - Engine92+C++实例开发详细教程

更新时间:2024-06-01 16:36:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第一讲 桌面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 ///

/// public IMap Create() {

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结构 ///

///

/// .NET中的System.Drawing.Color结构表示ARGB颜色 public Color ConvertIRgbColorToColor(IRgbColor pRgbColor) {

return ColorTranslator.FromOle(pRgbColor.RGB); }

.NET中的Color结构转换至于ArcGIS Engine中的IColor接口的函数:

///

/// 将.NET中的Color结构转换至于ArcGIS Engine中的IColor接口 ///

/// /// 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);

= = =

本文来源:https://www.bwwdw.com/article/jln6.html

Top