9

这是我用鼠标在图表上绘制自定义线的绘图代码。你能帮我以正确的方式做吗?

namespace Grafi
    {
        public partial class Form1 : Form
        {

            bool isDrawing = false;
            Point prevPoint;

            public Form1()
            {
                InitializeComponent();
            }

            private void chartTemperature_MouseDown(object sender, MouseEventArgs e)
            {
                isDrawing = true;
                prevPoint = e.Location;
            }

            private void chartTemperature_MouseMove(object sender, MouseEventArgs e)
            {
                Pen p = new Pen(Color.Red, 2); 
                if (isDrawing)
                {
                    Graphics g = chartTemperature.CreateGraphics();    
                    g.DrawLine(p, prevPoint, e.Location);
                    prevPoint = e.Location;

                    numOfMouseEvents = 0;              
                }
                p.Dispose();
            }

            private void chartTemperature_MouseUp(object sender, MouseEventArgs e)
            {
                isDrawing = false;
            }
        }
    }

问题是,当我调整表格大小时,我的线条消失了。每当引发 onPaint 事件时,它就会消失。

4

4 回答 4

9

试试这个……这是一种描边方法,实现非常简单,并且尽可能接近你自己的代码。Stokes 是鼠标移动的单独集合。鼠标在上下之间的每一次移动都被记录为一个笔画,所有的笔画都被收集起来,然后在绘制事件被触发时重新绘制。这个例子很简单,但可能是一个很好的起点。

请注意,您必须为图表对象添加绘制处理程序。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace Grafi
{
    public partial class Form1 : Form
    {
        bool isDrawing;
        // our collection of strokes for drawing
        List<List<Point>> _strokes = new List<List<Point>>();
        // the current stroke being drawn
        List<Point> _currStroke;
        // our pen
        Pen _pen = new Pen(Color.Red, 2); 

        public Form1()
        {
            InitializeComponent();
        }

        private void chartTemperature_MouseDown(object sender, MouseEventArgs e)
        {
            isDrawing = true;
            // mouse is down, starting new stroke
            _currStroke = new List<Point>();
            // add the initial point to the new stroke
            _currStroke.Add(e.Location);
            // add the new stroke collection to our strokes collection
            _strokes.Add(_currStroke);
        }

        private void chartTemperature_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDrawing)
            {
                // record stroke point if we're in drawing mode
                _currStroke.Add(e.Location);
                Refresh(); // refresh the drawing to see the latest section
            }
        }

        private void chartTemperature_MouseUp(object sender, MouseEventArgs e)
        {
            isDrawing = false;
        }

        private void chartTemperature_Paint(object sender, PaintEventArgs e)
        {
            // now handle and redraw our strokes on the paint event
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            foreach (List<Point> stroke in _strokes.Where(x => x.Count > 1))
                e.Graphics.DrawLines(_pen, stroke.ToArray());
        }
    }
}
于 2010-11-12T13:58:52.757 回答
1

您需要将线路存储在某个地方。

您需要采取的步骤是:

  1. 创建某个地方以将您的积分存储在主类中,例如 . an ArrayList<ArrayList<Point>>- 其中 eachArrayList<Point>包含一行中的点列表。
  2. 等待 mousedown 事件,并在行new ArrayList<Point>列表的末尾为新行(例如 a )创建一个数组
  3. 等待 mousemoved 事件,并在拖动鼠标时在列表的最后一行添加一个点。要求在此处更新您的窗口。
  4. 在您的paint, 遍历所有行,并绘制数组中每一行的每个点。
  5. 要清除绘图,只需将数组替换为空白列表,然后更新窗口。

如果您不将您的线路存储在某个地方,它们将会丢失。这有意义吗?

另一种存储线条的方法是使用一个Canvas对象,其中所绘制的像素图会被记住并自动绘制。如果您不介意将线数据用作矢量点,并且您可能还想使用图像或颜色,那么这可能是一种更好的方法。

于 2010-11-12T13:27:21.080 回答
1

您当前的实施有任何问题吗?它是否有效,或者您只是想让代码更好地用于已经工作的功能。

我认为你的逻辑看起来很好。但是,我会像这样向 Pen 添加一个 using 子句:

private void chartTemperature_MouseMove(object sender, MouseEventArgs e)
{
  using( Pen p = new Pen(Color.Red, 2)){
    if (isDrawing)
    {
      Graphics g = chartTemperature.CreateGraphics();    
      g.DrawLine(p, prevPoint, e.Location);
      prevPoint = e.Location;

      numOfMouseEvents = 0;              
    }
  }
}

这样,即使在创建 Pen 并调用Dispose.

但是,您也可以考虑创建Pen一个类变量,这样您就不必在每次移动鼠标时都创建和处理它。

于 2010-11-12T13:06:34.063 回答
0

不久前,我发布了一个关于如何使用鼠标移动画线的解决方案。这应该适合你。

  Point mAnchorPoint = new Point(200, 200);
  Point mPreviousPoint = Point.Empty;

  private void panel1_MouseMove(object sender, MouseEventArgs e)
  {
     if (mPreviousPoint != Point.Empty)
     {
        // Clear last line drawn
        ControlPaint.DrawReversibleLine(PointToScreen(mAnchorPoint), PointToScreen(mPreviousPoint), Color.Pink);
     }

     // Update previous point
     mPreviousPoint = e.Location;
     mPreviousPoint.Offset(myPanel1.Location);

     // Draw the new line
     ControlPaint.DrawReversibleLine(PointToScreen(mAnchorPoint), PointToScreen(mPreviousPoint), Color.Pink);
  }

基本上你可以做的是每次鼠标移动时画一条线。如果有前一行并且您仍在移动鼠标,请擦除该行并绘制新行。请注意,此示例基于特定的偏移量Panel(此示例中为 myPanel1)。相应调整。如果您调整控件的大小,您将需要使用锚点上一点重绘线。

于 2010-11-12T13:05:56.493 回答