如何利用C# Winform画一个简单的关系图

     如何利用C# 自带的控件画一个比较简单的关系图,因为很少在Winform开发,所有对我来说,第一反应就是在winform中嵌入网页。因为在网页中,画图是比较容易的,然后利用WebBrowser 嵌入到窗体中。或者可以直接找第三方画流程图的控件进行绘画。但是,对于我来说,如何利用Winform创建,却很重要。在多方面的尝试中,一步一步的探索,终于画出了满意的图片。

    在我这个小Demo中,第一、根据输入的一个数,查找相关数据之间的关系,所以数据源是动态的,即动态绘图;第二、数据源的逻辑,有点复杂。大概是这么个样子,针对数据之间的逻辑关系大致可以划分成以下情况:

            (1)1个体 A;

            (2)A有多个子节点;

            (3)A有多个父节点;

            (4)当A只有一个子节点时,需要知道列出该子节点的所有父节点或者只有一个父节点时,列出该父节点的所有子节点;是不是有点乱了,或许看图会好一些:

  

图(1)

图(2)

图(3)

图(4)

    起初,我刚开始设计的时候,发现这些位置都应该是相对的。所以我先固定要寻找的点,当然这个点的在几种情况下是固定的,但是为了美观些,我将列分为三块区域,而我的起始点初步左中两个区域。不啰嗦,直接讲原理,每个数字就是一个picturebox,背景可以画长方形,园,椭圆,然后根据字数的长度以及背景图像的宽度,在画字的时候,让字居中显示。另外一个难点就是画线,需要创建一个类Lines,用来记住开始与终点的控件。

    Lines类:     

 1      public class Lines
 2         {
 3             public Control StartControl { get; set; }
 4 
 5             public Control EndControl { get; set; }
 6 
 7             public Lines(Control startCtl, Control endCtl)
 8             {
 9                 this.StartControl = startCtl;
10                 this.EndControl = endCtl;
11             }
12          }
View Code

    画picturebox,以及动态绑定Click事件,利用Graphics的DrawString来在图片上写字。默认情况的,图片或者线之类的可能出现锯齿,在画的时候设置一下 gra.SmoothingMode = SmoothingMode.HighQuality;下面是我画方框图的代码:

 1         #region 画方框图
 2 
 3         /// <summary>
 4         /// 画方框图
 5         /// </summary>
 6         /// <param name="picBox"></param>
 7         /// <param name="content"></param>
 8         /// <param name="brush"></param>
 9         private void DrawContentOnImage(PictureBox picBox, string content, Brush brush)
10         {
11             Bitmap bitmap = new Bitmap(picBox.Width, picBox.Width);
12 
13             picBox.Image = bitmap;
14             Graphics gra = Graphics.FromImage(bitmap);
15             //Pen pen = new Pen(Color.Black);//画笔颜色
16             gra.SmoothingMode = SmoothingMode.HighQuality;
17             PointF p = new PointF();
18             p.Y = 6;
19             int len = content.Trim().Length;
20             p.X = this._width / 2 - (float)3.6 * len;
21             gra.DrawString(content, new Font("宋体", 10), brush, p);
22 
23 
24 
25 
26             //gra.DrawEllipse(pen,0 ,0, 67, 26);//画椭圆的方法,x坐标、y坐标、宽、高,如果是100,则半径为50
27 
28             //Point p=new Point();
29             //p.Y = 6;
30             //int len = content.Trim().Length;
31             //p.X = 7;
32             //if (len <= 6)
33             //{
34             //    p.X = 31 - 4*len;
35             //}
36             //gra.DrawString(content, new Font("宋体", 10), brush,p);
37         }
38 
39         /// <summary>
40         /// 根据字符串画picturebox
41         /// </summary>
42         /// <param name="contents"></param>
43         /// <param name="parent"></param>
44         /// <param name="startPoint"></param>
45         /// <returns></returns>
46         private List<Control> DrawContentContainers(List<Zdgx> contents, Control parent, Point startPoint, Brush brush)
47         {
48             List<Control> controlLst = new List<Control>();
49             PictureBox picb;
50             int x = startPoint.X;
51             int y = startPoint.Y;
52 
53             //Graphics g = parent.CreateGraphics();
54 
55             foreach (Zdgx gx in contents)
56             {
57                 Point p = new Point(x, y);
58                 picb = new PictureBox();
59                 picb.Location = p;
60                 picb.Name = gx.Zdh;
61 
62                 picb.BorderStyle = BorderStyle.FixedSingle;
63                 picb.Width = this._width;
64                 picb.Height = this._height;
65 
66                 this._picControls.Add(picb);
67                 picb.Click += new EventHandler(picb_Click);
68                 parent.Controls.Add(picb);
69 
70                 controlLst.Add(picb);
71 
72                 DrawContentOnImage(picb, gx.Zdh, brush);
73 
74                 y = y + this._heightBetween;
75             }
76 
77             return controlLst;
78         }
79 
80         public void picb_Click(object sender, EventArgs e)
81         {
82             string zdj = "";
83             PictureBox pb = sender as PictureBox;
84             MessageBox.Show(pb.Name);
85         }
86          #endregion
View Code

    接下来就是画数据之间的两两关系了,就是画线了,这里我一般都会定义一个全局变量,List<Lines> _lineLst=newList<Lines>();用来存储有关系的pictcurebox。然后开始画线:

 1         /// <summary>
 2         /// 画图
 3         /// </summary>
 4         /// <param name="linesLst"></param>
 5         public void DrawGxLine(List<Lines> linesLst)
 6         {
 7             if (linesLst != null)
 8             {
 9                 foreach (Lines line in linesLst)
10                 {
11                     //右下角坐标
12                     Point pLft = new Point(line.StartControl.Location.X + line.StartControl.Width, line.StartControl.Location.Y + line.StartControl.Height / 2);
13 
14                     //左上角图标
15                     Point pRgt = new Point(line.EndControl.Location.X, line.EndControl.Location.Y + line.EndControl.Height / 2);
16 
17                     Pen p = new Pen(Color.Black);
18                     p.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
19                     p.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
20                     p.CustomEndCap = new System.Drawing.Drawing2D.AdjustableArrowCap(5, 5, true);
21                     Graphics g = this.CreateGraphics();
22                     g.SmoothingMode = SmoothingMode.HighQuality;
23                     g.DrawLine(p, pLft, pRgt);
24                 }
25             }
26         }
View Code

     然后是处理数据逻辑关系,与计算位置的方法了,大体上解释一下,我们从左往右思考,如果出现图(1)的情况,将起始位置处理成左边位置,起始的高度是一样的;接着,如果A的父节点B只有一个的情况下,我们就计算该父节点B下的所有子节点,根据B的子节点的个数,计算出B在这几个节点的左侧中间位置,同时记住中间_centerLastControl,与位置关系;如果A存在多个父节点,那就根据A节点的计算出左侧的picturebox的起始点的高度,每个节点的高度是一个定值。右边的逻辑,与左侧一样的。

  1     public void InitInfo(string zdh)
  2         {
  3             if (string.IsNullOrEmpty(zdh)) return;
  4             if (zdh.Length > 19) return;
  5             initialIList();
  6             ClearZdGxT();
  7 
  8             //SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, false);
  9             //UpdateStyles();
 10 
 11             this._picControls = new List<PictureBox>();
 12             this._zdh = zdh;
 13             List<ZD_GX> leftList = GetData(this._zdh, true);
 14             List<ZD_GX> rightList = GetData(this._zdh, false);
 15 
 16             #region 
 17             if (leftList.Count == 0 && rightList.Count == 0)
 18             {
 19                 //中间默认ID为0
 20                 this._centerZdGx.Add(new Zdgx(0, this._zdh));
 21                 //画中间的
 22                 this._centerControlLst = DrawContentContainers(this._centerZdGx, this, new Point(this._startX, this._startY), Brushes.Blue);
 23                 Control cCenter = this._centerControlLst[0];
 24                 //中间最下面一个Control
 25                 this._centerLastControl = cCenter;
 26 
 27                 //画图
 28                 DrawGxLine(this._lineLst);
 29                 return;
 30             }
 31             #endregion
 32 
 33             Control ccCenter = new Control();
 34 
 35 
 36             if (leftList.Count > 0)
 37             {
 38 
 39                 //中间默认ID为0
 40                 this._centerZdGx.Add(new Zdgx(0, this._zdh));
 41                 //画中间的
 42                 this._centerControlLst = DrawContentContainers(this._centerZdGx, this, new Point(this._startX + 180, this._startY), Brushes.Blue);
 43                 ccCenter = this._centerControlLst[0];
 44                 //中间最下面一个Control
 45                 this._centerLastControl = ccCenter;
 46 
 47                 this._leftZdGx = GetZdgxList(leftList, true);
 48                 int y = 0;
 49 
 50                 #region 
 51                 if (this._leftZdGx.Count > 1)
 52                 {
 53                     y = 0;
 54                     int count = this._leftZdGx.Count;
 55                     //为了样式好看些
 56                     if (this._leftZdGx.Count % 2 == 0)//个数是偶数
 57                     {
 58                         y = this._startY - ((this._heightBetween - this._height) / 2 - this._height / 2)
 59                             - (count / 2) * this._height
 60                             - (count / 2 - 1) * (this._heightBetween - this._height);
 61                     }
 62                     else
 63                     {
 64                         y = this._startY - (count / 2) * this._height - (count / 2) * (this._heightBetween - this._height);
 65                     }
 66 
 67                     //画左边框
 68                     this._leftControlLst = DrawContentContainers(this._leftZdGx, this, new Point(this._startX, y), Brushes.Black);
 69                     //左边最下面一个
 70                     this._leftLastControl = this._leftControlLst[leftList.Count - 1];
 71 
 72                     //保存左-->中的连线
 73                     foreach (Control c in this._leftControlLst)
 74                     {
 75                         _lineLst.Add(new Lines(c, ccCenter));
 76                     }
 77                 }
 78 
 79 
 80                 //画左边扩展
 81                 if (leftList.Count == 1)
 82                 {
 83                     List<ZD_GX> list = GetData(leftList[0].LZDH_L, false);
 84                     this._leftExtendZdGx = GetZdgxList(list, false);
 85                     RemoveCenter(this._leftExtendZdGx);
 86                     if (this._leftExtendZdGx.Count > 0)
 87                     {
 88                         y = 0;
 89                         int count = this._leftExtendZdGx.Count + 1;
 90                         if (count % 2 == 0)
 91                         {
 92                             y = this._startY + ((this._heightBetween - this._height) / 2 - this._height / 2)
 93                                 + (count / 2) * this._height
 94                                 + (count / 2 - 1) * (this._heightBetween - this._height);
 95                         }
 96                         else
 97                         {
 98                             y = this._startY + (count / 2) * this._height + (count / 2) * (this._heightBetween - this._height);
 99                         }
100 
101 
102                         //画左边框
103                         this._leftControlLst = DrawContentContainers(this._leftZdGx, this, new Point(this._startX, y), Brushes.Black);
104                         //左边最下面一个
105                         this._leftLastControl = this._leftControlLst[leftList.Count - 1];
106 
107                         //保存左-->中的连线
108                         foreach (Control c in this._leftControlLst)
109                         {
110                             _lineLst.Add(new Lines(c, ccCenter));
111                         }
112 
113                         //画中间扩展
114                         this._leftExtendControlLst = DrawContentContainers(this._leftExtendZdGx, this, new Point(this._centerLastControl.Location.X, this._centerLastControl.Location.Y + this._heightBetween), Brushes.Black);
115                         //中间最后一个
116                         this._centerLastControl = this._leftExtendControlLst[this._leftExtendZdGx.Count - 1];
117 
118                         //左右连线
119                         foreach (Control c in this._leftExtendControlLst)
120                         {
121                             _lineLst.Add(new Lines(this._leftLastControl, c));
122                         }
123                     }
124                     else
125                     {
126 
127                         //画左边框
128                         this._leftControlLst = DrawContentContainers(this._leftZdGx, this, new Point(this._startX, this._startY), Brushes.Black);
129                         //左边最下面一个
130                         this._leftLastControl = this._leftControlLst[leftList.Count - 1];
131 
132                         //保存左-->中的连线
133                         foreach (Control c in this._leftControlLst)
134                         {
135                             _lineLst.Add(new Lines(c, ccCenter));
136                         }
137                     }
138 
139                 }
140 
141 
142 
143                 #endregion
144             }
145             else
146             {
147                 //中间默认ID为0
148                 this._centerZdGx.Add(new Zdgx(0, this._zdh));
149                 //画中间的
150                 this._centerControlLst = DrawContentContainers(this._centerZdGx, this, new Point(this._startX, this._startY), Brushes.Blue);
151                 ccCenter = this._centerControlLst[0];
152                 //中间最下面一个Control
153                 this._centerLastControl = ccCenter;
154             }
155 
156 
157 
158 
159 
160             #region 右边
161 
162 
163 
164             //画右边
165             if (rightList.Count > 0)
166             {
167                 this._rightZdGx = GetZdgxList(rightList, false);
168                 int y = 0;
169 
170                 if (this._rightZdGx.Count > 1)
171                 {
172                     y = 0;
173                     //为了样式好看些
174                     int count = this._rightZdGx.Count;
175                     if (this._leftZdGx.Count % 2 == 0)//个数是偶数
176                     {
177                         y = this._startY - ((this._heightBetween - this._height) / 2 - this._height / 2)
178                             - (count / 2) * this._height
179                             - (count / 2 - 1) * (this._heightBetween - this._height);
180                     }
181                     else
182                     {
183                         y = this._startY + (count / 2) * this._height + (count / 2) * (this._heightBetween - this._height);
184                     }
185 
186                     //画右边边框
187                     this._rightControlLst = DrawContentContainers(this._rightZdGx, this, new Point(ccCenter.Location.X + 180, y), Brushes.Black);
188                     //右边最下面一个
189                     this._rightLastControl = this._rightControlLst[rightList.Count - 1];
190 
191                     //中右连线
192                     foreach (Control c in this._rightControlLst)
193                     {
194                         _lineLst.Add(new Lines(this._centerControlLst[0], c));
195                     }
196                 }
197 
198 
199                 //画右边扩展
200                 if (rightList.Count == 1)
201                 {
202                     List<ZD_GX> list = GetData(rightList[0].LZDH_X, true);
203                     this._rightExtendZdGx = GetZdgxList(list, true);
204                     RemoveCenter(this._rightExtendZdGx);
205                     if (this._rightExtendZdGx.Count > 0)
206                     {
207                         y = 0;
208                         int count = this._rightExtendZdGx.Count + this._leftExtendControlLst.Count + 1;
209                         if (count % 2 == 0)
210                         {
211                             y = this._startY + (this._heightBetween - this._height) / 2 + this._height / 2
212                                 + (count / 2) * this._height
213                                 + (count / 2 - 1) * (this._heightBetween - this._height);
214                         }
215                         else
216                         {
217                             y = this._startY + (count / 2) * this._height + (count / 2) * (this._heightBetween - this._height);
218                         }
219 
220                         //画右边边框
221                         this._rightControlLst = DrawContentContainers(this._rightZdGx, this, new Point(ccCenter.Location.X + 180, y), Brushes.Black);
222                         //右边最下面一个
223                         this._rightLastControl = this._rightControlLst[rightList.Count - 1];
224 
225                         //中右连线
226                         foreach (Control c in this._rightControlLst)
227                         {
228                             _lineLst.Add(new Lines(this._centerControlLst[0], c));
229                         }
230 
231 
232                         //画中间扩展
233                         this._rightExtendControlLst = DrawContentContainers(this._rightExtendZdGx, this, new Point(this._centerLastControl.Location.X, this._centerLastControl.Location.Y + this._heightBetween), Brushes.Black);
234                         //中间最后一个
235                         this._centerLastControl = this._rightExtendControlLst[this._rightExtendZdGx.Count - 1];
236                         //中右连线
237 
238                         foreach (Control c in this._rightExtendControlLst)
239                         {
240                             _lineLst.Add(new Lines(c, this._rightLastControl));
241                         }
242                     }
243                     else
244                     {
245                         //画右边边框
246                         this._rightControlLst = DrawContentContainers(this._rightZdGx, this, new Point(ccCenter.Location.X + 180, this._startY), Brushes.Black);
247                         //右边最下面一个
248                         this._rightLastControl = this._rightControlLst[rightList.Count - 1];
249 
250                         //中右连线
251                         foreach (Control c in this._rightControlLst)
252                         {
253                             _lineLst.Add(new Lines(this._centerControlLst[0], c));
254                         }
255                     }
256 
257                 }
258 
259 
260 
261 
262             }
263             #endregion
264 
265             //画图
266             DrawGxLine(this._lineLst);
267         }
View Code

   清空程序,释放资源:

 1       private void ClearLines()
 2         {
 3             this._lineLst = new List<Lines>();
 4             this.OnPaint(new PaintEventArgs(this.CreateGraphics(), new Rectangle(this.Location, new Size(this.Width, this.Height))));
 5         }
 6 
 7         private void ClearPictureBox()
 8         {
 9             if (this._picControls.Count > 0)
10             {
11                 foreach (PictureBox picBox in this._picControls)
12                 {
13                     picBox.Dispose();
14                 }
15             }
16         }
View Code

   在这里会经常发现一个,就是对话框最小化或者放大缩小的时候,我们会发现,绘画的线不见了,那是因为我们在窗体上绘画的时候使用的是 Graphics g = this.CreateGraphics();这种情况下对窗体进行操作会触发它的OnPaint的事件,所以我们需要重写Onpaint的事件。

1       protected override void OnPaint(PaintEventArgs e)
2         {
3             base.OnPaint(e);
4 
5             DrawGxLine(this._lineLst);
6         }
View Code

   运行结果图:

 

 

posted @ 2017-05-10 09:22  行风流年  阅读(2400)  评论(2)    收藏  举报