winform曲线图动态绘制

  在winform开发过程中,有时候会需要开发曲线图相关功能,本文将分享一个自己开发的一个自定义曲线功能,如坐标轴的动态改变,以及曲线点的拖动和曲线动态绘制功能。

  首先准备一张精准的ps坐标图,由于我们要实现坐标轴可动态变化,所以这张ps图不含具体坐标轴的值。

  坐标轴图1000*500

   然后在winform窗口的panel里添加这张图作为背景,并且在坐标轴的位置添加lable用于显示坐标轴数值。接下来是坐标点,我用的是12个坐标点,方法是添加12个pictureBox,然后给每一个pictureBox添加红色的背景,并缩到最小大小;同时添加12个textbox用于显示每个坐标点的坐标(相对于坐标轴)效果如图。

 

 

       

 

 

  曲线图功能核心是要实现点与点之间的连线,这个通过DrawLine方法即可实现,但是要实现坐标点的拖动,就必须是实时更新绘制,我的解决方法是:

  1、每次有点在拖动的时候清空已经绘制的线条。

  2、坐标点移动到新的位置以后,重新绘制界面。

  3、在界面绘制事件里加入所有曲线点之间线条绘制的功能。

  首先实现坐标点拖动功能,由于12个坐标的拖动功能都一样,给12个pictureBox添加相同的事件,贴上坐标点的拖动功能代码:

Point downPoint;//记录鼠标按下时的坐标(相对于panel)
Point centerPoint = new Point(5, 505);//坐标轴原点(相对于panel)
List<TextBox> textXList = new List<TextBox>();//横坐标集合 List<TextBox> textYList = new List<TextBox>();//纵坐标集合

int iMaxX=1000;//横纵最大值
int iMaxY=500;//纵轴最大值
     private void PictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                PictureBox current = (PictureBox)sender;
                current.Location = new Point(current.Location.X + e.Location.X - downPoint.X, current.Location.Y + e.Location.Y - downPoint.Y);
            }
        }

        private void PictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                downPoint = e.Location;
            }
        }

        private void PictureBox_Move(object sender, EventArgs e)//限制每个点的移动位置
        {
            PictureBox current = (PictureBox)sender;
#region 限制位置,根据自己的panel分辨率和坐标轴分辨率来定,我的panel分辨率为1020*520,坐标轴分辨率为1000*500,坐标轴居中显示 int index = int.Parse(current.Tag.ToString()) - 1;//每个pictureBox都有一个tag值,从1到12,用于区分对象 int x, y; if (index == 0) { x = current.Location.X <= panel1.Controls[index + 1].Location.X ? current.Location.X : panel1.Controls[index + 1].Location.X; x = x >= 5 ? x : 5; } else if (index == 11) { x = current.Location.X >= panel1.Controls[index - 1].Location.X ? current.Location.X : panel1.Controls[index - 1].Location.X; x = x <= 1005 ? x : 1005; } else { x = current.Location.X; if (current.Location.X <= panel1.Controls[index - 1].Location.X) { x = panel1.Controls[index - 1].Location.X; } if (current.Location.X >= panel1.Controls[index + 1].Location.X) { x = panel1.Controls[index + 1].Location.X; } } y = current.Location.Y; if (current.Location.Y < 5) { y = 5; } if (current.Location.Y > 505) { y = 505; } current.Location = new Point(x, y); #endregion
string x1 = (Math.Round((float)(current.Location.X- centerPoint.X)* iMaxX / 1000 ,1)).ToString(); string y1 = (Math.Round((float)(centerPoint.Y - current.Location.Y )* iMaxY / 500 ,1)).ToString();
for (int i = 0; i < 12; i++)//记录所有点的横纵坐标 { if (current.Tag == textXList[i].Tag) { textXList[i].Text = x1; } if (current.Tag == textYList[i].Tag) { textYList[i].Text = y1; panel1.Invalidate();//用于重绘界面 return; } } }

  然后就是绘制坐标点之间的连线:

     private void Panel1_Paint(object sender, PaintEventArgs e)
        {
            for (int i = 1; i < 12; i++)
            {
                Point current = new Point(panel1.Controls[i].Location.X + panel1.Controls[i].Width / 2, panel1.Controls[i].Location.Y + panel1.Controls[i].Height / 2);//当前点
                Point last = new Point(panel1.Controls[i - 1].Location.X + panel1.Controls[i - 1].Width / 2, panel1.Controls[i - 1].Location.Y + panel1.Controls[i - 1].Height / 2);//上一个点
                e.Graphics.DrawLine(new Pen(Color.Red, 2), current, last);//当前点和上一个点连线
            }
        }

  最后显示坐标轴数值:

     public void ChangXValue()//卸载窗体的load事件里
        {
            label1.Text = (iMaxX / 10).ToString();
            label2.Text = (2 * iMaxX / 10).ToString();
            label3.Text = (3 * iMaxX / 10).ToString();
            label4.Text = (4 * iMaxX / 10).ToString();
            label5.Text = (5 * iMaxX / 10).ToString();
            label6.Text = (6 * iMaxX / 10).ToString();
            label7.Text = (7 * iMaxX / 10).ToString();
            label8.Text = (8 * iMaxX / 10).ToString();
            label9.Text = (9 * iMaxX / 10).ToString();
            label10.Text = (10 * formShip.curveClass.iMaxX / 10).ToString();

            label11.Text = (iMaxY / 10).ToString();
            label12.Text = (2 * iMaxY / 10).ToString();
            label13.Text = (3 * iMaxY / 10).ToString();
            label14.Text = (4 * iMaxY / 10).ToString();
            label15.Text = (5 * iMaxY / 10).ToString();
            label16.Text = (6 * iMaxY / 10).ToString();
            label17.Text = (7 * iMaxY / 10).ToString();
            label18.Text = (8 * iMaxY / 10).ToString();
            label19.Text = (9 * iMaxY / 10).ToString();
            label20.Text = (10 *iMaxY / 10).ToString();
        }

  此时,已经完成曲线点的绘制以及点的拖动功能,效果图如下:

 

   最后,如果想实现通过直接配置textbox来实现点的坐标变化,可以加上如下代码:

     private void X2_LostFocus(object sender, EventArgs e)//失去焦点事件
        {
            TextBox tempTxt = (TextBox)sender;
            int index = int.Parse(tempTxt.Tag.ToString()) - 1;

            int x = (int)(float.Parse(tempTxt.Text) * 1000 / formShip.curveClass.iMaxX + centerPoint.X);
            panel1.Controls[index].Location = new Point(x, panel1.Controls[index].Location.Y);
        }

        private void Y12_LostFocus(object sender, EventArgs e)//失去焦点事件
        {
            TextBox tempTxt = (TextBox)sender;
            int index = int.Parse(tempTxt.Tag.ToString()) - 1;

            int y = (int)(centerPoint.Y - float.Parse(tempTxt.Text) * 500 / formShip.curveClass.iMaxY);
            panel1.Controls[index].Location = new Point(panel1.Controls[index].Location.X, y);
        }

        private void X2_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != 8 && !Char.IsDigit(e.KeyChar))//退格键和数字
            { 
                e.Handled = true;
            }
            if (e.KeyChar == 13 )//回车键
            {
                pictureBox1.Focus();
            }
        }

  自此,功能全部完成。以上仅供参考,如有更好的方案,可以提供交流一下。

posted @ 2020-09-23 15:14  橘猫不太胖  阅读(2834)  评论(0)    收藏  举报