惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
WordPress大学
WordPress大学
博客园 - 【当耐特】
The Cloudflare Blog
B
Blog
Last Week in AI
Last Week in AI
小众软件
小众软件
量子位
S
SegmentFault 最新的问题
V
Visual Studio Blog
博客园 - 叶小钗
美团技术团队
阮一峰的网络日志
阮一峰的网络日志
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
宝玉的分享
宝玉的分享
A
About on SuperTechFans
雷峰网
雷峰网
J
Java Code Geeks
Microsoft Azure Blog
Microsoft Azure Blog
腾讯CDC
MongoDB | Blog
MongoDB | Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Martin Fowler
Martin Fowler

博客园 - 何以解忧唯有撸码

Winform上位机也能写出媲美Avalonia的界面 C# 视频录制监控系统 玩转控件:封装个带图片的Label控件 c#实现包裹扣面单的几种方式 c#造个轮子--GIF录制工具 c#造个轮子-取色器TakeColor(附源码) OpenCvSharp基于颜色反差规避FBA面单贴标2 OpenCvSharp基于颜色反差规避FBA面单贴标 winform 绘制太阳,地球,月球 运作规律 玩转控件:Fucking ERP之流程图 玩转控件:对Dev的GridControl控件扩展 玩转控件:封装Dev的SearchLookupEdit 玩转控件:对Dev中GridControl控件的封装和扩展 玩转控件:封装Dev的LabelControl和TextEdit 玩转控件:扩展Dev中SimpleButton 玩转控件:重写/重绘Dev中MessageBox弹窗控件 C# 视频监控系统(提供源码分享) C# 小游戏-拼图魔方【Game Puzzle】 玩转控件:重绘DEVEXPRESS中DateEdit控件 —— 让DateEdit支持只选择年月 (提供源码下载) 玩转控件:重绘ComboBox —— 让ComboBox多列显示 (提供源码下载) 分享:动态添加控件和公用章水印工具 提供源码下载
玩转控件:GDI+动态绘制流程图
何以解忧唯有撸码 · 2020-10-13 · via 博客园 - 何以解忧唯有撸码
  •    前言

  今天,要跟大家一起分享是“GDI+动态生成流程图”的功能。别看名字高大上(也就那样儿--!),其实就是动态生成控件,然后GDI+绘制直线连接控件罢了。实际项目效果图如下:

  • Talk is Cheap,Show me the Code

  首先,人靠衣装马靠鞍!在绘制流程图之前,我们得有个高大上的背景来衬托,比如网格背景:

代码如下:

  /// <summary>
  /// 初始化网格
  /// </summary>
  private void InitGridLine()
  {
      pictureBox1.BorderStyle = BorderStyle.Fixed3D;
      pictureBox1.Focus();
      m_picture = pictureBox1.CreateGraphics();
      Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
      Graphics gp = Graphics.FromImage(canvas);
      DrawGrid(gp);
      pictureBox1.BackgroundImage = canvas;
      pictureBox1.Refresh();
  }
  //绘制网格
  private void DrawGrid(Graphics gp)
  {
      for (int i = 0; i < Row; i++)
      {
          gp.DrawLine(new Pen(Color.LightCyan), (i + 1) * pictureBox1.Width / Row, 0, (i + 1) * pictureBox1.Width / Row, pictureBox1.Height);
      }
      for (int i = 0; i < colums; i++)
      {
          gp.DrawLine(new Pen(Color.LightCyan), 0, (i + 1) * pictureBox1.Height / colums, pictureBox1.Width, (i + 1) * pictureBox1.Height / colums);
      }
  }

     我们此处以PictureBox为画布,初始化好网格背景后,就可以开始创建流程标签了,效果如下:

  代码如下:

/// <summary>
/// 绘制元素,此处以Label为例
/// </summary>
/// <returns></returns>
private Label createBlock(string lblName)
{
    try
    {
        Label label = new Label();
        label.AutoSize = false;
        //TODO:如需动态生成每个标签元素位置,请根据实际情况,初始化标签的Location即可。此处默认X=150,Y 以75间隔递增
        label.Location = new Point(150, iPosition); 
        iPosition = iPosition + 75;
        label.Size = new Size(89, 36);
        label.BackColor = Color.DarkOliveGreen;
        label.ForeColor = Color.Black;
        label.FlatStyle = FlatStyle.Flat;
        label.TextAlign = ContentAlignment.MiddleCenter;
        label.Text = lblName;
        //TODO;可以绑定标签元素的右键事件
        //label.ContextMenuStrip = contextBlock;
        pictureBox1.Controls.Add(label);
        //拖拽移动
        MoveBlock(label);
        return label;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    return null;
}

    实现动态生成的标签拖拽移动效果,方法如下:

 //标签移动效果
private void MoveBlock(Label block, Label endBlock = null)
{
    block.MouseDown += (ss, ee) =>
    {
        if (ee.Button == System.Windows.Forms.MouseButtons.Left)
            fPoint = Control.MousePosition;
    };
    block.MouseMove += (ss, ee) =>
    {
        if (ee.Button == System.Windows.Forms.MouseButtons.Left)
        {
            Point temp = Control.MousePosition;
            Point res = new Point(fPoint.X - temp.X, fPoint.Y - temp.Y);

            block.Location = new Point(block.Location.X - res.X,
                                       block.Location.Y - res.Y);
            fPoint = temp;
            pictureBox1.Invalidate();   // <------- draw the new lines
        }
    };
}

      生成好背景网格和标签,以及实现标签的拖拽后,就需要绘制直线按自己需求,实现连接了本文我们用 Tuple 来实现两个标签的连接关系。

//用于存储需要直线连接的元素
List<Tuple<Label, Label>> lines = new List<Tuple<Label, Label>>();

    绑定PictureBox的Paint事件,利用GDI+的DrawLine实现绘制直线。

private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
    foreach (Tuple<Label, Label> t in lines)
    {
        Point p1 = new Point(t.Item1.Left + t.Item1.Width / 2,
                             t.Item1.Top + t.Item1.Height / 2);
        Point p2 = new Point(t.Item2.Left + t.Item2.Width / 2,
                             t.Item2.Top + t.Item2.Height / 2);

        e.Graphics.DrawLine(Pens.Black, p1, p2);
    }
}

      好了,所有工作都已完成,此时,只需要把想要连接的两个标签添加到当前集合中,即可完成直线的连接功能。效果如图

  参考文献:

     https://docs.microsoft.com/zh-cn/dotnet/api/system.tuple-2?view=netcore-3.1

  https://stackoverflow.com/questions/31626027/how-to-connect-with-line-shapes-labels-on-runtime/31642448#31642448?newreg=de162494b077460383555e4da76bdd18

  • 结束语

   由于后续所有重写/重绘控件都在同一个项目使用,而且Dev系统引用文件较多,压缩后源码文件仍然很大,如果有需要源码的朋友,可以微信公众号回复:erp,即可获取Fucking ERP所有源码示例~!有疑问的也可以CALL我一起探讨。

        最后,感谢您的耐心陪伴!如果觉得本篇博文对您或者身边朋友有帮助的,麻烦点个关注!赠人玫瑰,手留余香,您的支持就是我写作最大的动力,感谢您的关注,期待和您一起探讨!再会!