user1464962
user1464962

Reputation: 173

Drawing in Winforms

I have written this code, however, it doesn't work. Not only will this not work, but none of the methods I have tried for drawing have worked. I've spent more than an hour or two trying to solve this, but to no success. Ive tried simple programs where all it does is display a small line, but it wont work no matter what i do :c

What am I doing wrong, or what could cause this?

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

Upvotes: 1

Views: 4786

Answers (4)

Jamie
Jamie

Reputation: 25

This is an old question and if anyone else has a similar problem. See below. First let's examine the Ops code.

(1) See code: The first recommended change is to keep the Pen's format simple until we have a better understanding about how the Pen actually works when drawing to graphics. Look at the Op's line where we create graphics from image which is a perfectly good example of how to directly draw ("which means to write") to the supplied bitmap by use of the bitmap's graphics context. Next, the Op provides an excellent example of the Graphics DrawLine method which can draw the defined line to the supplied bitmap.

(2) Due to missing details we have to make the following assumptions about the Op's supplied bitmap and about their method for drawing a line to the bitmap. Assuming there already exists an image inside this pictureBox1; if an image is not set the graphics we get from image will be from a null image or that each pixel will be black just as a footnote:

(a) Is the Pen's color unique to the existing bitmap and is the alpha component of the color high enough to actually see the resultant color when it's drawn (when in doubt use a unique solid color or at least set the alpha channel to 255)?

(b) This line the Op wants to draw is starting Left 3, Top 3 to Left 133 and that is 3-pixels to the right of bitmap's left side where this line has a height of 133 and as such the Pen's line size was changed to a width = 3 for demonstration purposes.

(c) The final consideration, is the pictureBox1.Size sufficient for us to see this drawn line? The line's geometry forms a rectangle similar to this RectangleF(3, 3, 3, 133) structure, so if the pictureBox1 Bounds rectangle intersects with the derived line's rectangle then the area of that intersection is where the line could be drawn and considered visible.

Before we can draw to the pictureBox1 image from graphics we must first convert the pictureBox1 image data back to a usable image type like a bitmap for example. The reason is the picture box stores only pixel data in array format and is not directly usable by GDI/GDI+ without conversion to an image type ie. bitamp, jpeg, png etc..

One can avoid this messy conversion if you handle you own painting by the way of a custom user control and by properly handling the PaintEventArgs OnPaint implementation and/or by using related graphics screen buffer context scenarios.

For those who just want the answer about what's missing:

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

The Op's code so far only draws a line to the bitmap's surface next if we are to "see" this change we must either save bitmap to file to be viewed later in an image viewer or we must draw the updated bitmap to our display monitor, the screen.

There are several methods with which to draw to your monitor's screen. The most common graphics contexts one could use are Control.CreateGraghics, graphics to screen method from (PaintEventArgs) and/or by using a graphics screen buffer sometimes called and used as a manual double buffered graphics context in which all is implemented by the way of DrawImage method from graphics.

The simplest solution, in this case based upon the Op's own code, is to display this newly updated bitmap using the pictureBox1 control. We'll simply update the control's image with the newly updated bitmap of course once first converted to a usage graphics image as seen in the above code descriptions.

Happy coding!

Upvotes: 0

willnode
willnode

Reputation: 1527

You must draw it from image first. then attach it to 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;

Upvotes: 0

Samy Arous
Samy Arous

Reputation: 6814

This is not the right way to draw to a picture box:

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

Btw, this method will create a temporary image which is reseted when the control is invalidated. For a more persistent drawing, you need to listen to the Paint event of the picture box and draw your graphics there.

Upvotes: 1

Try adding a

pictureBox1.Invalidate();

call.

Upvotes: 5

Related Questions