【问题标题】:Why does the drawn line disappear when mouse button is released?为什么释放鼠标按钮时绘制的线会消失?
【发布时间】:2014-08-19 08:59:29
【问题描述】:

我一直在玩System.Drawing,除了一件事之外,我已经让它按照我想要的方式工作了。当我松开鼠标按钮时,线条消失了。

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

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;
        }
    }
}

【问题讨论】:

    标签: c# .net winforms gdi+


    【解决方案1】:

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

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

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

    那么你在画线之前检查if (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);
        }
    }
    

    我猜你不需要if (mouseDown)签入OnPaint方法。

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

    【讨论】:

    • 谢谢 Sriram,这已经回答了我的问题。我的意图是能够拖动线条,当我释放按钮时,将线条留在原处。
    • @Aeron 看看my related answer helps。您只需将点声明为Nullable&lt;T&gt; 检查是否nullable.HasValue 并绘制它。你不需要if (mouseDown)检查。
    【解决方案2】:

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

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

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

    // 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>();
    

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

    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);
    }
    

    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);
    }
    

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

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

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

    1. 将数据格式保留为矢量,而不是位图(允许高分辨率缩放),
    2. 添加编辑功能(即选择现有行、移动它、更改其颜色和类似的东西)。

    【讨论】:

    • 此外,扩展它以绘制不同类型的几何对象是 OOP 中的一个常见练习:您将拥有一个基础 Shape 类(或一个 IShape 接口),它将暴露其 @987654330 @ 方法并绘制自己。这意味着会有一个形状列表和一个当前形状而不是一条线,并且您可能会从菜单中选择形状类型。
    猜你喜欢
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-01
    相关资源
    最近更新 更多