【问题标题】:Drawing in Winforms在 Winforms 中绘图
【发布时间】:2012-06-18 22:26:20
【问题描述】:

我已经编写了这段代码,但是它不起作用。这不仅行不通,而且我尝试过的绘图方法都没有奏效。我花了一两个多小时试图解决这个问题,但没有成功。我尝试过简单的程序,它所做的只是显示一条小线,但无论我做什么它都不会工作:c

我做错了什么,或者什么可能导致这种情况?

private void pictureBox1_MouseDown(object sender, 
                                   MouseEventArgs m, 
                                   EventArgs e, 
                                   PaintEventArgs q)
{
    if (m.Button == System.Windows.Forms.MouseButtons.Left)
    {
        Point currpoint = System.Windows.Forms.Cursor.Position;

        Point origin = new Point(0, 0);

        decimal sizee = nud.Value;

        int size = Convert.ToInt32(sizee);

        Random randonGen = new Random();

        Color randomColor = Color.FromArgb(randonGen.Next(255),
                                           randonGen.Next(255),
                                           randonGen.Next(255));

        Pen selPen = new Pen(randomColor, size);

        Graphics g = Graphics.FromImage(pictureBox1.Image);

        g.DrawLine(selPen, 3, 3, 133, 133);
    }
}

【问题讨论】:

  • 你的笔的宽度是多少?大小以像素为单位,所以如果它是 0,那么你的线将没有粗细。还可以尝试使用恒定颜色 - 首先简化代码以证明其有效,然后再增加复杂性。
  • 宽度默认为5,有一个numericUpDown改变它

标签: c# winforms drawing


【解决方案1】:

尝试添加一个

pictureBox1.Invalidate();

打电话。

【讨论】:

  • g.Dispose(); 或更好的 using close。
【解决方案2】:

这不是绘制图片框的正确方法:

private void pictureBox1_MouseDown(object sender, 
                                   MouseEventArgs m, 
                                   EventArgs e, 
                                   PaintEventArgs q)
{
    if (m.Button == System.Windows.Forms.MouseButtons.Left)
    {
        Point currpoint = System.Windows.Forms.Cursor.Position;

        Point origin = new Point(0, 0);

        decimal sizee = nud.Value;

        int size = Convert.ToInt32(sizee);

        Random randonGen = new Random();

        Color randomColor = Color.FromArgb(randonGen.Next(255),
                                           randonGen.Next(255),
                                           randonGen.Next(255));

        Pen selPen = new Pen(randomColor, size);

        using(Graphics g = pictureBox1.CreateGraphics()) // Use the CreateGraphics method to create a graphic and draw on the picture box. Use using in order to free the graphics resources.
        {
             g.DrawLine(selPen, 3, 3, 133, 133);
        }
    }
}

顺便说一句,此方法将创建一个临时图像,当控件无效时会重置该图像。对于更持久的绘图,您需要监听图片框的 Paint 事件并在那里绘制您的图形。

【讨论】:

  • 这个方法确实可以创建一个临时图像,但是OP的方法不会。
  • 绘制到图片框图像是一个坏主意(好吧,我们只是说这是一个不好的做法)。从图片框没有加载图像的情况开始,它可能是许多错误的根源:)
  • 如何监听绘画事件?
  • 在设计器中选中图片框,然后在图片框的属性中,点击事件Tab,在Paint表前面双击。
  • 你说这是不好的做法,有什么更好的方法?
【解决方案3】:

您必须先从图像中绘制它。然后附加到pictureBox1

Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(canvas);

Point currpoint = System.Windows.Forms.Cursor.Position;

Point origin = new Point(0, 0);

decimal sizee = nud.Value;

int size = Convert.ToInt32(sizee);

Random randonGen = new Random();

Color randomColor = Color.FromArgb(randonGen.Next(255),
                                   randonGen.Next(255),
                                   randonGen.Next(255));

Pen selPen = new Pen(randomColor, size);

g.DrawLine(selPen, 3, 3, 133, 133);
pictureBox1.image = canvas;

【讨论】:

    【解决方案4】:

    这是一个老问题,如果其他人也有类似的问题。见下文。首先让我们检查一下 Ops 代码。

    (1) 查看代码:建议的第一个更改是保持 Pen 的格式简单,直到我们更好地了解 Pen 在绘制图形时的实际工作原理。看看我们从图像创建图形的 Op 行,这是一个很好的例子,说明如何通过使用位图的图形上下文直接绘制(“这意味着写入”)到提供的位图。接下来,Op 提供了一个很好的 Graphics DrawLine 方法示例,该方法可以将定义的线绘制到提供的位图上。

    (2) 由于缺少细节,我们必须对 Op 提供的位图及其绘制位图的方法做出以下假设。假设这个pictureBox1中已经存在一个图像;如果未设置图像,我们从图像中获取的图形将来自空图像,或者每个像素将是黑色的,就像脚注一样:

    (a) Pen 的颜色对于现有位图是唯一的,并且颜色的 alpha 分量足够高,可以在绘制时实际看到生成的颜色(如有疑问,请使用唯一的纯色或者至少将 alpha 通道 设置为 255)?

    (b) Op 想要绘制的这条线从 Left 3、Top 3 到 Left 133 开始,即 3 像素在位图左侧的右侧,这条线的高度为 133,因此出于演示目的,Pen 的线大小已更改为宽度 = 3。

    (c) 最后考虑,pictureBox1.Size 是否足以让我们看到这条画线?线的几何形状形成一个类似于 RectangleF(3, 3, 3, 133) 结构的矩形,因此如果图片框1 Bounds rectangle 与派生线的矩形相交,则该 intersection 是可以绘制线条并视为可见的位置。

    在我们可以从图形绘制到pictureBox1 图像之前,我们必须首先将pictureBox1 图像数据转换回可用的图像类型,例如位图。原因是图片框仅以数组格式存储像素数据,如果不转换为图像类型,GDI/GDI+ 不能直接使用。 bitamp、jpeg、png 等。

    如果您通过 自定义用户控件 和正确处理 PaintEventArgs OnPaint 实现和/或使用相关的图形屏幕缓冲区上下文场景。

    对于那些只想知道缺少什么的人:

        private void button1_Click(Object sender, EventArgs e)
        {
            Pen selPen = new Pen(Color.Red, 2);  //  The Op uses random color which is not good idea for testing so we'll choose a solid color not on the existing bitmap and we'll confine our Pen's line size to 2 until we know what we're doing.
    
            //  Unfortionately the picture box "image" once loaded is not directly usable afterwords.
    
            //  We need tp recreate the pictureBox1 image to a usable form, being the "newBmp", and for efficiency the bitmap type is chosen
            Bitmap newBmp = new Bitmap(pictureBox1.Width, pictureBox1.Height, PixelFormat.Format32bppArgb); // Tip: Using System.Drawing.Imaging for pixel format which uses same pixel format as screen for speed
    
            // We create the graphics from our new and empty bitmap container
            Graphics g = Graphics.FromImage(newBmp);
    
            // Next we draw the pictureBox1 data array to our equivelent sized bitmap container
            g.DrawImage(pictureBox1.Image, 0, 0);
    
            g.DrawLine(selPen, 3, 3, 3, 133);  // Format: (pen, x1, y1, x2, y2)
            pictureBox1.Image = newBmp;
    
            //  Don't forget to dispose of no longer needed resources
            g.Dispose();
            selPen.Dispose();
            newBmp.Dispose(); // or save newBmp to file before dispose ie. newBmp.Save("yourfilepath", ImageFormat.Jpeg) or in whatever image type you disire;
        }
    

    到目前为止,Op 的代码只在位图表面画一条线,如果我们要“看到”这种变化,我们必须将 位图保存到文件 以便稍后在图像查看器中查看,或者我们必须将更新后的位图绘制到我们的显示监视器屏幕

    有几种方法可以绘制到显示器的屏幕上。可以使用的最常见的图形上下文是 Control.CreateGraghics、来自 (PaintEventArgs) 的图形到屏幕方法和/或通过使用有时称为并用作手动双缓冲图形上下文,其中全部通过图形中的DrawImage方法实现。

    在本例中,基于 Op 自己的代码,最简单的解决方案是使用 pictureBox1 控件显示这个新更新的位图。我们将简单地使用新更新的位图更新控件的图像,当然,一旦第一次转换为使用图形图像,如上面的代码描述中所示。

    编码愉快!

    【讨论】:

    • Unfortionately the picture box "image" once loaded is not directly usable afterwords. 假。您也不会处置以前的现有图像。
    • 这个聚会有点晚了。 #1。 op的问题涉及使用图片框。我的回答演示了如何对图片框数据进行装箱和拆箱。换句话说,如何操作图片数据然后将其发送回图片框进行显示,因为这是操作选择使用#2 的控件。我很想看到任何建议在不再需要/需要图形对象时不要处置图形对象的地方——我认为这就是 cmets 在处置前明确声明要额外保存的内容,但您是否注意到处置的建议?啊,反正没人读这些东西——编码愉快!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-25
    • 1970-01-01
    • 2013-05-01
    相关资源
    最近更新 更多