【问题标题】:How to draw a graph in chart control with mouse如何用鼠标在图表控件中绘制图形
【发布时间】:2015-07-06 07:01:17
【问题描述】:

我的任务是使用鼠标在图表控件中绘制图形并从图形中检索 (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-forms。

【问题讨论】:

  • 如果您应该 a) 使用图表控件并 b) 稍后检索点,您确定您确实应该在图表的表面上绘制吗?我猜您应该在图表中的系列中添加点。您还需要清楚鼠标的使用方式:在图表上单击还是拖动?
  • @TaW Ya 我知道如何通过使用一系列点成系列然后将该系列添加到图中来绘制图形。但我的任务是用鼠标移动绘制图形。我无法将这些点放入图表上绘制的系列中。这是我检索关于图表的点 X、Y 的问题。
  • 这很棘手。由于您正在绘制图表的 Paint 事件,因此转换方法将起作用,根据MSDN
  • @TaW 雅谢谢。我正在做。同时,如果可能的话,请给我一些这种类型转换的例子。
  • 在我的回答中查看更新的示例!

标签: c# winforms visual-studio-2010 charts linechart


【解决方案1】:

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 方法的当前图表布局从像素点列表重新创建它们。当标签大小、其他缩放、其他最小/最大值等发生变化时,布局总是会发生变化。

也许你真的想反过来工作,即使用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 总是绑定到图表的缩放比例,所以它们是“真实的东西”。当您调整图表大小时,DataPoints 和它们组成的图形会照常缩放,并且绘制的像素点会完美地跟随:

(当您调整第一个版本的大小时,您可以看到没有任何东西被放大或缩小,只有图表的网格线发生了变化......)

请注意,我首先设置了一些东西,因此并不是我添加的每个点都会强制执行过多的布局更改。另请注意,当新点发生变化时,有时仍会出现反馈循环,例如标签大小,这会强制更改布局和绘制循环。要解决此问题,您可能应该控制标签的格式!

另请注意,这两种转换方法仅在Paint 事件中(正确)有效,可能是因为只有这样当前布局才会被解决。

【讨论】:

  • 谢谢,我会处理这个并回复你。希望这行得通。
  • 它以某种方式工作,问题是当我最大化窗口图时,它从以前的位置发生了变化。无论如何谢谢
  • 您使用哪个版本?第二个不应该那样做。
  • 哦,抱歉忘记提了,第一个代码更改了,但第二个很好。
  • 嘿,当我执行第二个代码时,图形与我在问题中提到的第二个相同。请检查一下。它使我们在图表控件之外进行绘制。
猜你喜欢
  • 2012-04-20
  • 1970-01-01
  • 2013-07-31
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
  • 2012-07-24
  • 2013-06-28
  • 1970-01-01
相关资源
最近更新 更多