winform曲线图动态绘制
在winform开发过程中,有时候会需要开发曲线图相关功能,本文将分享一个自己开发的一个自定义曲线功能,如坐标轴的动态改变,以及曲线点的拖动和曲线动态绘制功能。
首先准备一张精准的ps坐标图,由于我们要实现坐标轴可动态变化,所以这张ps图不含具体坐标轴的值。

然后在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(); } }
自此,功能全部完成。以上仅供参考,如有更好的方案,可以提供交流一下。
浙公网安备 33010602011771号