Winform 拖拽控件流程

1  效果展示,双击节点可以新的页面进行操作

 

2 代码编写

 1、新建一个流程节点用户控件,2个lable 控件组成,如果要lable 可以搞改变大小可以将AutoSize设置为false

 后台代码:

public partial class FlowNode : UserControl
    {
        /// <summary>
        /// 上一个节点
        /// </summary>
        public string PreNodeID { get; set; }
        /// <summary>
        /// 当前节点
        /// </summary>
        public string NodeID { get; set; }
        /// <summary>
        /// 下一个节点
        /// </summary>
        public string NextNodeID { get; set; }



        /// <summary>
        /// 输入参数
        /// </summary>
        public HObject InputParms { get; set; }

        /// <summary>
        /// 输出参数
        /// </summary>
        public HObject OutputParms { get; set; }



        /// <summary>
        /// 保存上一个节点数据
        /// </summary>
        public static FlowNode PreFlowNode { get; set; }


        /// <summary>
        /// 节点名称
        /// </summary>
        /// 
        [Category("节点名称")]
        public string NodeName { get { return labTilt.Text; } set { labTilt.Text = value; } }


        /// <summary>
        /// 
        /// </summary>
        [Category("节点颜色")]
        public Color LightColor { get { return lblLight.ForeColor; } set { lblLight.ForeColor = value; } }
        public FlowNode()
        {
            InitializeComponent();
            NodeID = Guid.NewGuid().ToString("N");
            LightColor = Color.LightGray;

            foreach (Control item in this.Controls)
            {
                // 移动相关
                item.MouseDown += UserControl1_MouseDown;
                item.MouseUp += UserControl1_MouseUp;
                item.MouseMove += UserControl1_MouseMove;

                //双击打开对应的窗体
                item.DoubleClick += Item_DoubleClick;

            }
        }
        /// <summary>
        /// 双击打开页面
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Item_DoubleClick(object sender, EventArgs e)
        {
           var node=(sender as Control).Parent;
            switch (NodeName)
            {
                case "加载图像":
                    new FrmImage(this).ShowDialog();
                    PreFlowNode = this;
                    break;
                case "绘制矩形":
                    new FrmROI4(PreFlowNode, this).ShowDialog();
                    PreFlowNode = this;
                    break;
                case "创建模版":
                    new FrmCreateModel(PreFlowNode, this).ShowDialog();
                    PreFlowNode = this;
                    break;
                case "模版匹配":
                    new FrmResult(PreFlowNode, this).ShowDialog();
                    break;
            }
        }

        /// <summary>
        /// 是否移动
        /// </summary>
        bool mMoving = false;

        Point mStartPoint;
        /// <summary>
        /// 按下鼠标左键  我要开始移动了
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl1_MouseDown(object sender, MouseEventArgs e)
        {
            // 标识控制准备移动
            mMoving = true;
            //记录开始的位置
            mStartPoint=new Point(e.X, e.Y);
        }
  
       /// <summary>
       /// 拖动节点结束
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
        private void UserControl1_MouseUp(object sender, MouseEventArgs e)
        {
            if (mMoving)
            {
                mMoving = false;
                Control control= sender as Control;
                control.Cursor = Cursors.Default;
            }
           
        }

        /// <summary>
        /// 移动设置操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl1_MouseMove(object sender, MouseEventArgs e)
        {
            if (mMoving)
            {
                if (e.Button == MouseButtons.Left)
                {
                    // 这个是label 
                    var control = sender as Control;
                    // 这个是用户控件
                    var node = control.Parent;
                    // 获取控件的偏移量
                    //将控件当前位置加上鼠标移动的距离得到的新位置
                    int left = node.Left+(e.X-mStartPoint.X);
                    int top = node.Top+(e.Y-mStartPoint.Y);

                    //控件本身的宽 高 
                    int width=node.Width;
                    int height=node.Height;

                    // 动态获取编辑流程区域大小
                    var rect = node.Parent.ClientRectangle;
                    //判断拖拽过程中不能超过边界
                    if (left + width > rect.Width)
                    {
                        left = rect.Width-width;
                    }
                    if (left < 0)
                    {
                        left = 0;
                    }
                    if (top + height > rect.Height)
                    { 
                        top = rect.Height-height;
                    }
                    if (top < 0)
                    {
                        top = 0;
                    }
                    //设置控件的新的偏移量
                    node.Left = left;
                    node.Top = top;
                 //var  s=   node.Parent;
                    //强制刷新界面 要不然界面成了一个模糊的饼,强制刷新绘图区域
                     node.Parent.Invalidate(); ;
                }
            }
        }



        #region 实现绘制节点连续操作

        #endregion

        /// <summary>
        /// 绘制点到点之间的线
        /// </summary>
        public void DrawPontToPointLine(Control node1, Control node2, Control panel)
        {
            Graphics g = panel.CreateGraphics();
            // 定义2个点的对象
            Point point1, point2;

            // 左到右  
            if (Math.Abs(node2.Location.X - node1.Location.X) > Math.Abs(node2.Location.Y - node1.Location.Y) && node2.Location.X >= node1.Location.X)
            {
                point1 = new Point(node1.Location.X + node1.Width + 1, node1.Location.Y + node1.Height / 2);
                point2 = new Point(node2.Location.X - 1, node2.Location.Y + node2.Height / 2);
                DrawJoinLine(point1, point2, E_DrawLineDirect.L_R, g);

            }
            // 右  左
            else if (Math.Abs(node2.Location.X - node1.Location.X) > Math.Abs(node2.Location.Y - node1.Location.Y) && node2.Location.X < node1.Location.X)
            {
                point1 = new Point(node1.Location.X - 1, node1.Location.Y + node1.Height / 2);
                point2 = new Point(node2.Location.X + node2.Width + 1, node2.Location.Y + node2.Height / 2);
                DrawJoinLine(point1, point2, E_DrawLineDirect.R_L, g);

            }
            // 上  下
            else if (Math.Abs(node2.Location.Y - node1.Location.Y) > Math.Abs(node2.Location.X - node1.Location.X) && node2.Location.Y >= node1.Location.Y)
            {
                point1 = new Point(node1.Location.X + node1.Width / 2, node1.Location.Y + node1.Height + 1);
                point2 = new Point(node2.Location.X + node2.Width / 2, node2.Location.Y - 1);
                DrawJoinLine(point1, point2, E_DrawLineDirect.U_D, g);

            }
            // 下  上
            else if (Math.Abs(node2.Location.Y - node1.Location.Y) > Math.Abs(node2.Location.X - node1.Location.X) && node2.Location.Y < node1.Location.Y)
            {
                point1 = new Point(node1.Location.X + node1.Width / 2, node1.Location.Y - 1);
                point2 = new Point(node2.Location.X + node2.Width / 2, node2.Location.Y + node2.Height + 1);
                DrawJoinLine(point1, point2, E_DrawLineDirect.D_U, g);
            }
        }

        /// <summary>
        /// 根据2点绘制一条线
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="forward"></param>
        /// <param name="g"></param>
        public void DrawJoinLine(Point p1, Point p2, E_DrawLineDirect forward, Graphics g)
        {

            //Graphics g = panel3.CreateGraphics();

            g.SmoothingMode = SmoothingMode.HighQuality;
            Color color = Color.DarkRed;
            Pen p = new Pen(color, 5);
            p.DashStyle = DashStyle.Solid;
            p.StartCap = LineCap.Round;
            p.EndCap = LineCap.ArrowAnchor;
            p.LineJoin = LineJoin.Round;
            Point inflectPoint1;
            Point inflectPoint2;
            if (forward == E_DrawLineDirect.L_R || forward == E_DrawLineDirect.L_R)
            {
                inflectPoint1 = new Point((p1.X + p2.X) / 2, p1.Y);
                inflectPoint2 = new Point((p1.X + p2.X) / 2, p2.Y);
            }
            else
            {
                inflectPoint1 = new Point(p1.X, (p1.Y + p2.Y) / 2);
                inflectPoint2 = new Point(p2.X, (p1.Y + p2.Y) / 2);
            }
            Point[] points = new Point[] { p1, inflectPoint1, inflectPoint2, p2 };
            g.DrawLines(p, points);
        }

    }


    /// <summary>
    /// 是否连线状态
    /// </summary>
    public enum E_DrawStatus
    {
        /// <summary>
        /// 正常状态
        /// </summary>
        Normal,
        /// <summary>
        /// 画线
        /// </summary>
        DrawLint

    }

    /// <summary>
    /// 绘制线的方向
    /// </summary>
    public enum E_DrawLineDirect
    {
        /// <summary>
        /// 左到右
        /// </summary>
        L_R,
        /// <summary>
        /// 右到左
        /// </summary>
        R_L,
        /// <summary>
        /// 上--下
        /// </summary>
        U_D,
        /// <summary>
        /// 下--上
        /// </summary>
        D_U

    }

 

2 、设置主页面 控件

 

      Label mlabel;
        /// <summary>
        /// 设置Label 可以移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void LabelMouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Control control = sender as Control;
                mlabel = (Label)sender;
                //设置当前点击上的样式,设置控件可以移动
                control.DoDragDrop(sender, DragDropEffects.Copy | DragDropEffects.Move);
            }
        }

  

3、设置承载控件Panel 的属性

 添加事件

 
            /// <summary>
            ///  设置鼠标样式
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
         private void panel3_DragEnter(object sender, DragEventArgs e)
          {
            if (e.Data.GetDataPresent(typeof(Label)))
            {
                 e.Effect = DragDropEffects.Copy | DragDropEffects.Move;
            };
        }
        /// <summary>
        /// 拖动完成时候
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void panel3_DragDrop(object sender, DragEventArgs e)
        {
            Control contrainer = sender as Control;
            FlowNode btn = new FlowNode();
            foreach (Control item in btn.Controls)
            {
                item.Click += btn_Click;
            }
            btn.Size = new Size(btn.Width, btn.Height);
            btn.NodeName = mlabel.Text;
            btn.Location = contrainer.PointToClient(new Point(e.X, e.Y));
            contrainer.Controls.Add(btn);
        }

        /// <summary>
        /// 鼠标点击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void btn_Click(object sender, EventArgs e)
        {
                if (DrawStuas == E_DrawStatus.DrawLint)//绘制线的状态
                {
                    if (NumNo == 0)//点击第一控件
                    {
                        Node1 = (FlowNode)(sender as Control).Parent;
                        NumNo = 1;
                    }
                    else if (NumNo == 1)//点击第二个节点 绘制2个连线操作
                    {
                        if (Node1.Equals(Node2))
                        {
                            MessageBox.Show("不能选择同一个控件");
                        }
                        else
                        {
                            NumNo = 0;
                            Node2 = (FlowNode)(sender as Control).Parent;

                            Node1.NextNodeID = Node2.NodeID;
                            Node2.PreNodeID= Node1.NodeID;
                            // 绘制连线
                            Node1.DrawPontToPointLine(Node1,Node2,panel3);
                            DrawStuas = E_DrawStatus.Normal;
                        }

                    }
                }
        }
     
        /// <summary>
        /// 重绘时发生
        /// 当拖动节点时候,需要重新绘制
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void panel3_Paint(object sender, PaintEventArgs e)
        {
           Control cont=(Control)sender;

            //找出流程编辑节点所有的空间
            foreach (var item in cont.Controls)
            {
                if (item is FlowNode)//这个根据自己到时候定义
                {
                    var node1 = (FlowNode)item;
                    foreach (var item2 in cont.Controls)
                    {
                        var node2 = (FlowNode)item2;
                        if (node1.NextNodeID != null && node1.NextNodeID == node2.NodeID)
                        {
                            node1.DrawPontToPointLine(node1, node2,panel3);
                        }
                    }
                }
            }
        }

 

4 、设置开始连线的导火线,上下文,这里的上下文控件可以增加删除 或者其他业务

 

     /// <summary>
        /// 上下文
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
           // MessageBox.Show("上下文");
            DrawStuas = E_DrawStatus.DrawLint;
            //注销节点的所有事件
            Node1 = null;
            Node2 = null;
            NumNo = 0;
        }

 

5 当双击节点弹出每个节点对应的设置页面

 开始节点,没有输入参数

 public partial class FrmImage : Form
    {
        FlowNode mFlowNode;
        public FrmImage(FlowNode flowNode)
        {
            InitializeComponent();
            mFlowNode = flowNode;
        }

  中间节点有输入参数和输出参数

 public partial class FrmCreateModel : Form
    {
        FlowNode mPreFlowNode;

        FlowNode mCurrentFlowNode;

        //HWindow ttttHWindow;
        public FrmCreateModel(FlowNode preNode, FlowNode flowNode)
        {
            InitializeComponent();
            mPreFlowNode = preNode;
            mCurrentFlowNode = flowNode;
        }
    private void FrmCreateModel_Load(object sender, EventArgs e)
        {
            halconUC1.DispImage(mPreFlowNode.OutputParms);
        }

总结: 大致流程代码都在这里了,可以扩展做自动化测试,流程化操作

 

posted @ 2024-05-17 14:56  陌念  阅读(196)  评论(0)    收藏  举报