0

The Problem

I have a simple form with 2 PictureBoxes

I allow the user to draw on PictureBox1 When I click a Button on the form I want to capture the image in PictureBox1 and store it in PictureBox2

The issue is that if I add the line: PictureBox2.Image = PictureBox1.Image Any updates to PictureBox1 are immediately reflected in PictureBox2 ?!?

I just want to capture the image in PictureBox1 at that moment in time so that I can use it to 'Undo'

Tech

It's a Windows Forms App in Visual Basic, .Net 4.7.2 using Visual Studio 2019 Preview

Code

Public Class Form1

    Dim drawMouseDown = False ' Set initial mouse state to not clicked
    Dim drawMyBrush As New Pen(Brushes.White, 20) 'Set up the Brush
    Public drawCanvas As New Bitmap(245, 352) 'Set up Bitmap Canvas

    Private Sub btn_Color_Yellow_Click(sender As Object, e As EventArgs) Handles btn_Color_Yellow.Click
        drawMyBrush.Brush = Brushes.Yellow
        drawMyBrush.Width = 20
    End Sub

    Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
        drawMouseDown = True
    End Sub

    Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
        drawMouseDown = False
    End Sub

    Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        Dim g As Graphics = Graphics.FromImage(drawCanvas)
        Static coord As New Point
        If drawMouseDown Then
            g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
            drawMyBrush.StartCap = Drawing2D.LineCap.Round
            drawMyBrush.EndCap = Drawing2D.LineCap.Round
            g.DrawLine(drawMyBrush, coord.X, coord.Y, e.X, e.Y)
            g.Dispose()
            PictureBox1.Image = drawCanvas
            Me.Refresh()
        End If
        coord = e.Location
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        PictureBox2.Image = PictureBox1.Image 'Why does this not just update the PicBox2 image once?!? (or only when the Button is clicked)
    End Sub

End Class

Expectation

When Button1 is clicked I expect PictureBox2 to contain the PictureBox1 image, when I continue to draw on PictureBox1 I do NOT expect it to keep updating PictureBox2 as the user is drawing on the other!

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
David Kuske
  • 11
  • 1
  • 2
  • 1
    Clone the Image instead of assigning a reference. This is a really awkward way of painting Graphics objects. Really, really slow, btw. You should use the Paint event of the PictureBox, draw the shapes you need to draw on its surface and if you want to save everything in a Bitmap, draw all the shapes in one go and then save the Bitmap to disc. – Jimi Jan 13 '19 at 11:50
  • 2
    You really should use [`Option Strict On`](https://stackoverflow.com/a/29985039/1115360) - it makes Visual Studio tell you where you have variable type mismatches and so on. – Andrew Morton Jan 13 '19 at 11:53
  • Similar question, same issue: https://stackoverflow.com/a/45043490/3740093 – Visual Vincent Jan 13 '19 at 12:00

2 Answers2

1

As you suspect, PictureBox2.Image = PictureBox1.Image makes the former a reference to the latter.

What you can do instead is clone the image:

PictureBox2.Image = DirectCast(PictureBox1.Image.Clone(), Image)
Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
  • Yes!! This solved the issue. Thank you! it's been driving me crazy – David Kuske Jan 13 '19 at 11:53
  • 1
    You're welcome :) Please do take note of [Jimi's comment](https://stackoverflow.com/questions/54168433/picturebox2-image-picturebox1-image-seems-to-be-linking-the-boxes-instead-of-c/54168584#comment95166092_54168433) and find out the "proper" way to do the drawing. – Andrew Morton Jan 13 '19 at 11:54
0

Because you are referencing the Image property of PictureBox2 to PictureBox1.Image. So when they both point to the same reference, any changes to either of the PictureBox's image property, will affect the other's.

In order to avoid his, make a new instance of Bitmap object based on the PictureBox1.Image and set it to PictureBox2.Image:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    PictureBox2.Image = New Bitmap(PictureBox1.Image)
End Sub
ajakblackgoat
  • 2,119
  • 1
  • 15
  • 10