原文:《ArcGIS Engine+C#实例开发教程》第七讲 图层符号选择器的实现
摘要:我们要实现的是图层符号选择器,与ArcMap中的Symbol Selector的类似。本讲较前几讲而言,些许有些复杂,不过只要仔细琢磨,认真操作,你就很容易实现如下所示的符号选择器。
教程目录:
第三讲 MapControl与PageLayoutControl同步
------------------------------------------------------------------
在上一讲中,我们实现了右键菜单(ContextMenu)的添加与实现,在最后我预留给下一讲的问题是TOCControl控件图层拖拽的实现。后来发现此功能的实现异常简单,只要在TOCControl的属性页中,勾选“Enable Layer Drag and Drop”即可。
这一讲,我们要实现的是图层符号选择器,与ArcMap中的Symbol Selector的类似。本讲较前几讲而言,些许有些复杂,不过只要仔细琢磨,认真操作,你就很容易实现如下所示的符号选择器。因为本讲篇幅较长,故我将其分成两个阶段,本文是第一阶段。
图1
在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事件。 因为种方法不是本讲的重点,故不对代码进行分析,有兴趣的读者请自行理解或结合后面的内容理解。代码如下:
(4)编译运行即可。 |
2. 自定义符号选择器
AE9.2提供了SymbologyControl控件,极大的方便了图层符号选择器的制作。本讲实现的符号选择器有如下功能。
用户双击TOCControl控件中图层的符号时,弹出选择符号对话框,对话框能够根据图层类型自动加载相应的符号,如点、线、面。用户可以调整符号的颜色、线宽、角度等参数。还可以打开自定义的符号文件(*.ServerStyle),加载更多的符号。
2.1 新建符号选择器窗体
新建Winodws窗体,命名为SymbolSelectorFrm,修改窗体的Text属性为“选择符号”。并添加SymboloryControl、PictureBox、Button、Label、NumericUpDown、GroupBox、ColorDialog、OpenFileDialog、ContextMenuStrip控件。控件布局如下所示:
图3
2.2 设置控件属性
设置相应控件的相关属性,如下表所示(空则不用修改):
控件 |
Name属性 |
Text属性 |
其它 |
SymbologyControl |
axSymbologyControl |
||
PictureBox |
ptbPreview |
||
Label |
lblColor |
颜色 |
|
Label |
lblSize |
大小 |
|
Label |
lblWidth |
线宽 |
|
Label |
lblAngle |
角度 |
|
Label |
lblOutlineColor |
外框颜色 |
|
NumericUpDown |
nudSize |
||
NumericUpDown |
nudWidth |
||
NumericUpDown |
nudAngle |
||
Button |
btnColor |
(设置为空) |
|
Button |
btnOutlineColor |
(设置为空) |
|
Button |
btnMoreSymbols |
更多符号 |
|
Button |
btnOK |
确定 |
DialogResult属性设为OK |
Button |
btnCancel |
取消 |
|
GroupBox |
groupBox1 |
预览 |
|
GroupBox |
groupBox2 |
设置 |
|
ColorDialog |
colorDialog |
||
OpenFileDialog |
openFileDialog |
Filter属性设置为: Styles 文件|*.ServerStyle |
|
ContextMenuStrip |
contextMenuStripMoreSymbol |
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的构造函数,传入图层和图例接口。代码如下:
/// <summary>
/// 构造函数,初始化全局变量 /// </summary> /// <param name="tempLegendClass">TOC图例</param> /// <param name="tempLayer">图层</param> public SymbolSelectorFrm(ILegendClass tempLegendClass, ILayer tempLayer) { InitializeComponent(); this.pLegendClass = tempLegendClass; this.pLayer = tempLayer; } |
(3) 添加SymbolControl的SymbologyStyleClass设置函数SetFeatureClassStyle(),代码如下:
/// <summary> /// 初始化SymbologyControl的StyleClass,图层如果已有符号,则把符号添加到SymbologyControl中的第一个符号,并选中 /// </summary> /// <param name="symbologyStyleClass"></param> 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的安装路径,代码如下:
/// <summary>
/// 从注册表中取得指定软件的路径 /// </summary> /// <param name="sKey"></param> /// <returns></returns> 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("InstallDir"); } |
(5) 添加SymbolSelectorFrm的Load事件。根据图层类型为SymbologyControl导入相应的符号样式文件,如点、线、面,并设置控件的可视性。代码如下:
private void SymbolSelectorFrm_Load(object sender, EventArgs e) { //取得ArcGIS安装路径 string sInstall = ReadRegistry("SOFTWARE\\ESRI\\CoreRuntime"); //载入ESRI.ServerStyle文件到SymbologyControl this.axSymbologyControl.LoadStyleFile(sInstall + "\\Styles\\ESRI.ServerStyle"); //确定图层的类型(点线面),设置好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) 双击确定按钮和取消按钮,分别添加如下代码:
/// <summary>
/// 确定按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnOK_Click(object sender, EventArgs e) { //取得选定的符号 this.pSymbol = (ISymbol)pStyleGalleryItem.Item; //更新预览图像 this.pSymbolImage = this.ptbPreview.Image; //关闭窗体 this.Close(); } /// <summary> /// 取消按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnCancel_Click(object sender, EventArgs e) { this.Close(); } |
(7) 为了操作上的方便,我们添加SymbologyControl的DoubleClick事件,当双击符号时同按下确定按钮一样,选定符号并关闭符号选择器窗体。代码如下:
/// <summary>
/// 双击符号同单击确定按钮,关闭符号选择器。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void axSymbologyControl_OnDoubleClick(object sender, ESRI.ArcGIS.Controls.ISymbologyControlEvents_OnDoubleClickEvent e) { this.btnOK.PerformClick(); } |
(8) 再添加符号预览函数,当用户选定某一符号时,符号可以显示在PictureBox控件中,方便预览,函数代码如下:
/// <summary> /// 把选中并设置好的符号在picturebox控件中预览 /// </summary> private void PreviewImage() { stdole.IPictureDisppicture =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事件类似,如下:
/// <summary>
/// 当样式(Style)改变时,重新设置符号类型和控件的可视性 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> privatevoid axSymbologyControl_OnStyleClassChanged(object sender,ESRI.ArcGIS.Controls.ISymbologyControlEvents_OnStyleClassChangedEvent e) { 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事件,再添加如下事件响应函数代码:
/// <summary>
/// 双击TOCControl控件时触发的事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> 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编译运行,相信你已经看到自己新手打造的符号选择器已经出现在眼前了。当然,它还比较简陋,下面我们将一起把它做得更完美些。