使用GDI+实现动态设置分级断点值

ArcMap的专题图制作中,我们对Classification并不陌生(如图)。这主要是对应于ClassBreak类型的地图渲染而言的。它可以用来动态设置分类的等级数目,而且可以使用鼠标对代表Break数值大小的蓝色线进行拖动,以调整分级值的大小,甚至可以显示某区间内样本值的分布状况。

 

AO中没有提供现成的接口用来实现该工具。但可以使用三种方式,实现具有简单分类和动态调节值大小的工具。

第一种思路:修改用于绘图的开源控件,例如ZedGraph等,本来也想按照这个方法实现,但是有点懒的看别人的代码了:(

第二种思路:在MapControl上,添加LineElement,用LineElement代表制的大小,然后用IDisplayFeedback接口完成Element的移动,这样实现的难度最小,但是并不灵活,因为,假如开发工作并没有采用ArcGIS Engine的话,我们总不能为了做出这么个工具,就花上十多万的银子吧?

第三种思路:适用.NetGDI+直接在窗体上绘制出来。这样的实现方式最灵活,不受所采用的组件的影响。

 

关键代码:

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;





namespace HAPPY2007

{

	/// <summary>

	/// frmGetManualValue 的摘要说明。

	/// </summary>

	/// 

	//定义两个代理,用于调用HappyMap中的分级渲染和添加图例功能

	public delegate ArrayList _deleClassBreakDrawing2(string str,ArrayList arrValues,out ArrayList arrSymbol,out ArrayList arrText);

	public delegate void _deleAddLegendClassBreak(ArrayList arrText,ArrayList arrSymbol);





	public class frmGetManualValue : System.Windows.Forms.Form

	{

		/// <summary>

		/// 必需的设计器变量。

		/// </summary>

		public _deleClassBreakDrawing2 _deleCBD;

		public _deleAddLegendClassBreak _deleALCB;

		private System.ComponentModel.Container components = null;

		//首先获得已有的arrValues的最大值和最小值,这是把x坐标值转化为arrValue的必须条件

		double dblStartValue;

		double dblEndValue;

		//横线x坐标的起点

		private int intStartX = 30;

		//横线x坐标的终点

		private int intEndX = 320;

		//所有竖线y坐标的起点

		private int intStartY = 40;

		//所有竖线y坐标的终点

		private int intEndY = 230;

		//判断鼠标是否按下

		private bool blnIsMouseDown = false;

		private Graphics dc;

		//用于接收传进来的ArrayList变量,该变量内放置的是等级的break值,包括起点值和终点值

		private ArrayList arrValues;

		//用于保存各条竖线的x坐标值,该值与arrValues里的制具有一定的换算机制

		private int[] intXs;

		//用于标记渲染哪个字段(面积、缴租、单位租金)

		public string strFieldName;



		private System.Windows.Forms.GroupBox groupBox1;

		private System.Windows.Forms.ComboBox comboBox1;

		private System.Windows.Forms.GroupBox groupBox2;

		private System.Windows.Forms.Button button1;

		private System.Windows.Forms.Button button2;

		//用于表示选中的线的x值在intXs中的索引位置,初始值为-1

		private int intIndex = -1;

		public static frmGetManualValue frm;



		public static frmGetManualValue CreateForm(ArrayList arr)

		{

			if(frm==null)

				frm = new frmGetManualValue(arr);

			return frm;

		}



		private frmGetManualValue()

		{

			//

			// Windows 窗体设计器支持所必需的

			//

			InitializeComponent();

			this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);

			this.SetStyle(ControlStyles.DoubleBuffer,true);

			this.SetStyle(ControlStyles.UserPaint,true);



			//必须初始化dc

			this.dc = this.CreateGraphics();

			//必须先show出来,绘制代码才起作用

			this.Show();



			//

			// TODO: 在 InitializeComponent 调用后添加任何构造函数代码

			//

		}

		//重载构造函数,因为往往会传进来一个Values用来初始化

		private frmGetManualValue(ArrayList arr)

		{

			this.InitializeComponent();

			this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);

			this.SetStyle(ControlStyles.DoubleBuffer,true);

			this.SetStyle(ControlStyles.UserPaint,true);



			//初始化dc

			this.dc = this.CreateGraphics();

			this.Show();

			this.arrValues = arr;

			//利用arr对intXs的个数进行初始化

			this.intXs = new int[arr.Count];

			this.dblStartValue = Convert.ToDouble(arr[0]);

			this.dblEndValue = Convert.ToDouble(arr[arr.Count-1]);

			//初始化intXs

			this.ConvertToXs(arr);

			

		}

		//用于绘制图形的方法

		private void Draw(Graphics dc)

		{

			Pen PenAnixes = new Pen(Color.Blue,2);

			Pen PenValue = new Pen(Color.Red,0);

			Brush textBrush = new SolidBrush(Color.Black);

			Font fnt = new Font("Times New Roman",8);



			Point p1 = new Point(intStartX,intEndY);

			Point p2 = new Point(intEndX,intEndY);



			dc.DrawLine(PenAnixes,p1,p2);

			for(int i=0;i<this.intXs.Length;i++)

			{

				p1 = new Point(this.intXs[i],intEndY);

				p2 = new Point(this.intXs[i],intStartY);

				if(i==0||i==this.intXs.Length-1)

				{

					dc.DrawLine(PenAnixes,p1,p2);

				}

				else

				{

					dc.DrawLine(PenValue,p1,p2);

				}

			}

//			dc.RotateTransform(90);

			for(int i=0;i<this.intXs.Length;i++)

			{

//				this.dc.RotateTransform(90);

				dc.DrawString(Convert.ToInt32(this.arrValues[i]).ToString(),fnt,textBrush,new RectangleF(this.intXs[i],this.intStartY,40,15));

			}

		}



		//用于intXs与arrValues之间的转换。即竖线的x坐标值与实际代表制具有一定的关系

		private void ConvertToXs(ArrayList arrList)

		{

			if(this.intXs!=null)

			{

				for(int i=0;i<arrList.Count;i++)

				{

					double dbl = (Convert.ToDouble(arrList[i])-Convert.ToDouble(arrList[0]))*(this.intEndX-this.intStartX)/(Convert.ToDouble(arrList[arrList.Count-1])-Convert.ToDouble(arrList[0])) + this.intStartX;

					intXs[i] = Convert.ToInt32(dbl);

				}

			}

			else

			{

				MessageBox.Show("请首先初始化intXs数组!");

			}

		}

		//用于intXs与arrValues之间的转换。即竖线的x坐标值与实际代表制具有一定的关系

		private void ConvertToValues(int[] xs)

		{

			if(this.arrValues!=null)

			{

				//首先获得已有的arrValues的最大值和最小值,这是把x坐标值转化为arrValue的必须条件

				this.dblStartValue = Convert.ToDouble(this.arrValues[0]);

				this.dblEndValue = Convert.ToDouble(this.arrValues[this.arrValues.Count-1]);

				for(int i = 0;i<xs.Length;i++)

				{

					this.arrValues[i] = (xs[i]-this.intStartX)*(dblEndValue-dblStartValue)/(this.intEndX-this.intStartX)+dblStartValue;

				}

			}

			else

			{

				MessageBox.Show("请首先初始化arrValues!");

			}

		}

		//重写OnPaint方法

		protected override void OnPaint(PaintEventArgs e)

		{

			base.OnPaint(e);

			//调用绘制方法进行重绘

			this.Draw(e.Graphics);

		}

		/// <summary>

		/// 清理所有正在使用的资源。

		/// </summary>

		protected override void Dispose( bool disposing )

		{

			if( disposing )

			{

				if(components != null)

				{

					components.Dispose();

				}

			}

			base.Dispose( disposing );

		}



		#region Windows 窗体设计器生成的代码

		/// <summary>

		/// 设计器支持所需的方法 - 不要使用代码编辑器修改

		/// 此方法的内容。

		/// </summary>

		private void InitializeComponent()

		{

			this.groupBox1 = new System.Windows.Forms.GroupBox();

			this.comboBox1 = new System.Windows.Forms.ComboBox();

			this.groupBox2 = new System.Windows.Forms.GroupBox();

			this.button2 = new System.Windows.Forms.Button();

			this.button1 = new System.Windows.Forms.Button();

			this.groupBox1.SuspendLayout();

			this.groupBox2.SuspendLayout();

			this.SuspendLayout();

			// 

			// groupBox1

			// 

			this.groupBox1.Controls.Add(this.comboBox1);

			this.groupBox1.Location = new System.Drawing.Point(352, 32);

			this.groupBox1.Name = "groupBox1";

			this.groupBox1.Size = new System.Drawing.Size(96, 80);

			this.groupBox1.TabIndex = 0;

			this.groupBox1.TabStop = false;

			this.groupBox1.Text = "分级数目";

			// 

			// comboBox1

			// 

			this.comboBox1.Items.AddRange(new object[] {

														   "3",

														   "4",

														   "5",

														   "6"});

			this.comboBox1.Location = new System.Drawing.Point(8, 32);

			this.comboBox1.Name = "comboBox1";

			this.comboBox1.Size = new System.Drawing.Size(72, 20);

			this.comboBox1.TabIndex = 0;

			this.comboBox1.Text = "4";

			this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);

			// 

			// groupBox2

			// 

			this.groupBox2.Controls.Add(this.button2);

			this.groupBox2.Controls.Add(this.button1);

			this.groupBox2.Location = new System.Drawing.Point(352, 128);

			this.groupBox2.Name = "groupBox2";

			this.groupBox2.Size = new System.Drawing.Size(96, 104);

			this.groupBox2.TabIndex = 0;

			this.groupBox2.TabStop = false;

			// 

			// button2

			// 

			this.button2.Location = new System.Drawing.Point(16, 64);

			this.button2.Name = "button2";

			this.button2.Size = new System.Drawing.Size(64, 23);

			this.button2.TabIndex = 1;

			this.button2.Text = "取消";

			this.button2.Click += new System.EventHandler(this.button2_Click);

			// 

			// button1

			// 

			this.button1.Location = new System.Drawing.Point(16, 24);

			this.button1.Name = "button1";

			this.button1.Size = new System.Drawing.Size(64, 23);

			this.button1.TabIndex = 0;

			this.button1.Text = "确定";

			this.button1.Click += new System.EventHandler(this.button1_Click);

			// 

			// frmGetManualValue

			// 

			this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);

			this.BackColor = System.Drawing.SystemColors.HighlightText;

			this.ClientSize = new System.Drawing.Size(464, 253);

			this.Controls.Add(this.groupBox1);

			this.Controls.Add(this.groupBox2);

			this.MaximizeBox = false;

			this.Name = "frmGetManualValue";

			this.Text = "动态分级";

			this.TopMost = true;

			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.frmGetManualValue_MouseDown);

			this.Closing += new System.ComponentModel.CancelEventHandler(this.frmGetManualValue_Closing);

			this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.frmGetManualValue_MouseUp);

			this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.frmGetManualValue_MouseMove);

			this.groupBox1.ResumeLayout(false);

			this.groupBox2.ResumeLayout(false);

			this.ResumeLayout(false);



		}

		#endregion



		private void frmGetManualValue_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)

		{

			if(this.blnIsMouseDown)

			{

				if(e.X>intXs[this.intIndex-1]&&e.X<intXs[this.intIndex+1])

				{

					this.intXs[this.intIndex] = e.X;

					this.Draw(this.dc);

					this.ConvertToValues(intXs);

					//实施刷新,为了防止晃动,已经在窗体的构造函数中加入缓存函数.

					this.Refresh();

				}

			}

		}



		private void frmGetManualValue_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)

		{

			//i从1开始到Length-1,确保最小值和最大值不能移动!

			for(int i=1;i<intXs.Length-1;i++)

			{

				//缓冲区为5

				if(e.X>intXs[i]-5&&e.X<intXs[i]+5)

				{

					this.Cursor = Cursors.SizeWE;

					this.blnIsMouseDown = true;

					this.intIndex = i;

					return;

				}

			}

		}



		private void frmGetManualValue_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)

		{

			//还原所有相关属性

			this.Cursor = Cursors.Default;

			this.blnIsMouseDown = false;

			this.intIndex = -1;

		}



		private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)

		{

			//首先删除已有的所有Labels

//			this.DeleteLabels();

			//classNum表示分类的级别

			int classNum = Convert.ToInt32(this.comboBox1.SelectedItem);

			//num表示数组内元素的个数,总是比分类级别大1

			int num = classNum+1;

			//range为arrValues的极差

			int range = Convert.ToInt32(this.arrValues[this.arrValues.Count-1])-Convert.ToInt32(this.arrValues[0]);

			//重新定义arrValues,和intXs、lblVs的个数

			this.arrValues = new ArrayList();

			this.intXs = new int[num];

//			this.lblVs = new Label[num];



			//定义arrValues的值,从0,开始,逐渐加上每个级别的大小,即平均分级

			for(int i=0;i<num;i++)

			{

				//由于存在误差,为了不显示误差,第一和最后一个值强行设定

				if(i==0)

				{

					arrValues.Add(0);

				}

				else if(i==num-1)

				{

					this.arrValues.Add(this.dblEndValue);

				}

				else

				{

					arrValues.Add(Convert.ToDouble(arrValues[i-1])+range/classNum);

				}

				

			}

			//将arrValues里的值转化为x坐标值得

			this.ConvertToXs(this.arrValues);

			//绘制图形并刷新,一定要刷新

			this.Draw(this.dc);

			this.Refresh();

		}





		private void frmGetManualValue_Closing(object sender, System.ComponentModel.CancelEventArgs e)

		{

			frm = null;

		}



		private void button2_Click(object sender, System.EventArgs e)

		{

			frm.Close();

		}



		private void button1_Click(object sender, System.EventArgs e)

		{

			this.arrValues.RemoveAt(0);



			ArrayList arrText;

			ArrayList arrSymbol;



			this._deleCBD(this.strFieldName,arrValues,out arrSymbol,out arrText);

			this._deleALCB(arrText,arrSymbol);

		}

	}

}

效果:

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值