绘制/形状/图形问题(提供 ZIP)

时间:2021-01-16 16:28:42

标签: c# winforms graphics draw paint

我的代码需要一些帮助,因为我做错了什么!我试图以正确的方式修复和做所有事情,但我制造了更多问题......下面的代码是一个类似疼痛的程序的原型,我想在我知道我需要的一切并且原型完美运行后创建它。

我在这里分享了完整的代码,我还提供了一个下载我的完整项目/解决方案的链接,以便您可以运行它以查看发生了什么或进行修改以进行测试.

下载: PainPrototype_BushWookie

主要问题:

  • 我想以该函数在绘图应用程序中的工作方式通过鼠标按钮创建矩形。这意味着当我按下鼠标时,我开始绘制矩形,当我在画布中移动鼠标时,矩形会动态改变其大小以适应。当我的鼠标抬起时,矩形就完成了。我相信你知道我在说什么,因为这就是几乎所有绘图软件绘制包括矩形在内的形状的方式。我可以对此进行编码,但我不确定我是否以正确的方式进行了编码,而且我也遇到了这个问题!在我绘制了一个矩形后,我再次单击以绘制另一个矩形后,前一个矩形消失/删除了..我需要在您的帮助下解决这个问题!
<块引用>

当我使用我的“图形”对象(在代码中注释)和 不是“e.Graphics”来绘制矩形这将绘制每个形状 厚/框架/更新..所以当我移动鼠标时,我会变成数百个 rect 连续抽奖..

  • 我还有“画笔”工具,它可以像 Photoshop 中的画笔工具或基本 Windows 画图中的钢笔工具一样在画布上进行绘制。这部分工作正常!但是我从'MouseMove' 事件而不是从Paint 中绘制。我在教程视频中看到了这一点,但每个人都说“仅从疼痛事件中绘制”.. 当我尝试这样做时,画笔的功能已损坏。这意味着,它绘制直线而不是“追逐”鼠标光标并在其路径之后绘制。你能帮我澄清一下吗,这应该如何从 Paint 事件中工作?

  • 当我单击“清除”按钮时出现了我的最后一个问题,这应该清除整个画布!这适用于我的画笔(仅当我从 MouseMove 绘制时)和像素工具(绘制单个像素)并正确清除画布。我从 Paint 事件绘制的矩形未清除。在我按下“新建”按钮以获取新的空画布后,矩形也会留在那里。这是个大问题!如果我从 Paint 事件中清除它就可以了,但这会导致 Paint 事件在无限循环中调用..

这是我的主要问题,我需要帮助! 我还有一些问题关于我从 MSDN 中无法正确理解的绘图/图形:

  • 为什么我应该只从 Pain 事件中抽取?或者转出问题,如果我从 MouseMove 中绘制有什么问题?
  • 什么是 OnPaint(),为什么它与 Paint() 不同?
  • Invalidate().. 我知道这会调用 Paint 事件,但还有什么要知道的吗?为什么它与导致 Paint 事件重绘的任何其他方法不同?

我还想要求概述我的代码的每一行,以帮助了解我可以改进的地方,因为我在 C# 方面还很陌生!例如,当我尝试从“新建”按钮释放旧图片框时……我的所有线条都是必需的吗?还是我错过了什么?等等等等。或者我的代码逻辑很好,或者我应该以其他方式做吗?

提前感谢您抽出宝贵时间!如果您从上面的链接下载我的完整解决方案以更轻松地查看并运行/测试它,那将是最好的!我只想帮助解决我的问题并学习正确的编码方式!再次感谢,感谢您的帮助!


这里是我的代码,请注意pbx_canvasbmp_canvas的区别! (我想在位图上绘制,因为我想稍后保存创建的图像)。

namespace NewFile___PixelDraw___Pen___Shapes
{
    public partial class Form1 : Form
    {
        PictureBox pbx_usedColorBox;
        PictureBox pbx_canvas;
        Bitmap btm_canvas;
        Graphics graphics;
        Pen pen;

        Button btn_activeTool = new Button();
        Point initialMouse = new Point(-1, -1);
        Color chosenColor = Color.White;
        bool mouseDown;

        Rectangle rect;

        public Form1()
        {
            InitializeComponent();

            pen = new Pen(chosenColor, (float)num_drawWidth.Value)
            {
                StartCap = System.Drawing.Drawing2D.LineCap.Round,
                EndCap = System.Drawing.Drawing2D.LineCap.Round,
            };

            tbx_canvasX.MaxLength = 5;
            tbx_canvasY.MaxLength = 5;

            pbx_usedColorBox = pbx_cBlack;
            pnl_cPalette.BackColor = chosenColor;
            pbx_cWhite.BorderStyle = BorderStyle.None;
        }

        // NEW
        private void btn_new_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(tbx_canvasX.Text) && !string.IsNullOrEmpty(tbx_canvasY.Text))
            {
                Point offset = new Point(7, 19);
                Point canvasSize = new Point(int.Parse(tbx_canvasX.Text), int.Parse(tbx_canvasY.Text));
                Point canvasLocation = new Point((Size.Width / 2) - (canvasSize.X / 2) - offset.X, (Size.Height / 2) - (canvasSize.Y / 2) - offset.Y);

                if (canvasSize.X != 0 && canvasSize.Y != 0)
                {
                    if (pbx_canvas != null && btm_canvas != null)
                    {
                        pbx_canvas.MouseDown -= Pbx_canvas_MouseDown;
                        pbx_canvas.MouseMove -= Pbx_canvas_MouseMove;
                        pbx_canvas.MouseUp -= Pbx_canvas_MouseUp;
                        Controls.Remove(pbx_canvas);
                        pbx_canvas.Dispose();
                        btm_canvas.Dispose();
                        graphics.Dispose();
                    }

                    pbx_canvas = new PictureBox
                    {
                        Size = new Size(canvasSize.X, canvasSize.Y),
                        BorderStyle = BorderStyle.FixedSingle,
                        Anchor = AnchorStyles.None,
                        Location = canvasLocation,
                        BackColor = Color.White,
                        Cursor = Cursors.Cross,
                    };

                    Controls.Add(pbx_canvas);
                    pbx_canvas.MouseDown += Pbx_canvas_MouseDown;
                    pbx_canvas.MouseMove += Pbx_canvas_MouseMove;
                    pbx_canvas.MouseUp += Pbx_canvas_MouseUp;
                    pbx_canvas.Paint += Pbx_canvas_Paint;

                    btm_canvas = new Bitmap(canvasSize.X, canvasSize.Y);
                    graphics = Graphics.FromImage(btm_canvas);

                    if (cbx_smoothing.Checked)
                    {
                        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    }
                }
                else
                {
                    tbx_canvasX.Text = "";
                    tbx_canvasY.Text = "";
                }
            }
        }

        // PAINT
        private void Pbx_canvas_Paint(object sender, PaintEventArgs e)
        {
            Debug.WriteLine("IN PAINT EVENT!");

            e.Graphics.DrawRectangle(pen, rect);
            //graphics.DrawRectangle(pen, rect);
        }

        // M > DOWN
        private void Pbx_canvas_MouseDown(object sender, MouseEventArgs e)
        {
            switch (btn_activeTool.Name)
            {
                case "btn_toolBrush":
                    mouseDown = true;
                    initialMouse = e.Location;
                    break;
                case "btn_toolRect":
                    mouseDown = true;
                    initialMouse = e.Location;
                    rect = new Rectangle(initialMouse, new Size(0, 0));
                    break;
            }
        }

        // M > MOVE
        private void Pbx_canvas_MouseMove(object sender, MouseEventArgs e)
        {
            switch (btn_activeTool.Name)
            {
                case "btn_toolBrush":
                    if (mouseDown == true && initialMouse.X != -1 && initialMouse.Y != -1)
                    {
                        graphics.DrawLine(pen, initialMouse, e.Location);
                        pbx_canvas.Image = btm_canvas;
                        initialMouse = e.Location;
                    }
                    break;
                case "btn_toolRect":
                    if (mouseDown == true && initialMouse.X != -1 && initialMouse.Y != -1)
                    {
                        rect = new Rectangle(Math.Min(e.X, initialMouse.X),
                                             Math.Min(e.Y, initialMouse.Y),
                                             Math.Abs(e.X - initialMouse.X),
                                             Math.Abs(e.Y - initialMouse.Y));

                        pbx_canvas.Image = btm_canvas;
                        //Invalidate(rect);
                    }
                    break;
            }
        }

        // M > UP
        private void Pbx_canvas_MouseUp(object sender, MouseEventArgs e)
        {
            switch (btn_activeTool.Name)
            {
                case "btn_toolPixel":
                    btm_canvas.SetPixel(e.X, e.Y, chosenColor);
                    pbx_canvas.Image = btm_canvas; 
                    break;
                case "btn_toolBrush": 
                    mouseDown = false;
                    initialMouse.X = -1;
                    initialMouse.Y = -1;
                    break;
                case "btn_toolRect":
                    mouseDown = false;
                    initialMouse.X = -1;
                    initialMouse.Y = -1;
                    break;
            }
        }

        // PIXEL
        private void btn_toolPixel_Click(object sender, EventArgs e)
        {
            btn_activeTool.BackColor = Color.GhostWhite;
            btn_activeTool = (Button)sender;
            btn_activeTool.BackColor = Color.Beige;
        }

        // BRUSH
        private void btn_toolBrush_Click(object sender, EventArgs e)
        {
            btn_activeTool.BackColor = Color.GhostWhite;
            btn_activeTool = (Button)sender;
            btn_activeTool.BackColor = Color.Beige;
        }

        // RECT
        private void btn_toolRect_Click(object sender, EventArgs e)
        {
            btn_activeTool.BackColor = Color.GhostWhite;
            btn_activeTool = (Button)sender;
            btn_activeTool.BackColor = Color.Beige;
        }

        // CLEAR
        private void btn_clear_Click(object sender, EventArgs e)
        {
            graphics.Clear(pbx_canvas.BackColor);
            pbx_canvas.Image = null;
        }

        // Color change
        private void G_pbx_colors_Click(object sender, EventArgs e)
        {
            PictureBox pbx_sender = (PictureBox)sender;

            pbx_usedColorBox.BorderStyle = BorderStyle.FixedSingle;
            pbx_sender.BorderStyle = BorderStyle.None;
            pbx_usedColorBox = pbx_sender;

            chosenColor = pbx_sender.BackColor;
            pnl_cPalette.BackColor = chosenColor;
            pen.Color = chosenColor;
        }

        // CanvasSize
        private void G_tbx_canvasSize_Enter(object sender, EventArgs e)
        {
            BeginInvoke(new Action(() => (sender as TextBox).SelectAll()));
        }
        private void G_tbx_canvasSize_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = !char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar);
        }

        // DrawWidth
        private void num_drawWidth_ValueChanged(object sender, EventArgs e)
        {
            pen.Width = (float)num_drawWidth.Value;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

<块引用>

为什么我应该只从 Paint 事件中绘制?或者转出问题,如果我从 MouseMove 中绘制有什么问题?

你打算画什么?您无权访问控件的图形对象。如果需要,您可以绘制位图或其他缓冲区。但是在事件处理程序中绘制并不是一个好主意。您可能有多个输入事件,如果每个事件都导致代价高昂的绘制,而不是廉价的无效,应用程序将无法正常运行。

<块引用>

什么是 OnPaint(),为什么它与 Paint() 不同?

覆盖 OnPaint 或使用 Paint 事件通常无关紧要。

<块引用>

Invalidate().. 我知道这会调用 Paint 事件,但还有什么要知道的吗?为什么它与任何其他导致 Paint 事件重绘的方法不同?

这不会调用paint事件。它会将控件标记为稍后需要重绘。

提供的代码有很多问题,比如

  • 在 switch 语句中使用字符串
  • 所有逻辑似乎都在一个类中
  • 您正在按钮单击处理程序中附加事件
  • 据我所知,你没有处理任何东西

这是关于我将如何解决问题的高级概述。

当激活一个工具时,应该有一个状态机来跟踪使用的工具,以及如何为工具绘制形状。您似乎有一个原始状态机,但我建议使用类来模拟状态,以便每个工具彼此独立。

使用工具完成后,您应该将完成的形状绘制到表示完成图形的位图。此位图应在活动工具的图形之前绘制到屏幕上。这样,当您绘制下一个矩形时,前一个矩形会存储在位图中。

另一种方法是保留一个形状缓冲区,以便在使用工具时附加到其中。这样您就可以依次绘制每个形状,并且可以在创建后删除或更改它。

相关问题