释放鼠标按钮时为什么绘制的线会消失?

时间:2023-01-04 09:44:23

I've been playing around with System.Drawing and I've got it working the way that I wanted it to except for one thing. When I release the mouse button, the line disappears.

我一直在玩System.Drawing并且我已经按照我想要的方式工作,除了一件事。当我释放鼠标按钮时,线条消失。

How do I ensure the line remains exactly where I left it?

如何确保线路保持在我离开的位置?

using System;
using System.Drawing;
using System.Windows.Forms;

namespace DrawingSample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            this.DoubleBuffered = true;
        }

        Graphics graphics;

        Random
            color = new Random(1);
        Int32
            penThickness = 1;
        Point
            currentCursorLocation, initialTouchLocation, touchOffset;
        Boolean
            mouseDown;

        protected override void OnPaint(PaintEventArgs e)
        {
            graphics = e.Graphics;

            if (mouseDown)
            {
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

                //DrawRectangle(graphics);
                //DrawEllipse(graphics);

                DrawLine(graphics);
            }
        }

        private void DrawRectangle(Graphics graphics)
        {
            graphics.DrawRectangle(new Pen(
                Color.FromArgb((color.Next(1, 
                255)), 
                (color.Next(1, 
                255)), 
                (color.Next(1, 
                255)))
                , 
                penThickness),
                currentCursorLocation.X,
                currentCursorLocation.Y,
                (this.Width / 2),
                (this.Height / 2)
                );
        }

        private void DrawEllipse(Graphics graphics)
        {
            graphics.DrawEllipse(new Pen(
                Color.FromArgb((color.Next(1, 255)),
                (color.Next(1, 255)),
                (color.Next(1, 255))), penThickness), 
                new RectangleF(currentCursorLocation, new Size(100, 100)));
        }

        private void DrawLine(Graphics graphics)
        {
            graphics.DrawLine(new Pen(
                Color.FromArgb((color.Next(1, 255)), 
                (color.Next(1, 255)), 
                (color.Next(1, 255))), penThickness),
                currentCursorLocation.X,
                currentCursorLocation.Y,
                touchOffset.X,
                touchOffset.Y
                );
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            currentCursorLocation = e.Location;
            this.Refresh();
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            if (!mouseDown)
            {
                touchOffset = e.Location;
                mouseDown = true;
            }
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            mouseDown = false;
        }
    }
}

2 个解决方案

#1


3  

You're asking the code to behave like that. So it does the same thing.

你要求代码表现得那样。所以它做同样的事情。

You set mouseDown to false in Form1_MouseUp event.

在Form1_MouseUp事件中将mouseDown设置为false。

private void Form1_MouseUp(object sender, MouseEventArgs e)
{
    mouseDown = false; //<--Here
}

Then you are checking if (mouseDown) before painting the line.

然后你在绘制线之前检查是否(mouseDown)。

protected override void OnPaint(PaintEventArgs e)
{
    graphics = e.Graphics;

    if (mouseDown)//<--Here
    {
        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

        //DrawRectangle(graphics);
        //DrawEllipse(graphics);

        DrawLine(graphics);
    }
}

I guess you don't need if (mouseDown) check in OnPaint method.

我猜你不需要if(mouseDown)检查OnPaint方法。

Not sure what your intention is, If you need more help drop a comment below the answer.

不确定你的意图是什么,如果你需要更多的帮助,请在答案下方发表评论。

#2


1  

You probably want to keep a list of all drawn lines in a separate field to be able to redraw them when necessary. In other words, if you define a class like this:

您可能希望在单独的字段中保留所有绘制线的列表,以便能够在必要时重绘它们。换句话说,如果你定义一个这样的类:

class Line
{
    public Point Start { get; set; }
    public Point End { get; set; }
}

This allows you to have both a list of already drawn lines, and the currently drawn line (while mouse is held down):

这允许您同时拥有已绘制线条的列表和当前绘制的线条(按住鼠标时):

// this is the line currently being drawn (i.e. a temporary line)
private Line _currentLine = null;

// this is the list of all finished lines
private readonly List<Line> _lines = new List<Line>();

Mouse handlers are now straightforward:

鼠标处理程序现在很简单:

protected override void OnMouseDown(MouseEventArgs e)
{
    // when button is pressed, create a new _currentLine instance

    _currentLine = new Line() { Start = e.Location, End = e.Location };
    Invalidate();
    base.OnMouseDown(e);
}

protected override void OnMouseMove(MouseEventArgs e)
{
    // when mouse is moved, update the End position

    if (_currentLine != null)
    {
        _currentLine.End = e.Location;
        Invalidate();
    }
    base.OnMouseMove(e);
}

protected override void OnMouseUp(MouseEventArgs e)
{
    // when button is released, add the line to the list

    if (_currentLine != null)
    {
        _lines.Add(_currentLine);
        _currentLine = null;
        Invalidate();
    }
    base.OnMouseUp(e);
}

And the OnPaint method would look something like this:

而OnPaint方法看起来像这样:

protected override void OnPaint(PaintEventArgs e)
{
    // if you want smoother (anti-aliased) graphics, set these props
    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
    e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

    // draw all existing lines from the list
    using (var p = new Pen(Color.Black, 2f))
        foreach (var line in _lines)
            e.Graphics.DrawLine(p, line.Start, line.End);

    // if mouse is down, draw the dashed line also
    if (_currentLine != null)
        using (var p = new Pen(Color.Salmon, 2f))
        {
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            e.Graphics.DrawLine(p, _currentLine.Start, _currentLine.End);
        }

    base.OnPaint(e);
}

Also, there is much less flickering if you use the Form.SetStyles method in the constructor to indicate that you'll be doing all painting yourself and don't want Windows to clear the form by itself. This means that your Form's constructor should look something like:

此外,如果您在构造函数中使用Form.SetStyles方法来指示您将自己进行所有绘制并且不希望Windows自行清除表单,则闪烁要少得多。这意味着您的Form的构造函数应该类似于:

public Form1()
{
    InitializeComponent();
    SetStyle(
       ControlStyles.AllPaintingInWmPaint | 
       ControlStyles.OptimizedDoubleBuffer | 
       ControlStyles.ResizeRedraw | 
       ControlStyles.UserPaint,
       true);
}

Keeping the list of lines is much better than simply drawing them onto the surface, because it allows you to:

保持行列表比简单地将它们绘制到曲面上要好得多,因为它允许您:

  1. Keep the data format as vectors, instead of as a bitmap (allows high-res scaling),
  2. 将数据格式保留为矢量,而不是位图(允许高分辨率缩放),
  3. Add editing functionality (i.e. select an existing line, move it, change its color, and similar stuff).
  4. 添加编辑功能(即选择现有行,移动它,更改其颜色和类似的东西)。

#1


3  

You're asking the code to behave like that. So it does the same thing.

你要求代码表现得那样。所以它做同样的事情。

You set mouseDown to false in Form1_MouseUp event.

在Form1_MouseUp事件中将mouseDown设置为false。

private void Form1_MouseUp(object sender, MouseEventArgs e)
{
    mouseDown = false; //<--Here
}

Then you are checking if (mouseDown) before painting the line.

然后你在绘制线之前检查是否(mouseDown)。

protected override void OnPaint(PaintEventArgs e)
{
    graphics = e.Graphics;

    if (mouseDown)//<--Here
    {
        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

        //DrawRectangle(graphics);
        //DrawEllipse(graphics);

        DrawLine(graphics);
    }
}

I guess you don't need if (mouseDown) check in OnPaint method.

我猜你不需要if(mouseDown)检查OnPaint方法。

Not sure what your intention is, If you need more help drop a comment below the answer.

不确定你的意图是什么,如果你需要更多的帮助,请在答案下方发表评论。

#2


1  

You probably want to keep a list of all drawn lines in a separate field to be able to redraw them when necessary. In other words, if you define a class like this:

您可能希望在单独的字段中保留所有绘制线的列表,以便能够在必要时重绘它们。换句话说,如果你定义一个这样的类:

class Line
{
    public Point Start { get; set; }
    public Point End { get; set; }
}

This allows you to have both a list of already drawn lines, and the currently drawn line (while mouse is held down):

这允许您同时拥有已绘制线条的列表和当前绘制的线条(按住鼠标时):

// this is the line currently being drawn (i.e. a temporary line)
private Line _currentLine = null;

// this is the list of all finished lines
private readonly List<Line> _lines = new List<Line>();

Mouse handlers are now straightforward:

鼠标处理程序现在很简单:

protected override void OnMouseDown(MouseEventArgs e)
{
    // when button is pressed, create a new _currentLine instance

    _currentLine = new Line() { Start = e.Location, End = e.Location };
    Invalidate();
    base.OnMouseDown(e);
}

protected override void OnMouseMove(MouseEventArgs e)
{
    // when mouse is moved, update the End position

    if (_currentLine != null)
    {
        _currentLine.End = e.Location;
        Invalidate();
    }
    base.OnMouseMove(e);
}

protected override void OnMouseUp(MouseEventArgs e)
{
    // when button is released, add the line to the list

    if (_currentLine != null)
    {
        _lines.Add(_currentLine);
        _currentLine = null;
        Invalidate();
    }
    base.OnMouseUp(e);
}

And the OnPaint method would look something like this:

而OnPaint方法看起来像这样:

protected override void OnPaint(PaintEventArgs e)
{
    // if you want smoother (anti-aliased) graphics, set these props
    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
    e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

    // draw all existing lines from the list
    using (var p = new Pen(Color.Black, 2f))
        foreach (var line in _lines)
            e.Graphics.DrawLine(p, line.Start, line.End);

    // if mouse is down, draw the dashed line also
    if (_currentLine != null)
        using (var p = new Pen(Color.Salmon, 2f))
        {
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            e.Graphics.DrawLine(p, _currentLine.Start, _currentLine.End);
        }

    base.OnPaint(e);
}

Also, there is much less flickering if you use the Form.SetStyles method in the constructor to indicate that you'll be doing all painting yourself and don't want Windows to clear the form by itself. This means that your Form's constructor should look something like:

此外,如果您在构造函数中使用Form.SetStyles方法来指示您将自己进行所有绘制并且不希望Windows自行清除表单,则闪烁要少得多。这意味着您的Form的构造函数应该类似于:

public Form1()
{
    InitializeComponent();
    SetStyle(
       ControlStyles.AllPaintingInWmPaint | 
       ControlStyles.OptimizedDoubleBuffer | 
       ControlStyles.ResizeRedraw | 
       ControlStyles.UserPaint,
       true);
}

Keeping the list of lines is much better than simply drawing them onto the surface, because it allows you to:

保持行列表比简单地将它们绘制到曲面上要好得多,因为它允许您:

  1. Keep the data format as vectors, instead of as a bitmap (allows high-res scaling),
  2. 将数据格式保留为矢量,而不是位图(允许高分辨率缩放),
  3. Add editing functionality (i.e. select an existing line, move it, change its color, and similar stuff).
  4. 添加编辑功能(即选择现有行,移动它,更改其颜色和类似的东西)。