如何用鼠标在图表控件中绘制图形
How to draw a graph in chart control with mouse
我的任务是使用鼠标在图表控件中绘制图形并从图形中检索 (X,Y) 点。
我试过用鼠标画图。
这是正常的图形。
用鼠标绘制后,它看起来像:
我用来绘制图形的代码是:
private void Form1_Load(object sender, EventArgs e)
{
chart1.ChartAreas[0].AxisX.Minimum =0170101;
chart1.ChartAreas[0].AxisX.Maximum =0175951;
chart1.ChartAreas[0].AxisY.Minimum=0780101;
chart1.ChartAreas[0].AxisY.Maximum=0785951;
double range = chart1.ChartAreas[0].AxisX.Maximum - chart1.ChartAreas[0].AxisX.Minimum;
chart1.ChartAreas[0].AxisX.Interval = range / 5;
range = chart1.ChartAreas[0].AxisY.Maximum - chart1.ChartAreas[0].AxisY.Minimum;
chart1.ChartAreas[0].AxisY.Interval = range / 5;
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (!(FirstPoint == null))
{
Graphics g = chart1.CreateGraphics();
Pen ErasePen = new Pen(Color.Transparent);
g.DrawLine(ErasePen, FirstPoint, TempPoint);
TempPoint = new Point(e.X, e.Y);
this.Refresh();
}
}
private void chart1_MouseDown_1(object sender, MouseEventArgs e)
{
FirstPoint = new Point(e.X, e.Y);
TempPoint = new Point(e.X, e.Y);
}
private void chart1_MouseUp_1(object sender, MouseEventArgs e)
{
LineEndPoints Line = new LineEndPoints
{
StartPoint = FirstPoint,
endPont = new Point(e.X, e.Y)
};
LinesList.Add(Line);
// FirstPoint = null;
this.Refresh();
}
private void chart1_Paint_1(object sender, PaintEventArgs e)
{
foreach (LineEndPoints line in LinesList)
{
e.Graphics.DrawLine(Pens.Green, line.StartPoint, line.endPont);
}
if (!(FirstPoint == null))
{
e.Graphics.DrawLine(Pens.Red, FirstPoint, TempPoint);
}
}
当我以前绘制图形时,它正在远离图表控件的最大值和最小值。
现在我需要知道的是:
1) 我的图形不应离开图表控件的 X 和 Y 轴点。
2) 我需要知道相对于图表轴而不是表格轴绘制的图表的 X、Y 点。
我使用 C# VS 2010 Win 窗体。
Chart
使用与其控制界面不同的 coordinate system for its content,即鼠标定位;有转换函数,但它们有一个警告:它们只能保证在 Paint 事件中工作..
这是一个 示例,它将像素点转换为图表点值。您可以看到两个图形非常好地重叠: DataPoints
以蓝色线条连接,像素点以红色虚线连接..:
public Form1()
{
InitializeComponent();
chart1.Series[0].ChartType = SeriesChartType.Line;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Maximum = 500;
chart1.ChartAreas[0].AxisY.Minimum = 0;
chart1.ChartAreas[0].AxisY.Maximum = 500;
}
List<Point> points = new List<Point>();
private void chart1_MouseClick(object sender, MouseEventArgs e)
{
points.Add(e.Location);
chart1.Invalidate();
}
private void chart1_Paint(object sender, PaintEventArgs e)
{
chart1.Series[0].Points.Clear();
foreach(Point pt in points)
{
double dx = chart1.ChartAreas[0].AxisX.PixelPositionToValue(pt.X);
double dy = chart1.ChartAreas[0].AxisY.PixelPositionToValue(pt.Y);
chart1.Series[0].Points.AddXY(dx, dy);
}
if (points.Count > 1)
using (Pen pen = new Pen(Color.Red, 2.5f))
e.Graphics.DrawLines(pen, points.ToArray());
}
请注意,这将始终清除 DataPoints
并根据当前图表布局使用 PixelPositionToValue
方法从像素点列表重新创建它们.当标签大小、其他缩放比例、其他 minimum/maximum 值等发生变化时,布局将始终发生变化。
也许你真的想反过来,即使用 ValueToPixelPosition
改变点击点。
这里是保留DataPoints
并重新计算像素点的修改示例:
List<Point> points = new List<Point>();
Point lastPoint = Point.Empty;
private void chart1_MouseClick(object sender, MouseEventArgs e)
{
lastPoint = e.Location;
chart1.Invalidate();
}
private void chart1_Paint(object sender, PaintEventArgs e)
{
// if we have a new point, convert to DataPoint and add to Series.Points:
if (lastPoint != Point.Empty)
{
double dx = chart1.ChartAreas[0].AxisX.PixelPositionToValue(lastPoint.X);
double dy = chart1.ChartAreas[0].AxisY.PixelPositionToValue(lastPoint.Y);
chart1.Series[0].Points.AddXY(dx, dy);
}
lastPoint = Point.Empty;
// now recalculate all pixel points:
points.Clear();
foreach (DataPoint pt in chart1.Series[0].Points)
{
double x = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(pt.XValue);
double y = chart1.ChartAreas[0].AxisY.ValueToPixelPosition(pt.YValues[0]);
points.Add(new Point((int)x, (int)y));
}
if (points.Count > 1)
using (Pen pen = new Pen(Color.Red, 2.5f))
{
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
e.Graphics.DrawLines(pen, points.ToArray());
}
}
这更有意义,因为 DataPoints
总是绑定到图表的缩放比例,所以它们是 'real thing'。当您调整图表大小时,DataPoints
和它们组成的图形会像往常一样缩放,并且绘制的像素点完全遵循:
(当您调整第一个版本的大小时,您可以看到没有任何东西被放大或缩小,只有图表的网格线发生变化..)
请注意,我首先设置了一些内容,这样并不是我添加的每个点都会强制执行过多的布局更改。另请注意,有时当新点发生变化时仍会出现反馈循环,例如标签大小,强制更改布局和绘制循环。要解决此问题,您可能应该控制标签的格式!
另请注意,这两种转换方法仅在 Paint
事件中(正确)有效,可能是因为只有在那时才确定当前布局。
我的任务是使用鼠标在图表控件中绘制图形并从图形中检索 (X,Y) 点。
我试过用鼠标画图。
这是正常的图形。
private void Form1_Load(object sender, EventArgs e)
{
chart1.ChartAreas[0].AxisX.Minimum =0170101;
chart1.ChartAreas[0].AxisX.Maximum =0175951;
chart1.ChartAreas[0].AxisY.Minimum=0780101;
chart1.ChartAreas[0].AxisY.Maximum=0785951;
double range = chart1.ChartAreas[0].AxisX.Maximum - chart1.ChartAreas[0].AxisX.Minimum;
chart1.ChartAreas[0].AxisX.Interval = range / 5;
range = chart1.ChartAreas[0].AxisY.Maximum - chart1.ChartAreas[0].AxisY.Minimum;
chart1.ChartAreas[0].AxisY.Interval = range / 5;
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (!(FirstPoint == null))
{
Graphics g = chart1.CreateGraphics();
Pen ErasePen = new Pen(Color.Transparent);
g.DrawLine(ErasePen, FirstPoint, TempPoint);
TempPoint = new Point(e.X, e.Y);
this.Refresh();
}
}
private void chart1_MouseDown_1(object sender, MouseEventArgs e)
{
FirstPoint = new Point(e.X, e.Y);
TempPoint = new Point(e.X, e.Y);
}
private void chart1_MouseUp_1(object sender, MouseEventArgs e)
{
LineEndPoints Line = new LineEndPoints
{
StartPoint = FirstPoint,
endPont = new Point(e.X, e.Y)
};
LinesList.Add(Line);
// FirstPoint = null;
this.Refresh();
}
private void chart1_Paint_1(object sender, PaintEventArgs e)
{
foreach (LineEndPoints line in LinesList)
{
e.Graphics.DrawLine(Pens.Green, line.StartPoint, line.endPont);
}
if (!(FirstPoint == null))
{
e.Graphics.DrawLine(Pens.Red, FirstPoint, TempPoint);
}
}
当我以前绘制图形时,它正在远离图表控件的最大值和最小值。 现在我需要知道的是: 1) 我的图形不应离开图表控件的 X 和 Y 轴点。 2) 我需要知道相对于图表轴而不是表格轴绘制的图表的 X、Y 点。
我使用 C# VS 2010 Win 窗体。
Chart
使用与其控制界面不同的 coordinate system for its content,即鼠标定位;有转换函数,但它们有一个警告:它们只能保证在 Paint 事件中工作..
这是一个 示例,它将像素点转换为图表点值。您可以看到两个图形非常好地重叠: DataPoints
以蓝色线条连接,像素点以红色虚线连接..:
public Form1()
{
InitializeComponent();
chart1.Series[0].ChartType = SeriesChartType.Line;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Maximum = 500;
chart1.ChartAreas[0].AxisY.Minimum = 0;
chart1.ChartAreas[0].AxisY.Maximum = 500;
}
List<Point> points = new List<Point>();
private void chart1_MouseClick(object sender, MouseEventArgs e)
{
points.Add(e.Location);
chart1.Invalidate();
}
private void chart1_Paint(object sender, PaintEventArgs e)
{
chart1.Series[0].Points.Clear();
foreach(Point pt in points)
{
double dx = chart1.ChartAreas[0].AxisX.PixelPositionToValue(pt.X);
double dy = chart1.ChartAreas[0].AxisY.PixelPositionToValue(pt.Y);
chart1.Series[0].Points.AddXY(dx, dy);
}
if (points.Count > 1)
using (Pen pen = new Pen(Color.Red, 2.5f))
e.Graphics.DrawLines(pen, points.ToArray());
}
请注意,这将始终清除 DataPoints
并根据当前图表布局使用 PixelPositionToValue
方法从像素点列表重新创建它们.当标签大小、其他缩放比例、其他 minimum/maximum 值等发生变化时,布局将始终发生变化。
也许你真的想反过来,即使用 ValueToPixelPosition
改变点击点。
这里是保留DataPoints
并重新计算像素点的修改示例:
List<Point> points = new List<Point>();
Point lastPoint = Point.Empty;
private void chart1_MouseClick(object sender, MouseEventArgs e)
{
lastPoint = e.Location;
chart1.Invalidate();
}
private void chart1_Paint(object sender, PaintEventArgs e)
{
// if we have a new point, convert to DataPoint and add to Series.Points:
if (lastPoint != Point.Empty)
{
double dx = chart1.ChartAreas[0].AxisX.PixelPositionToValue(lastPoint.X);
double dy = chart1.ChartAreas[0].AxisY.PixelPositionToValue(lastPoint.Y);
chart1.Series[0].Points.AddXY(dx, dy);
}
lastPoint = Point.Empty;
// now recalculate all pixel points:
points.Clear();
foreach (DataPoint pt in chart1.Series[0].Points)
{
double x = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(pt.XValue);
double y = chart1.ChartAreas[0].AxisY.ValueToPixelPosition(pt.YValues[0]);
points.Add(new Point((int)x, (int)y));
}
if (points.Count > 1)
using (Pen pen = new Pen(Color.Red, 2.5f))
{
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
e.Graphics.DrawLines(pen, points.ToArray());
}
}
这更有意义,因为 DataPoints
总是绑定到图表的缩放比例,所以它们是 'real thing'。当您调整图表大小时,DataPoints
和它们组成的图形会像往常一样缩放,并且绘制的像素点完全遵循:
(当您调整第一个版本的大小时,您可以看到没有任何东西被放大或缩小,只有图表的网格线发生变化..)
请注意,我首先设置了一些内容,这样并不是我添加的每个点都会强制执行过多的布局更改。另请注意,有时当新点发生变化时仍会出现反馈循环,例如标签大小,强制更改布局和绘制循环。要解决此问题,您可能应该控制标签的格式!
另请注意,这两种转换方法仅在 Paint
事件中(正确)有效,可能是因为只有在那时才确定当前布局。