zoukankan      html  css  js  c++  java
  • 玩转控件:GDI+动态绘制流程图

    •    前言

      今天,要跟大家一起分享是“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我一起探讨。

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

  • 相关阅读:
    算法:合并排序(Merge Sort)
    安全:Web 安全学习笔记
    算法:冒泡排序(Bubble Sort)、插入排序(Insertion Sort)和选择排序(Selection Sort)总结
    算法:四种冒泡排序(Bubble Sort)实现
    算法:阶乘的五种算法
    算法:递归知识文章汇总
    算法:插入排序(Insertion Sort)
    .NET:线程本地存储、调用上下文、逻辑调用上下文
    算法:Rate of Growth
    企业应用:一个够用的、通用的状态机(管理实体的业务状态)
  • 原文地址:https://www.cnblogs.com/axing/p/13809854.html
Copyright © 2011-2022 走看看