[原创]《C#高级GDI+实战:从零开发一个流程图》第08章:增长菱形、平行四边形、圆角矩形,文本居中体现

[复制链接]
发表于 2025-9-19 10:12:07 | 显示全部楼层 |阅读模式
一、前言

前面的课程我们已经完成了形状和连线的抽象,并独立出了画布控件,底子已经打好,下面就要添砖加瓦了。我们本节课程就来添加一些差别的形状,如:菱形、平行四边形、圆角矩形等。而且我们前面发现形状内的文本都不是居中体现的,我们也趁便优化下。
信赖看完的你,肯定会有所劳绩!
本文所在:https://www.cnblogs.com/lesliexin/p/18997090
二、先看效果

我们可以看到添加了差别的形状,且都支持拖动、连线。

看完本篇的代码,我们会发实际现起来很简朴,只必要给继续形状基类实现下就行了,主步伐只是添加个控件、天生个形状类,调用画布的添加形状方法就行了。
以是本节的课程重点在于怎样去用GDI+“画”出这些形状。
三、菱形

像菱形及本文中的形状,就没有如今的GDI+方法来实现了,只能通过各个子方法来组合绘制出想要的形状。
我们先看下图的菱形图示:

我们的所做的就是依次绘制菱形的四个边,这四个极点的坐标怎么来的呢?
我们在前面的抽象出形状基类那节讲过,属性Rect是指示形状所在的矩形地区,以是我们就要在这个矩形地区内,指定4个极点并盘算出坐标。
当有了坐标后,我可以利用GDI+的AddPolygon方法来将多个坐标点添加成一个多边形,其MSDN的表明如下:

末了利用GDI+的FillPath将此多边形绘制出来,详细的代码如下:

四、平行四边形

同菱形,我们也是利用雷同的方法求出四个极点的坐标,这里我们将倾斜间隔设置为1/5的宽度:

代码界说里直接按图示取值即可:

五、圆角矩形

圆角矩形就和上面的两个形状不一样了,由于不再是由直线构成,而是要有弧度:

这里要利用一个新的GDI+方法:AddArc,添加一段弧线,其MSDN的表明如下:

留意看最下面那段话:
如果图中有上一条直线或曲线,则会添加一条线,用于将上一段的端点毗连到弧线的开头。
以是我们并不必要添加4条直线4个弧线,只必要添加4个弧线就行了,我们暂时将弧线所在圆的直径固定为20。
此中:
1,左上角


2,右上角


3,右下角


4,左下角


我们参照上图的坐标及角度编写代码即可:

六、文本居中体现

上面的形状实现后,我们会发现文本位置都差别一,我们下面就来让文本同一居中体现。
核心是利用GDI+的DrawString的一个重载方法:

我们像下面如许写就能让文本居中体现:

关于StringFormat的详细讲授,请参照教程:
C# StringFormat详解之文本方向、对齐
https://www.cnblogs.com/lesliexin/p/12879270.html
详细的代码改造如下,不再赘述:
点击检察代码
  1.     /// <summary>
  2.     /// 菱形定义
  3.     /// </summary>
  4.     public class LozengeShapeV2 : ShapeBase
  5.     {
  6.         public override void Draw(Graphics g)
  7.         {
  8.             var x2 = Rect.X;
  9.             var y2 = Rect.Y;
  10.             var w2 = Rect.Width;
  11.             var h2 = Rect.Height;
  12.             var x = x2 + w2 / 2;
  13.             var y = y2 + h2 / 2;
  14.             //左-上-右-下
  15.             var r0 = new Point(x2, y);
  16.             var r1 = new Point(x, y2);
  17.             var r2 = new Point(x2 + w2, y);
  18.             var r3 = new Point(x, y2 + h2);
  19.             var path = new GraphicsPath();
  20.             path.Reset();
  21.             path.AddPolygon(new Point[]{ r0,r1,r2,r3});
  22.             path.CloseFigure();
  23.             g.FillPath(new SolidBrush(BackgroundColor), path);
  24.             g.DrawString(Text, TextFont, new SolidBrush(FontColor), Rect,
  25.                 new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
  26.         }
  27.     }
  28.        
  29.        
  30.     /// <summary>
  31.     /// 平行四边形定义
  32.     /// </summary>
  33.     public class ParallelogramShapeV2 : ShapeBase
  34.     {
  35.         public override void Draw(Graphics g)
  36.         {
  37.             var x2 = Rect.X;
  38.             var y2 = Rect.Y;
  39.             var w2 = Rect.Width;
  40.             var h2 = Rect.Height;
  41.             var f = w2 / 5;
  42.             //左-上-右-下
  43.             var r0 = new Point(x2 + f, y2);
  44.             var r1 = new Point(x2 + w2, y2);
  45.             var r2 = new Point(x2 + w2 - f, y2 + h2);
  46.             var r3 = new Point(x2, y2 + h2);
  47.             var path = new GraphicsPath();
  48.             path.Reset();
  49.             path.AddPolygon(new Point[]{ r0,r1,r2,r3});
  50.             path.CloseFigure();
  51.             g.FillPath(new SolidBrush(BackgroundColor), path);
  52.             g.DrawString(Text, TextFont, new SolidBrush(FontColor), Rect,
  53.                 new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
  54.         }
  55.     }
  56.        
  57.        
  58.     /// <summary>
  59.     /// 圆角矩形定义
  60.     /// </summary>
  61.     public class RoundRectShapeV2 : ShapeBase
  62.     {
  63.         public override void Draw(Graphics g)
  64.         {
  65.             float diameter = 20;
  66.             var path = new GraphicsPath();
  67.             path.Reset();
  68.             RectangleF arc = new RectangleF(Rect.X, Rect.Y, diameter, diameter);
  69.            
  70.             // 左上角
  71.             path.AddArc(arc, 180, 90);
  72.             // 右上角
  73.             arc.X = Rect.Right - diameter;
  74.             path.AddArc(arc, 270, 90);
  75.             // 右下角
  76.             arc.Y = Rect.Bottom - diameter;
  77.             path.AddArc(arc, 0, 90);
  78.             // 左下角
  79.             arc.X = Rect.Left;
  80.             path.AddArc(arc, 90, 90);
  81.             path.CloseFigure();
  82.             g.FillPath(new SolidBrush(BackgroundColor), path);
  83.             g.DrawString(Text, TextFont, new SolidBrush(FontColor), Rect,
  84.                 new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
  85.         }
  86.     }
复制代码
七、添加形状方法抽象出泛型方法

我们看之前添加矩形和圆形的方法:

会发现很雷同,雷同是由于矩形和圆形都是形状基类的实现,那么我们本节课程添加了这三个新的形状,再如许写就太繁琐了,我们直接抽象出一个泛型方法来办理此标题:

可以看到,就是将天生矩形和圆形的方法利用泛型替换。
我们再写一个泛型方法来将形状添加到画布:

好了,到此我们的代码就进一步简化了,添加差别形状只必要传入对应的形状范例就行了:

是不是很优雅~
完备代码如下,各人可自行实验:
点击检察代码
  1. using Elements;
  2. using Elements.Links;
  3. using Elements.Shapes;
  4. using FlowChartCanvas;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.ComponentModel;
  8. using System.Data;
  9. using System.Drawing;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using System.Windows.Forms;
  14. namespace FlowChartDemo
  15. {
  16.     public partial class FormDemo07V4 : FormBase
  17.     {
  18.         public FormDemo07V4()
  19.         {
  20.             InitializeComponent();
  21.             DemoTitle = "第09节随课Demo  Part4";
  22.             DemoNote = "效果:所有形状内文本居中显示。";
  23.             //添加画布控件
  24.             _fcc = new FCCanvasV1();
  25.             _fcc.FCC_LinkColor += _fcc_FCC_LinkColor;
  26.             _fcc.FCC_LinkState += _fcc_FCC_LinkState;
  27.             _fcc.Dock = DockStyle.Fill;
  28.             panel1.Controls.Add(_fcc);
  29.         }
  30.         private void _fcc_FCC_LinkState(string obj)
  31.         {
  32.             toolStripStatusLabel1.Text = obj;
  33.         }
  34.         private Color _fcc_FCC_LinkColor()
  35.         {
  36.             return GetColor(_linkColorIndex++);
  37.         }
  38.         FCCanvasV1 _fcc;
  39.         /// <summary>
  40.         /// 形状颜色序号
  41.         /// </summary>
  42.         int _shapeColorIndex = 0;
  43.         /// <summary>
  44.         /// 连线颜色序号
  45.         /// </summary>
  46.         int _linkColorIndex = 0;
  47.                
  48.         /// <summary>
  49.         /// 获取不同的背景颜色
  50.         /// </summary>
  51.         /// <param name="i"></param>
  52.         /// <returns></returns>
  53.         Color GetColor(int i)
  54.         {
  55.             switch (i)
  56.             {
  57.                 case 0: return Color.Red;
  58.                 case 1: return Color.Green;
  59.                 case 2: return Color.Blue;
  60.                 case 3: return Color.Orange;
  61.                 case 4: return Color.Purple;
  62.                 default: return Color.Red;
  63.             }
  64.         }
  65.         //注:文章中说明:再次抽象
  66.         /// <summary>
  67.         /// 创建形状
  68.         /// </summary>
  69.         /// <typeparam name="T"></typeparam>
  70.         /// <param name="shapeText"></param>
  71.         /// <returns></returns>
  72.         T CreateShape<T>(string shapeText) where T:ShapeBase
  73.         {
  74.             var t = Activator.CreateInstance<T>();
  75.             t.Id = shapeText + Guid.NewGuid().ToString();
  76.             t.Rect = new Rectangle()
  77.             {
  78.                 X = 50,
  79.                 Y = 50,
  80.                 Width = 100,
  81.                 Height = 100,
  82.             };
  83.             t.FontColor = Color.White;
  84.             t.BackgroundColor = GetColor(_shapeColorIndex++);
  85.             t.Text = shapeText + _shapeColorIndex;
  86.             t.TextFont = Font;
  87.             return t;
  88.         }
  89.         /// <summary>
  90.         /// 创建指定类型的形状并添加到当前流程图画布中。
  91.         /// </summary>
  92.         /// <typeparam name="T"></typeparam>
  93.         /// <param name="shapeText"></param>
  94.         void CreateShapeAndAddToFCCanvas<T>(string shapeText) where T : ShapeBase
  95.         {
  96.             var sp = CreateShape<T>(shapeText);
  97.             _fcc.FCC_AddShapes(new List<ShapeBase>() { sp });
  98.             _fcc.FCC_Refresh();
  99.         }
  100.         private void toolStripButton1_Click(object sender, EventArgs e)
  101.         {
  102.             CreateShapeAndAddToFCCanvas<RectShapeV2>("矩形");
  103.         }
  104.         private void toolStripButton4_Click(object sender, EventArgs e)
  105.         {
  106.             CreateShapeAndAddToFCCanvas<EllipseShapeV2>("圆形");
  107.         }
  108.         private void toolStripButton5_Click(object sender, EventArgs e)
  109.         {
  110.             CreateShapeAndAddToFCCanvas<LozengeShapeV2>("菱形");
  111.         }
  112.         private void toolStripButton6_Click(object sender, EventArgs e)
  113.         {
  114.             CreateShapeAndAddToFCCanvas<ParallelogramShapeV2>("平行四边形");
  115.         }
  116.         private void toolStripButton7_Click(object sender, EventArgs e)
  117.         {
  118.             CreateShapeAndAddToFCCanvas<RoundRectShapeV2>("圆角矩形");
  119.         }
  120.         private void toolStripButton2_Click(object sender, EventArgs e)
  121.         {
  122.             _fcc.FCC_StartLink();
  123.         }
  124.         private void toolStripButton3_Click(object sender, EventArgs e)
  125.         {
  126.             _fcc.FCC_StopLink();
  127.         }
  128.     }
  129. }
复制代码
八、结语

我们本节课添加了多个差别的形状,这些形状也是流程图中常用的形状,有了这些底子,用户可按本身的需求添加本身的形状。固然如今的形状属性还很少,会随着课程的深入而丰富,以支持更多效果。
我们还抽象出一泛型方法来简化添加形状的利用,利用起来非常优雅。
如今根本的形状都有了,我们下节课就来添加新的连线:贝塞尔曲线,这个险些是最常见的曲线。
同时,有了新的连线,我们还会增长差别的毗连点用来连线,而不再只毗连形状的中心点。
敬请等待。
感谢各人的观看,本人水平有限,文章不敷之处接待各人批评指正。
-[END]-

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表