简体   繁体   中英

Get what's drawn on panel to bitmap

I have two windows forms in my application. On the main form I'm clicking a button and opening the second window with a panel. In that form on the panel I draw things and I'm reading it to a picture box.

This is the coding of my main form.

        Bitmap retBmp;
        FrmDrawing frmDrawing = new FrmDrawing();
        var result = frmDrawing.ShowDialog();

        if (result == DialogResult.OK)
        {
            retBmp = frmDrawing.bmpNew;
            pbDesign.Image = retBmp;
        }

This is how I draw on my second form.

public FrmDrawing()
        {
            InitializeComponent();
            g = pnlDraw.CreateGraphics();
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            pen = new Pen(Color.Black, 5);
            pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;
        }

        private void pbRed_Click(object sender, EventArgs e)
        {
            PictureBox p = (PictureBox)sender;
            pen.Color = p.BackColor;
        }

        private void pnlDraw_MouseDown(object sender, MouseEventArgs e)
        {
            moving = true;
            x = e.X;
            y = e.Y;
            pnlDraw.Cursor = Cursors.Cross;
        }

        private void pnlDraw_MouseMove(object sender, MouseEventArgs e)
        {
            if (moving && x!=-1 && y!=-1 )
            {
                g.DrawLine(pen, new Point(x, y), e.Location);
                x = e.X;
                y = e.Y;
            }
        }

        private void pnlDraw_MouseUp(object sender, MouseEventArgs e)
        {
            moving = false;
            x = -1;
            y = -1;
            pnlDraw.Cursor = Cursors.Default;

        }

        private void btnClear_Click(object sender, EventArgs e)
        {

            g.Clear(Color.White);
            pnlDraw.Invalidate();
        }

        private void btnAccept_Click(object sender, EventArgs e)
        {              

            bmpNew = new Bitmap(pnlDraw.Width, pnlDraw.Height);

            this.pnlDraw.DrawToBitmap(bmpNew, new Rectangle(0, 0, this.pnlDraw.Width, this.pnlDraw.Height));
            this.DialogResult = DialogResult.OK;
            this.Close();    
        }

In the second form I read what's drawn on to the panel to a bmp and I pass it to the form on button click. This code works almost fine except the fact that it passes just the panel not what is drawn on that. If I place another two colored picture box controls on the panel I draw, the image being displayed comes with those colored picture boxes, but not with what I draw on the panel. What I'm doing wrong here when reading what I drew on panel to bitmap? Or what should be corrected in order to get what I draw on the panel to the bitmap.

First of all, as you can read on MSDN :

The Graphics object that you retrieve through the CreateGraphics method should not normally be retained after the current Windows message has been processed, because anything painted with that object will be erased with the next WM_PAINT message. Therefore you cannot cache the Graphics object for reuse, except to use non-visual methods like Graphics.MeasureString . Instead, you must call CreateGraphics every time that you want to use the Graphics object, and then call Dispose when you are finished using it.

(emphasis mine)

So you shouldn't create the Graphics object in the form constructor, you should dynamically create and dispose it in the event handler.

But that won't help you anyway. Try to move your form off-screen and back and you notice, that all your custom drawings disappear. This is because you're not retaining them - they are only rendered one-time.

Instead of using a panel, use a PictureBox and draw the lines directly on its Bitmap .

pnlDraw is now a PictureBox , not a Panel :

public FrmDrawing()
{
  InitializeComponent();
  pnlDraw.Image = new Bitmap(pnlDraw.Width, pnlDraw.Height);
}

private void pnlDraw_MouseMove(object sender, MouseEventArgs e)
{
    if (moving && x!=-1 && y!=-1 )
    {
        // Create Graphics object dynamically
        using (var g = Graphics.FromImage(pnlDraw.Image))
        {
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            using (var pen = new Pen(Color.Black, 5))
            {
                pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;

                g.DrawLine(pen, new Point(x, y), e.Location);  
            }
        }

        // This is necessary; otherwise, we won't see the changes until
        // the picture box is repainted by the OS
        pnlDraw.Invalidate();

        x = e.X;
        y = e.Y;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM