0

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.

ChathurawinD
  • 756
  • 1
  • 13
  • 35
  • See the examples in [this post](https://stackoverflow.com/a/40575797/3110834) – Reza Aghaei Dec 06 '18 at 15:26
  • _g = pnlDraw.CreateGraphics();_ Never do this!! Draw in the Paint event and then uase DrawToBitmap! – TaW Dec 06 '18 at 22:57
  • @RezaAghaei I didn't get what you have done in the code, can you provide me an example relevant to this scenario? – ChathurawinD Dec 07 '18 at 03:25
  • @TaW Can you show a code example ? – ChathurawinD Dec 07 '18 at 03:32
  • For freehand drawing see [here](https://stackoverflow.com/questions/31988079/copying-free-hand-drawing-from-panel-in-visual-studio-2013/32112426?s=3|15.2739#32112426). For saving with DrawToBirMap see [here](https://stackoverflow.com/questions/25086374/how-can-i-capture-as-bitmap-only-what-a-picturebox-is-displaying-without-using/25086932?s=16|24.6335#25086932). For more on CreateGraphics see [here](https://stackoverflow.com/questions/35544789/drawtobitmap-returning-blank-image/35571419?s=1|69.2968#35571419) – TaW Dec 07 '18 at 04:37

1 Answers1

1

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;
    }
}
dymanoid
  • 14,771
  • 4
  • 36
  • 64
  • this doesnt help. I changed my controller to a picture box. and did the code modifications as you suggested. But this doesn't even draw anything on the picture box which the previous code did. Can you try to provide a more viable solution? – ChathurawinD Dec 07 '18 at 03:12
  • You need to call the `Invalidate` method to see the changes. This code is 100% working because I tested it in a simple WinForms app before posting. Note that I didn't include your original `MouseDown` and `MouseUp` event handlers. They are still needed, however. – dymanoid Dec 07 '18 at 10:17
  • Hey it worked for me but it draws on the existing image, what need I do to clear the original one and rotate about the same center? – Son of Man Dec 23 '21 at 17:47
  • @ChathurawinD you probably forgot to reassing the event handlers once you've changed the control. The event handlers are probably assigned on the designer file, and went "lost" once you remover the Panel control to replace it... Am I right? – Rafael Ravena Vicente Nov 01 '22 at 13:56