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

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

<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 414pt; HEIGHT: 291pt" type="#_x0000_t75"><imagedata src="file:///F:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/04/clip_image001.png" o:title="未命名"></imagedata></shape>

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

效果:

<shape id="_x0000_i1026" style="WIDTH: 423pt; HEIGHT: 324pt" type="#_x0000_t75"><imagedata src="file:///F:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/04/clip_image003.png" o:title="未命名"></imagedata></shape>

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页