PLC
直播中

周煌煦

7年用户 1010经验值
私信 关注

如何去实现一种图层符号选择器

如何去实现一种图层符号选择器?

如何去实现一种自定义符号选择器?

回帖(1)

冯琳

2021-9-28 16:26:10
  TOCControl控件相当于ArcMap中左侧的目录树,需要与一个“伙伴控件”协同工作,可以是MapControl、PageLayoutControl、SceneControl或者GlobeControl。伙伴控件的设置可通过TOCControl属性对话框或用SetBuddyControl方法通过编程设置。fangfa
  HitTest方法用来获取用户再TOCControl中点击的相关信息
  public void HitTest(int X,int Y,ref esriTOCControlItem ItemType,ref IBasicMap BasicMap,ref ILayer,ref object Unk,ref object Data);
  ItemType:TOCControl中项的类型,如none、map、layer、heading、或者legend class。
  BasicMap:IMap对象。
  Layer:ILayer对象。
  Unk:ILegendGroup(图例组,一个图层可以有多种符号化方案)对象。
  Data:用户点击的图例组中某个图例的索引号(longInt);联合使用图例组Unk和某个索引号,可以获得用户点击的图例;图例的标题头索引为-1。
  图层符号选择器的实现
  调用ArcMap的符号选择器
  此种方法的前提是电脑上必须安装ArcGIS Desktop,该方法写在axTOCControl控件的双击事件下:
  private void axTOCControl1_OnDoubleClick(object sender, ITOCControlEvents_OnDoubleClickEvent e)
  {
  esriTOCControlItem toccItem = esriTOCControlItem.esriTOCControlItemNone;
  ILayer layer = null; IBasicMap basicMap = null; object unk = null; object data = null;//定义HitTest函数所需的参数
  if(e.button==1)
  {
  axTOCControl1.HitTest(e.x, e.y,ref toccItem, ref basicMap, ref layer, ref unk, ref data);
  {
  ESRI.ArcGIS.Carto.ILegendClass pLC = new LegendClassClass();//用户点击的图例
  ESRI.ArcGIS.Carto.ILegendGroup PLG = new LegendGroupClass();//用户点击的图例组
  if(unk is ILegendGroup)
  {
  PLG = (ILegendGroup)unk;
  }//获取图例组
  pLC=PLG.Class[(int)data];//获取图例组中点击的具体图例
  ISymbol pSym;
  pSym = pLC.Symbol;
  ISymbolSelector pSS = new SymbolSelectorClass();//实例化符号选择器
  bool bOK = false;
  pSS.AddSymbol(pSym);//添加符号的目录
  bOK = pSS.SelectSymbol(0);
  if(bOK)
  {
  pLC.Symbol = pSS.GetSymbolAt(0);//利用0索引检索选中的符号
  }
  this.axMapControl1.ActiveView.Refresh();
  this.axTOCControl1.Refresh();
  }
  }
  }
  ISymbolSelector涉及到的方法说明:
  AddSymbol:决定符号选择器出现时显示的初始符号,例如双击的是面符号,出现的界面也是面界面。
  GetSymbolAt:通过0索引检索符号。
  SelectSymbol:选择符号,检查用户点击确定或取消的返回值。
  效果图如下:
  
  自定义符号选择器
  如果并未安装arcgis desktop又想实现该功能,可以自定义界面来实现:
  界面设计如下:
  
  窗体及控件的属性设置见下表:
  [tr]控件NAMETEXT其它属性设置[/tr]FormGetSymbolByControlForm符号选择器
  AxSymbologyControlaxSymbologyControl1––
  groupBoxgroupBox1预览
  groupBoxgroupBox2设置–
  pictureBoxpictureBox1Dock设置为fill
  Labell_color颜色–
  Labell_size大小-
  Labell_width宽度-
  Labell_angel角度-
  Labell_cofout外框颜色-
  buttonb_color--
  buttonb_cofout--
  numericUpDownn_size--
  numericUpDownn_width--
  numericUpDownn_angle--
  buttonb_more更多符号-
  buttonb_color确定DialogResult属性设为OK
  buttonb_color取消-
  openFileDialogopenFileDialog1-Filter属性设置为:Styles 文件/*.ServerStyle
  ContextMenuStripContextMenur--
  ColorDialogcolorDialog--
  该事件仍旧写在图例双击里:
  代码的基本流程如下:
  获取图层组和图层
  初始化SymbologyControl的StyleClass
  根据图层类型为SymbologyControl导入相应的符号样式文件
  取得选定的符号
  在GetSymbolByControlForm窗体中使用到的全局变量有:
  private IStyleGalleryItem pStyleGalleryItem;//每一个style文件由IStyleGalleryItems组成
  private ILegendClass pLegendClass;//图例组
  private ILayer pLayer;//具体图层
  public ISymbol pSymbol;//符号
  public Image pSymbolImage;//用于预览符号
  bool contextMenuMoreSymbolInitiated = false;
  通过改变GetSymbolByControlForm的参数实现两个窗口之间传值,代码如下:
  public GetSymbolByControlForm(ILegendClass legendClass,ILayer layer)
  {
  InitializeComponent();
  this.pLegendClass = legendClass;//传入选择图例
  this.pLayer = layer;//传入选中图层
  }
  初始化SymbologyControl的StyleClass,图层如果已有符号,则把符号添加到SymbologyControl中的第一个符号,并选中
  private void SetFeatureClassStyle(esriSymbologyStyleClass symbologyStyleClass)
  {
  this.axSymbologyControl1.StyleClass = symbologyStyleClass;
  ISymbologyStyleClass PsymbologyStyleClass = this.axSymbologyControl1.GetStyleClass(symbologyStyleClass);
  if(this.pLegendClass!=null)
  {
  IStyleGalleryItem styleGalleryItem = new ServerStyleGalleryItem();
  styleGalleryItem.Name = “当前符号”;
  styleGalleryItem.Item = pLegendClass.Symbol;
  PsymbologyStyleClass.AddItem(styleGalleryItem, 0);
  this.pStyleGalleryItem = styleGalleryItem;
  }/如果传入的图例不为空,则将其加入至styleGalleryItem中的第一个,默认选中
  PsymbologyStyleClass.SelectItem(0);//传入图例为空,则默认选中第一个
  }
  载入ESRI.ServerStyle文件到SymbologyControl有两种方法:第一种方法是从注册表读取arcgis的安装路径,再使用axSymbologyControl1的LoadDesktopStyleFile()方法载入;也可以在axSymbologyControl1的属性中设置。
  方法一:
  读取注册表的函数(后文无用)
  private string ReadRegistry(string sKey)
  {
  RegistryKey localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
  string InstallDir = string.Empty;
  Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(sKey, true);
  if (rk == null)
  return “”;
  return (string)rk.GetValue(InstallDir);
  }
  2.直接设置(右键属性,Style Files,load~):
  
  在GetSymbolByControlForm窗体的load函数中代码如下(该程序中我采用的是设置属性的方法)
  private void GetSymbolByControlForm_Load(object sender, EventArgs e)
  {
  string sInstall = ESRI.ArcGIS.RuntimeManager.ActiveRuntime.Path;//这也是获取安装路径的一种方法
  // string sInstall = ReadRegistry(“SOFTWARE\ESRI\Desktop10.2”);//获取ArcGIS安装路径
  // this.axSymbologyControl1.LoadDesktopStyleFile(sInstall + “\Styles\ESRI.ServerStyle”);//载入ESRI.ServerStyle文件到SymbologyControl
  IGeoFeatureLayer pGeoFeatureLayer = (IGeoFeatureLayer)pLayer;
  switch(((IFeatureLayer)pLayer).FeatureClass.ShapeType)//确定图层的类型,设置空间按的StyleClass,设置各控件的可见性
  {
  case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint:
  this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassMarkerSymbols);//如果是点要素
  this.l_angel.Visible = true;
  this.n_angle.Visible = true;
  this.l_size.Visible = true;
  this.n_size.Visible = true;
  this.l_width.Visible = false;
  this.n_width.Visible = false;
  this.l_cofout.Visible = false;
  this.b_cofout.Visible = false;
  break;
  case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon:
  this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassFillSymbols);//如果是多边形
  this.l_angel.Visible = false;
  this.n_angle.Visible = false;
  this.l_size.Visible = false;
  this.n_size.Visible = false;
  this.l_width.Visible = true;
  this.n_width.Visible = true;
  this.l_cofout.Visible = true;
  this.b_cofout.Visible = true;
  break;
  case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline:
  this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassLineSymbols);//如果是线要素
  this.l_angel.Visible = false;
  this.n_angle.Visible = false;
  this.l_size.Visible = false;
  this.n_size.Visible = false;
  this.l_width.Visible = true;
  this.n_width.Visible = true;
  this.l_cofout.Visible = false;
  this.b_cofout.Visible = false;
  break;
  default:
  this.Close();
  break;
  }
  单击确定按钮:
  private void b_ok_Click(object sender, EventArgs e)
  {
  this.pSymbol = (ISymbol)pStyleGalleryItem.Item;//取得选定的符号
  this.pSymbolImage = this.pictureBox1.Image;//更新预览图像
  this.Close();//关闭窗体
  }
  单击取消按钮:
  private void b_no_Click(object sender, EventArgs e)
  {
  this.Close();
  }
  双击符号同单击确定按钮
  private void axSymbologyControl1_OnDoubleClick(object sender, ISymbologyControlEvents_OnDoubleClickEvent e)
  {
  this.b_ok.PerformClick();
  }
  将选中的符号在picturebox中预览的函数为
  private void axSymbologyControl1_OnStyleClassChanged(object sender, ISymbologyControlEvents_OnStyleClassChangedEvent e)
  {
  switch (((ISymbologyStyleClass)e.symbologyStyleClass).StyleClass)
  {
  case esriSymbologyStyleClass.esriStyleClassMarkerSymbols:
  this.l_angel.Visible = true;
  this.n_angle.Visible = true;
  this.l_size.Visible = true;
  this.n_size.Visible = true;
  this.l_width.Visible = false;
  this.n_width.Visible = false;
  this.l_cofout.Visible = false;
  this.b_cofout.Visible = false;
  break;
  case esriSymbologyStyleClass.esriStyleClassLineSymbols:
  this.l_angel.Visible = false;
  this.n_angle.Visible = false;
  this.l_size.Visible = false;
  this.n_size.Visible = false;
  this.l_width.Visible = true;
  this.n_width.Visible = true;
  this.l_cofout.Visible = true;
  this.b_cofout.Visible = false;
  break;
  case esriSymbologyStyleClass.esriStyleClassFillSymbols:
  this.l_angel.Visible = false;
  this.n_angle.Visible = false;
  this.l_size.Visible = false;
  this.n_size.Visible = false;
  this.l_width.Visible = true;
  this.n_width.Visible = true;
  this.l_cofout.Visible = true;
  this.b_cofout.Visible = true;
  break;
  default:
  this.Close();
  break;
  }
  }
  选中符号触发的事件
  private void axSymbologyControl1_OnItemSelected(object sender, ISymbologyControlEvents_OnItemSelectedEvent e)
  {
  pStyleGalleryItem = (IStyleGalleryItem)e.styleGalleryItem;
  Color color;
  switch (this.axSymbologyControl1.StyleClass)
  {
  //点符号
  case esriSymbologyStyleClass.esriStyleClassMarkerSymbols:
  color = this.ConvertIRgbColorToColor(((IMarkerSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
  //设置点符号角度和大小初始值
  this.n_angle.Value = (decimal)((IMarkerSymbol)this.pStyleGalleryItem.Item).Angle;
  this.n_size.Value = (decimal)((IMarkerSymbol)this.pStyleGalleryItem.Item).Size;
  break;
  //线符号
  case esriSymbologyStyleClass.esriStyleClassLineSymbols:
  color = this.ConvertIRgbColorToColor(((ILineSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
  //设置线宽初始值
  this.n_width.Value = (decimal)((ILineSymbol)this.pStyleGalleryItem.Item).Width;
  break;
  //面符号
  case esriSymbologyStyleClass.esriStyleClassFillSymbols:
  color = this.ConvertIRgbColorToColor(((IFillSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
  this.b_cofout.BackColor = this.ConvertIRgbColorToColor(((IFillSymbol)pStyleGalleryItem.Item).Outline.Color as IRgbColor);
  //设置外框线宽度初始值
  this.n_width.Value = (decimal)((IFillSymbol)this.pStyleGalleryItem.Item).Outline.Width;
  break;
  default:
  color = Color.Black;
  break;
  }
  //设置按钮背景色
  this.b_color.BackColor = color;
  //预览符号
  this.PreviewImage();
  }
  调整点符号的大小
  private void n_size_ValueChanged(object sender, EventArgs e)
  {
  ((IMarkerSymbol)this.pStyleGalleryItem.Item).Size = (double)this.n_size .Value;
  this.PreviewImage();
  }
  调整点符号的角度
  private void n_angle_ValueChanged(object sender, EventArgs e)
  {
  ((IMarkerSymbol)this.pStyleGalleryItem.Item).Angle = (double)this.n_angle .Value;
  this.PreviewImage();
  }
  调整线符号和面符号的宽度
  private void n_width_ValueChanged(object sender, EventArgs e)
  {
  switch (this.axSymbologyControl1.StyleClass)
  {
  case esriSymbologyStyleClass.esriStyleClassLineSymbols:
  ((ILineSymbol)this.pStyleGalleryItem.Item).Width = Convert.ToDouble(this.n_width .Value);
  break;
  case esriSymbologyStyleClass.esriStyleClassFillSymbols:
  //取得面符号的轮廓线符号
  ILineSymbol pLineSymbol = ((IFillSymbol)this.pStyleGalleryItem.Item).Outline;
  pLineSymbol.Width = Convert.ToDouble(this.n_width .Value);
  ((IFillSymbol)this.pStyleGalleryItem.Item).Outline = pLineSymbol;
  break;
  }
  this.PreviewImage();
  }
  在ArcGIS Engine中,颜色由IRgbColor接口实现,而在.NET框架中,颜色则由Color结构表示。故在调整颜色参数之前,我们必须完成以上两种不同颜色表示方式的转换。
  /// 《summary》
  /// 将ArcGIS Engine中的IRgbColor接口转换至.NET中的Color结构
  /// 《/summary》
  /// 《param name=“pRgbColor”》《/param》
  /// 《returns》《/returns》
  public Color ConvertIRgbColorToColor(IRgbColor pRgbColor)
  {
  return ColorTranslator.FromOle(pRgbColor.RGB);
  }
  /// 《summary》
  /// .NET中的Color接口转换至于ArcGIS Engine中的IColor接口的函数:
  /// 《/summary》
  /// 《param name=“color”》《/param》
  /// 《returns》《/returns》
  public IColor ConvertColorToIColor(Color color)
  {
  IColor pColor = new RgbColorClass();
  pColor.RGB = color.B * 65536 + color.G * 256 + color.R;
  return pColor;
  }
  选择颜色时,我们调用.NET的颜色对话框ColorDialog,选定颜色后,修改颜色按钮的背景色为选定的颜色,以方便预览。点击btnColor按钮,添加如下代码:
  private void b_color_Click(object sender, EventArgs e)
  {
  //调用系统颜色对话框
  if (this.colorDialog.ShowDialog() == DialogResult.OK)
  {
  //将颜色按钮的背景颜色设置为用户选定的颜色
  this.b_color.BackColor = this.colorDialog.Color;
  //设置符号颜色为用户选定的颜色
  switch (this.axSymbologyControl1.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();
  }
  }
  调整面符号的外框线颜色
  private void b_cofout_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);
  //重新设置面符号中的外框线符号
  ((IFillSymbol)this.pStyleGalleryItem.Item).Outline = pLineSymbol;
  //设置按钮背景颜色
  this.b_cofout .BackColor = this.colorDialog.Color;
  //更新符号预览
  this.PreviewImage();
  }
  }
  添加更多符号
  private void b_more_Click(object sender, EventArgs e)
  {
  if (this.contextMenuMoreSymbolInitiated == false)
  {
  string sInstall = ReadRegistry(“SOFTWARE\ESRI\Desktop10.2”);
  string path = System.IO.Path.Combine(sInstall, “Styles”);
  //取得菜单项数量
  string[] styleNames = System.IO.Directory.GetFiles(path, “*.ServerStyle”);
  ToolStripMenuItem[] symbolContextMenuItem = new ToolStripMenuItem[styleNames.Length + 1];
  //循环添加其它符号菜单项到菜单
  for (int i = 0; i 《 styleNames.Length; i++)
  {
  symbolContextMenuItem[i] = new ToolStripMenuItem();
  symbolContextMenuItem[i].CheckOnClick = true;
  symbolContextMenuItem[i].Text = System.IO.Path.GetFileNameWithoutExtension(styleNames[i]);
  if (symbolContextMenuItem[i].Text == “ESRI”)
  {
  symbolContextMenuItem[i].Checked = true;
  }
  symbolContextMenuItem[i].Name = styleNames[i];
  }
  //添加“更多符号”菜单项到菜单最后一项
  symbolContextMenuItem[styleNames.Length] = new ToolStripMenuItem();
  symbolContextMenuItem[styleNames.Length].Text = “添加符号”;
  symbolContextMenuItem[styleNames.Length].Name = “AddMoreSymbol”;
  //添加所有的菜单项到菜单
  this.ContextMenu.Items.AddRange(symbolContextMenuItem);
  this.contextMenuMoreSymbolInitiated = true;
  }
  //显示菜单
  this.ContextMenu.Show(this.b_more.Location);
  }
  当单击某一菜单项时响应ItemClicked事件,将选中的ServerStyle文件导入到SymbologyControl中并刷新。当用户单击“添加符号”菜单项时,弹出打开文件对话框,供用户选择其它的ServerStyle文件。代码如下:
  private void ContextMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
  {
  ToolStripMenuItem pToolStripMenuItem = (ToolStripMenuItem)e.ClickedItem;
  //如果单击的是“添加符号”
  if (pToolStripMenuItem.Name == “AddMoreSymbol”)
  {
  //弹出打开文件对话框
  if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
  {
  //导入style file到SymbologyControl
  this.axSymbologyControl1.LoadStyleFile(this.openFileDialog1.FileName);
  //刷新axSymbologyControl控件
  this.axSymbologyControl1.Refresh();
  }
  }
  else//如果是其它选项
  {
  if (pToolStripMenuItem.Checked == false)
  {
  this.axSymbologyControl1.LoadStyleFile(pToolStripMenuItem.Name);
  this.axSymbologyControl1.Refresh();
  }
  else
  {
  this.axSymbologyControl1.RemoveFile(pToolStripMenuItem.Name);
  this.axSymbologyControl1.Refresh();
  }
  }
  }
  至此,自定义的符号选择器已经可以使用辣,在代码调试过程中出现过很多次bug,但是很遗憾没能及时记录下来。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分