Results 1 to 19 of 19

Thread: Drawing shapes onto a pic box and saving the modified image

  1. #1

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Talking Drawing shapes onto a pic box and saving the modified image

    Hi all,
    The aim of my program is to load a picture into an pic box, then to be able to place multiple shapes on the picture in the pic box by clicking on the location where i want the shape. The type of shape will depend on the radio button which has been selected. Basically all i want is choice of X or O. (its not tic tac toe either!!)
    At the end of it all i want to be able to save the image WITH the shapes on it, doesnt matter what format its in (gif, jpg, bmp) as long as it has color and i can see the original image with the shapes included.

    I have made several attempts at this, and this is what i have so far. (I am brand new to VB and programming so i need all the help i can get)
    I have hit a wall with how far previous examples can get me.

    Thanks for your help
    Heres my code so far
    vb.net Code:
    1. Public Class Form1
    2.  
    3.     Private Sub LoadImage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LoadImage.Click
    4.         With OpenFileDialog1
    5.             '.InitialDirectory = "C:\"
    6.             .Filter = "All Files|*.*|Bitmaps|*.bmp|GIFs|*.gif|JPEGs|*.jpg"
    7.             .FilterIndex = 4
    8.         End With
    9.  
    10.         If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
    11.             PictureBox1.Image = Image.FromFile(OpenFileDialog1.FileName)
    12.             PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
    13.             PictureBox1.BorderStyle = BorderStyle.Fixed3D
    14.         End If
    15.  
    16.     End Sub
    17.  
    18.     Private Sub SaveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveButton.Click
    19.         With SaveFileDialog1
    20.             .InitialDirectory = Environment.SpecialFolder.Desktop
    21.             .Title = "Save As image file"
    22.             .Filter = "Portable Network Graphics (JPG/JPEG Format (*.JPG)|*.JPG|All files (*.*)|*.*"
    23.             .FilterIndex = 1
    24.             If .ShowDialog() = DialogResult.OK Then
    25.                 PictureBox1.Image.Save(.FileName)
    26.             End If
    27.         End With
    28.     End Sub
    29.  
    30.     Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
    31.         Dim p As New System.Drawing.Pen(Color.Red, 1)
    32.         Dim g As System.Drawing.Graphics
    33.         Dim x As Integer
    34.         Dim y As Integer
    35.         x = MousePosition.X
    36.         y = MousePosition.Y
    37.         MousePosition.Offset(250, 600)
    38.         If crsrO.Checked Then
    39.             g = PictureBox1.CreateGraphics
    40.             g.DrawEllipse(p, x, y, 3, 3)
    41.         ElseIf crsrsq.Checked Then
    42.             g = PictureBox1.CreateGraphics
    43.             g.DrawRectangle(p, x, y, 3, 3)
    44.         End If
    45.     End Sub
    Last edited by Robbyod; Aug 25th, 2009 at 06:11 PM.

  2. #2
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Drawing shapes onto a pic box and saving the modified image

    A few things first:
    In case you post some code here, use either [code](code here)[/code] tags, or [highlight=vb.net](code here)[/highlight] tags. That way, the indenting will be visible, and if you use the second way the syntax highlighting will too (more or less).

    Secondly, if you are creating a Graphics object (CreateGraphics), you should also Dispose it after you are done with it. Even better, you should use it in a Using block. That way it will be disposed automatically:
    vb.net Code:
    1. Using g As Graphics = PictureBox1.CreateGraphics
    2.    ...
    3. End Using
    It is also not required to create a new graphics object in most cases, since the Picturebox's Paint event will provide that for you.


    Now, if you use the Paint event, there is one problem: it will get run very often, and it will repaint the entire PictureBox, which will get rid of all your previously created objects. To make sure all your objects are painted, you can store them in a List(Of ...).

    Let's say you want to draw Rectangles, then you create a (global) List(Of Rectangle), and Add a new Rectangle to that list when you click the PictureBox.
    In the Paint event, you loop through that List, and draw all the rectangles:
    vb.net Code:
    1. Private Rectangles As New List(Of Rectangle)
    2.  
    3.     Private Sub PictureBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    4.         Rectangles.Add(New Rectangle(e.X - 5, e.Y - 5, 10, 10))
    5.         PictureBox1.Invalidate()
    6.     End Sub
    7.  
    8.     Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    9.         For Each r As Rectangle In Me.Rectangles
    10.             e.Graphics.FillRectangle(Brushes.Black, r)
    11.         Next        
    12.     End Sub
    The Invalidate after adding a rectangle makes the PictureBox redraw itself, so that our new rectangle becomes visible immediately.

    For storing the picture, I think there are various ways. You can create a bitmap object (again global) and store the image in that every time the picturebox is painted. In the Save function, you simply save that bitmap.
    You will have to create a New Bitmap with the correct size in the Form_Load or the constructor (Public Sub New) for that to work though.

    Here's what my code looks like, it seems to work:
    vb.net Code:
    1. 'List holding all our rectangles to paint
    2.     Private Rectangles As New List(Of Rectangle)
    3.  
    4.     'Bitmap holding our final image (updated each Paint event)
    5.     Private bmp As Bitmap = Nothing
    6.  
    7.     'Constructor:
    8.     Public Sub New()
    9.  
    10.         ' This call is required by the Windows Form Designer.
    11.         InitializeComponent()
    12.  
    13.         ' Add any initialization after the InitializeComponent() call.
    14.  
    15.         'Create a new Bitmap object so we can use it
    16.         bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
    17.     End Sub
    18.  
    19.     Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoad.Click
    20.         Using ofd As New OpenFileDialog
    21.             If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
    22.                 'Load image
    23.                 PictureBox1.ImageLocation = ofd.FileName
    24.             End If
    25.         End Using
    26.     End Sub
    27.  
    28.     Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
    29.         Using sfd As New SaveFileDialog With {.Filter = "JPG Files (*.jpg)|*.jpg"}
    30.             If sfd.ShowDialog = Windows.Forms.DialogResult.OK Then
    31.                  'Save image
    32.                  bmp.Save(sfd.FileName)
    33.             End If
    34.         End Using
    35.     End Sub
    36.  
    37.     Private Sub PictureBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    38.         'Add a new Rectangle and repaint the Picturebox
    39.         Rectangles.Add(New Rectangle(e.X - 5, e.Y - 5, 10, 10))
    40.         PictureBox1.Invalidate()
    41.     End Sub
    42.  
    43.     Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    44.         'Use a loop to draw all rectangles
    45.         For Each r As Rectangle In Me.Rectangles
    46.             e.Graphics.FillRectangle(Brushes.Black, r)
    47.         Next
    48.  
    49.         'Update the bmp object so we can save it
    50.         PictureBox1.DrawToBitmap(bmp, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
    51.     End Sub

  3. #3

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    Ok, first of all, fantastic reply, thank you very much
    Code worked perfectly. I made a little change to stretch the image into the pic box
    vb.net Code:
    1. 'Load image
    2.  
    3.                 PictureBox1.ImageLocation = ofd.FileName
    4.                 PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
    5.                 PictureBox1.BorderStyle = BorderStyle.Fixed3D

    Also i need to be able to select a different type of shape or letter to put on the picture depending on which radio button i have selected. preferably X or if need be an elipse.
    I have tried tinkering with your code but its too far over my head.
    vb.net Code:
    1. Private Rectangles As New List(Of Rectangle)
    2. Private elipses As New List(Of elipses)
    and that just illustrates my complete lack of mastery of VB.
    I also tried
    vb.net Code:
    1. 'Use a loop to draw all rectangles
    2.         If crsrO.Checked Then
    3.             For Each r As Rectangle In Me.Rectangles
    4.  
    5.                 e.Graphics.FillRectangle(Brushes.Red, r)
    6.  
    7.             Next
    8.         ElseIf crsrX.Checked Then
    9.             For Each r As Rectangle In Me.Rectangles
    10.  
    11.                 e.Graphics.FillRectangle(Brushes.Black, r)
    12.  
    13.             Next
    14.         ElseIf crsrsq.Checked Then
    15.             For Each r As Rectangle In Me.Rectangles
    16.  
    17.                 e.Graphics.FillRectangle(Brushes.Blue, r)
    18.  
    19.             Next
    20.         End If
    I thought that by doing this i would at least get some different coloured markers but unfortunately thay all change once a new colour is selected.

    Can you help me with the code to get multiple types of markers depending on the radio buttons?

    Once again, thanks a lot for your help.

  4. #4
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Drawing shapes onto a pic box and saving the modified image

    What you need is a class that holds that information for you: the shape, the color, and possibly more. I don't think such a class exists readily, so we can make one ourselves.
    This will also teach you an important lesson, as classes are very important in VB.NET.

    The class we will create will hold at least three properties, the Bounds, the Shape, and the Color. Because you only seem to use two shapes, the easiest way to make the Shape property is to make a Shapes enumeration, and simply check for the value of that enumeration before you start to draw. The enumeration holds just two values: Ellipse and Cross.

    The code for your class could look like this:
    vb.net Code:
    1. Public Class DrawObject
    2.  
    3.     Public Enum Shapes
    4.         Ellipse = 0
    5.         Cross = 1
    6.     End Enum
    7.  
    8.     Public Sub New()
    9.         Me.Color = Drawing.Color.Black
    10.         Me.Shape = Shapes.Ellipse
    11.         Me.Bounds = Rectangle.Empty
    12.     End Sub
    13.  
    14.     Public Sub New(ByVal clr As Color, ByVal s As Shapes, ByVal bounds As Rectangle)
    15.         Me.Color = clr
    16.         Me.Shape = s
    17.         Me.Bounds = bounds
    18.     End Sub
    19.  
    20.     Private _Color As Color
    21.     Public Property Color() As Color
    22.         Get
    23.             Return _Color
    24.         End Get
    25.         Set(ByVal value As Color)
    26.             _Color = value
    27.         End Set
    28.     End Property
    29.  
    30.     Private _Shape As Shapes
    31.     Public Property Shape() As Shapes
    32.         Get
    33.             Return _Shape
    34.         End Get
    35.         Set(ByVal value As Shapes)
    36.             _Shape = value
    37.         End Set
    38.     End Property
    39.  
    40.     Private _Bounds As Rectangle
    41.     Public Property Bounds() As Rectangle
    42.         Get
    43.             Return _Bounds
    44.         End Get
    45.         Set(ByVal value As Rectangle)
    46.             _Bounds = value
    47.         End Set
    48.     End Property
    49.  
    50. End Class

    Now, instead of creating a List(Of Rectangle), you create a List(Of DrawObject).
    vb.net Code:
    1. Dim drawObjects As New List(Of DrawObject)

    Instead of creating a new Rectangle, you create a New DrawObject, and set the values you want, for example
    vb.net Code:
    1. Dim drawObj As DrawObject = New DrawObject()
    2. drawObj.Bounds = New Rectangle(e.X - 5, e.Y - 5, 10, 10)
    3. If crsrO.Checked Then
    4.    drawObj.Shape = DrawObject.Shapes.Cross
    5.    drawObj.Color = Color.Blue
    6. Else
    7.    drawObj.Shape = DrawObject.Shapes.Ellipse
    8.    drawObj.Color = Color.Red
    9. End If
    10.  
    11. drawObjects.Add(drawObj)
    12. PictureBox1.Invalidate()


    Then, in the Paint event, you simply check the shape and color of the DrawObject, and draw it appropriately.

    An even easier way perhaps is to put the drawing in the class itself! Create a new method in your DrawObject class that takes a Graphics object as a parameter. You can then draw using that Graphics object, and check the Shape and Color of the current instance of the class. I use another Using block to create a brush to make sure it is disposed. You don't want to dispose the Graphics object, because we will be passing the picturebox's Graphics object to it, and you don't dispose that because the pb still needs it.
    vb.net Code:
    1. Public Sub Draw(ByVal g As Graphics)
    2.         Using b As New SolidBrush(Me.Color)
    3.             If Me.Shape = Shapes.Cross Then
    4.                 'Draw cross with brush 'b', and rectangle 'Me.Bounds'
    5.             Else
    6.                 g.FillEllipse(b, Me.Bounds)
    7.             End If
    8.         End Using
    9.     End Sub

    Now, in the Paint event, all you do is call this method several times in a loop:
    vb.net Code:
    1. For Each drawObj As DrawObject In Me.drawObjects
    2.    drawObj.Draw(e.Graphics)
    3. Next


    Hope it helps. I also hope you try to understand what I wrote instead of just copy/pasting it

  5. #5

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    Ok, after struggling to figure out where to put your code (And struggling to understand it) this is what i came up with.
    Its giving me 3 errors though which i cant get rid of
    vb.net Code:
    1. Public Class Form1
    2.     'List holding all our rectangles to paint
    3.     Private Rectangles As New List(Of DrawObject)
    4.  
    5.     'Bitmap holding our final image (updated each Paint event)
    6.     Private bmp As Bitmap = Nothing
    7.  
    8.     'Constructor:
    9.     Public Sub New()
    10.  
    11.         ' This call is required by the Windows Form Designer.
    12.         InitializeComponent()
    13.  
    14.         ' Add any initialization after the InitializeComponent() call.
    15.  
    16.         'Create a new Bitmap object so we can use it
    17.         bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
    18.     End Sub
    19.  
    20.     Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnload.Click
    21.         Using ofd As New OpenFileDialog
    22.             If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
    23.                 'Load image
    24.                 PictureBox1.ImageLocation = ofd.FileName
    25.                 PictureBox1.ImageLocation = ofd.FileName
    26.                 PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
    27.                 PictureBox1.BorderStyle = BorderStyle.Fixed3D
    28.             End If
    29.         End Using
    30.     End Sub
    31.  
    32.     Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnsave.Click
    33.         Using sfd As New SaveFileDialog With {.Filter = "JPG Files (*.jpg)|*.jpg"}
    34.             If sfd.ShowDialog = Windows.Forms.DialogResult.OK Then
    35.                 'Save image
    36.                 bmp.Save(sfd.FileName)
    37.             End If
    38.         End Using
    39.     End Sub
    40.  
    41.     Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    42.         Dim drawObj As DrawObject = New DrawObject()
    43.         drawObj.Bounds = New Rectangle(e.X - 3, e.Y - 3, 5, 5)
    44.         If crsrO.Checked Then
    45.             drawObj.Shape = DrawObject.Shapes.Cross
    46.             drawObj.Color = Color.Blue
    47.         Else
    48.             drawObj.Shape = DrawObject.Shapes.Ellipse
    49.             drawObj.Color = Color.Red
    50.         End If
    51.  
    52.         drawObjects.Add(drawObj)
    53.         PictureBox1.Invalidate()
    54.  
    55.     End Sub
    56.  
    57. End Class
    58. Public Class DrawObject
    59.  
    60.     Public Enum Shapes
    61.         Ellipse = 0
    62.         Cross = 1
    63.     End Enum
    64.  
    65.     Public Sub New()
    66.         Me.Color = Drawing.Color.Black
    67.         Me.Shape = Shapes.Ellipse
    68.         Me.Bounds = Rectangle.Empty
    69.     End Sub
    70.  
    71.     Public Sub New(ByVal clr As Color, ByVal s As Shapes, ByVal bounds As Rectangle)
    72.         Me.Color = clr
    73.         Me.Shape = s
    74.         Me.Bounds = bounds
    75.     End Sub
    76.  
    77.     Private _Color As Color
    78.     Public Property Color() As Color
    79.         Get
    80.             Return _Color
    81.         End Get
    82.         Set(ByVal value As Color)
    83.             _Color = value
    84.         End Set
    85.     End Property
    86.  
    87.     Private _Shape As Shapes
    88.     Public Property Shape() As Shapes
    89.         Get
    90.             Return _Shape
    91.         End Get
    92.         Set(ByVal value As Shapes)
    93.             _Shape = value
    94.         End Set
    95.     End Property
    96.  
    97.     Private _Bounds As Rectangle
    98.     Public Property Bounds() As Rectangle
    99.         Get
    100.             Return _Bounds
    101.         End Get
    102.         Set(ByVal value As Rectangle)
    103.             _Bounds = value
    104.         End Set
    105.     End Property
    106.  
    107. End Class
    These are the errors im getting
    all are in the paint event

    Error 1 'X' is not a member of 'System.Windows.Forms.PaintEventArgs'.

    Error 2 'Y' is not a member of 'System.Windows.Forms.PaintEventArgs'.

    Error 3 Name 'drawObjects' is not declared.

    tried reorganising things to make it work but it just isnt happening.

  6. #6
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Drawing shapes onto a pic box and saving the modified image

    You positioned a few things wrong indeed

    First of all, the place of the class is fine, sitting outside of the form's code, but I suggest you simply create a new Class file for it, and put it there. What you name that file doesn't really matter, I usually choose the name to match the class name (in this case DrawObject.vb). It won't change anything having it in a separate file, but it's just more logical, and easier to find.


    Secondly, what you have in the Paint event now should be in the MouseDown event of the PictureBox instead. What I'm doing there is creating a new instance of the DrawObject class, setting it's properties appropriately, and then adding it to the list of objects to draw.
    The actual drawing is what's done in the Paint event instead. For that, you need to add the last method i posted (Public Sub Draw) to your DrawObject class. Then in the Paint event, you just add the last piece of code:
    vb.net Code:
    1. Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    2.       For Each drawObj As DrawObject In Me.drawObjects
    3.          drawObj.Draw(e.Graphics)
    4.       Next
    5. End Sub
    Now it should call the Draw event (which paints the shape with the correct properties) for each individual DrawObject instance (the ones we created in the MouseDown event).

    This will solve errors 1 and 2.

    To solve error 3, you simply forgot to rename the Rectangles list to drawObjects (right at the top of your code). You can still call it Rectangles if you want, but that's not logical since the list doesn't contain Rectangles at all Either call it drawObjects everywhere, or call it Rectangles everywhere.

  7. #7

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    Ok, Im getting frustrated now. This code is making me feel like a complete idiot.
    I know i only started VB last week but i hate feeling helplessly stupid which is how i feel now. Goddamit!!!

    pause, relax, deep breath.....

    So i replaced the code in the paint event with what you suggested,
    I removed the code from the mouse down event and replaced it with what i had mistakenly put into the paint event
    I changed the code at the very start from rectangles to Drawobjects

    I didnt create a separate file for the class, mostly because im at breaking point and any more problems and ill crack up. (didnt want to tempt fate)

    Heres my code now but im still getting the same errors

    Error 1 'X' is not a member of 'System.EventArgs'.
    Error 2 'Y' is not a member of 'System.EventArgs'.
    Error 3 'Draw' is not a member of 'WindowsApplication1.Form1.DrawObject'.
    vb.net Code:
    1. Public Class Form1
    2.  
    3.  
    4.     'List holding all our rectangles to paint
    5.     Private drawobjects As New List(Of DrawObject)
    6.  
    7.     'Bitmap holding our final image (updated each Paint event)
    8.     Private bmp As Bitmap = Nothing
    9.  
    10.     'Constructor:
    11.     Public Sub New()
    12.  
    13.         ' This call is required by the Windows Form Designer.
    14.         InitializeComponent()
    15.  
    16.         ' Add any initialization after the InitializeComponent() call.
    17.  
    18.         'Create a new Bitmap object so we can use it
    19.         bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
    20.     End Sub
    21.  
    22.     Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnload.Click
    23.         Using ofd As New OpenFileDialog
    24.             If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
    25.                 'Load image
    26.                 PictureBox1.ImageLocation = ofd.FileName
    27.                 PictureBox1.ImageLocation = ofd.FileName
    28.                 PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
    29.                 PictureBox1.BorderStyle = BorderStyle.Fixed3D
    30.             End If
    31.         End Using
    32.     End Sub
    33.  
    34.     Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnsave.Click
    35.         Dim drawObj As DrawObject = New DrawObject()
    36.         drawObj.Bounds = New DrawObject(e.X - 3, e.Y - 3, 5, 5)
    37.         If crsrO.Checked Then
    38.             drawObj.Shape = DrawObject.Shapes.Cross
    39.             drawObj.Color = Color.Blue
    40.         Else
    41.             drawObj.Shape = DrawObject.Shapes.Ellipse
    42.             drawObj.Color = Color.Red
    43.         End If
    44.  
    45.         drawobjects.Add(drawObj)
    46.         PictureBox1.Invalidate()
    47.     End Sub
    48.  
    49.  
    50.     Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    51.  
    52.         For Each drawObj As DrawObject In Me.drawobjects
    53.  
    54.             drawObj.Draw(e.Graphics)
    55.  
    56.         Next
    57.  
    58.     End Sub
    59.  
    60.     Public Class DrawObject
    61.  
    62.         Public Enum Shapes
    63.             Ellipse = 0
    64.             Cross = 1
    65.         End Enum
    66.  
    67.         Public Sub New()
    68.             Me.Color = Drawing.Color.Black
    69.             Me.Shape = Shapes.Ellipse
    70.             Me.Bounds = Rectangle.Empty
    71.         End Sub
    72.  
    73.         Public Sub New(ByVal clr As Color, ByVal s As Shapes, ByVal bounds As Rectangle)
    74.             Me.Color = clr
    75.             Me.Shape = s
    76.             Me.Bounds = bounds
    77.         End Sub
    78.  
    79.         Private _Color As Color
    80.         Public Property Color() As Color
    81.             Get
    82.                 Return _Color
    83.             End Get
    84.             Set(ByVal value As Color)
    85.                 _Color = value
    86.             End Set
    87.         End Property
    88.  
    89.         Private _Shape As Shapes
    90.         Public Property Shape() As Shapes
    91.             Get
    92.                 Return _Shape
    93.             End Get
    94.             Set(ByVal value As Shapes)
    95.                 _Shape = value
    96.             End Set
    97.         End Property
    98.  
    99.         Private _Bounds As Rectangle
    100.         Public Property Bounds() As Rectangle
    101.             Get
    102.                 Return _Bounds
    103.             End Get
    104.             Set(ByVal value As Rectangle)
    105.                 _Bounds = value
    106.             End Set
    107.         End Property
    108.  
    109.     End Class
    110. End Class

    Once again thank you for your patience in teaching the programming ignorant

  8. #8
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Drawing shapes onto a pic box and saving the modified image

    Still not right

    Just look at the code. Read it, and try to understand what it does.

    Let's take it one step at a time.

    1. The bit what you have in the btnSave_Click event now.

    The first thing the code does is create a New DrawObject. An instance of the DrawObject (which you have just created) is one shape you are going to draw. It could be a red cross, or a blue ellipse, depending on the properties. These properties are set right after the DrawObject is created. The Bounds property is also set, which is just the position and size of the object to draw. The Bounds is set to a new Rectangle with a width and height of 10 pixels. The location of the rectangle is e.X - 5 and e.Y - 5. e.X and e.Y are supposed to be the x and y coordinates of the mouse click, assuming you place this code in the correct event!
    Then, in line 45 (in your last code), you Add the new DrawObject instance to the drawobjects List (collection). The idea is that the PictureBox paints each DrawObject in that list, but only in the Paint event, so we need to put it in the list to reference it later.
    Finally, the PictureBox is invalidated which means basically that it should repaint itself, otherwise it could take a while before the new DrawObject shows up (which is in the next Paint event).

    Now. Think about all that. Do you think that creating a new Drawobject at the mouse's location and adding it to the PictureBox is an appropriate action for the btnSave_Click event? I didn't think so
    You want this code to execute when the user clicks on the PictureBox. For that, you can use the PictureBox1_Click event, but that does not hold any information about the mouse click (it's location for example). For that reason I would choose the MouseDown event.


    2. 'Draw' is not a member of ...
    You still didn't add the Draw method I posted in post number 4 to your DrawObject class. Note that, as it is written now, it does not draw the cross yet, because I didn't implement that drawing yet. A cross isn't the easiest thing to draw (well it's not hard, but it requires a little calculation first), but if you need help with that I suggest to open a new thread about it as that's unrelated to this thread.

    Also, you are also missing the code to save the new image in the bmp Bitmap:
    Code:
    PictureBox1.DrawToBitmap(bmp, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
    That should go in the Paint event, right underneath the For Each loop.


    Finally, you will now have an empty btnSave_Click event, but I already gave you the code for that in post number 2


    You just need to take a look at the code and try to understand what it does. It won't be very hard in most cases, especially since VB is often just English if you look closely
    Then, after you figure out what it does, you can much more easily determine what goes where (in which event).

  9. #9

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    Ok, i thought the last two pieces of code in post 4 were for a different way of doing it. Misunderstanding. There in now, in the class. All the errors are gone apart from this one

    Error 1 Overload resolution failed because no accessible 'New' accepts this number of arguments.

    This is referring to line 11 of the code posted below.
    Ive added comments in so you can see how right/wrong i may be about what im doing

    vb.net Code:
    1. 'Mouse down event triggers the sub
    2.  
    3. Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    4.  
    5. 'Define drawobj as a new instance of the class/sub "drawobject" with () for input of mouse coords
    6.  
    7.         Dim drawObj As DrawObject = New DrawObject()
    8.  
    9. 'set size/location property of the new object as mouse coord x -3, y - 3, & height 5, width 5
    10.  
    11.         drawObj.Bounds = New DrawObject(e.X - 3, e.Y - 3, 5, 5)
    12.  
    13. 'then conditions for the radio buttons
    14.  
    15.         If crsrO.Checked Then
    16.             drawObj.Shape = DrawObject.Shapes.Cross
    17.             drawObj.Color = Color.Blue
    18.         Else
    19.             drawObj.Shape = DrawObject.Shapes.Ellipse
    20.             drawObj.Color = Color.Red
    21.         End If
    22.  
    23. 'dont get this bit, but i think it might be adding the object just drawn to the pic box,
    24.  
    25.         drawobjects.Add(drawObj)
    26.  
    27. 'this as you said redraws it immediately so we can see it straight away
    28.  
    29.         PictureBox1.Invalidate()
    30.     End Sub
    31. End Class

    how wrong am i?

    Now you said previously that all the rectangle references should be changed to drawobject, well there are "rectangle" reference still written down in a few places but i think it should be there.
    There is one instance of it in the picturebox_paint sub
    all the rest are in the class Drawobject which you created

    Should they all be there?

  10. #10
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Drawing shapes onto a pic box and saving the modified image

    Sorry, I should have explained clearer.

    In my very first example, I was drawing rectangles, using the FillRectangle function. Since all I was doing was drawing rectangles, I decided to call the collection 'Rectangles'.

    Now, we are no longer drawing rectangles, but rather an assortment of different shapes, so calling the collection 'Rectangles' is no longer very appropriate. I decided to call it DrawObjects instead (to reflect the class name DrawObject).

    That does not mean however that every reference to 'Rectangle' should be replaced by 'DrawObject'. The reason is that nearly all drawing functions (in the Graphics class) use a Rectangle object to define the place where to draw.

    The Rectangle structure in VB is simply an X, Y, Width and Height structure, defining a rectangle. The Graphics.DrawEllipse function (for example) takes a Rectangle as an argument to know where it should draw the ellipse, even though it's not drawing a rectangle at all. The ellipse is simply drawn within the bounds of the rectangle. Of course, Microsoft could have decided to create an Ellipse structure instead, which you would pass to the DrawEllipse function. You could specify the two (one in case of a circle) focal points of the ellipse, and it's orientation and radii (radius in case of a circle), and it's center point. That would work equally well, albeit a little more complicated. The problem is that that would only work for drawing an Ellipse, you cuold not use it properly to draw a Rectangle, or anything else.
    For that reason, we have the Rectangle structure, which is used almost universally in the drawing classes to define the boundaries of the drawing.

    That is the reason for the Bounds property in the DrawObject class: it merely defines the boundaries of the object to draw. In our case, it's an ellipse or a cross, but we still need a Rectangle structure to define the boundaries of the object to draw.



    In other (much shorter) words, all you need to do is replace the New DrawObject with New Rectangle (in line 11 only!). You already have a New DrawObject (line 7), and now we assign a Rectangle to its Bounds property so the instance knows where to draw its shape.

  11. #11

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    OK thanks for clearing that up,
    Now the program loads correctly, load and save work fine,
    but no matter what radio button i have selected, clicking on the picture does not produce an image.

  12. #12

  13. #13

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    Code:
    Public Class Form1
    
    
        'List holding all our rectangles to paint
        Private drawobjects As New List(Of DrawObject)
    
        'Bitmap holding our final image (updated each Paint event)
        Private bmp As Bitmap = Nothing
    
        'Constructor:
        Public Sub New()
    
            ' This call is required by the Windows Form Designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
    
            'Create a new Bitmap object so we can use it
            bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
        End Sub
    
        Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnload.Click
            Using ofd As New OpenFileDialog
                If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
                    'Load image
                    PictureBox1.ImageLocation = ofd.FileName
                    PictureBox1.ImageLocation = ofd.FileName
                    PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
                    PictureBox1.BorderStyle = BorderStyle.Fixed3D
                End If
            End Using
        End Sub
    
        Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnsave.Click
            Using sfd As New SaveFileDialog With {.Filter = "JPG Files (*.jpg)|*.jpg"}
                If sfd.ShowDialog = Windows.Forms.DialogResult.OK Then
                    'Save image
                    bmp.Save(sfd.FileName)
                End If
            End Using
        End Sub
    
        Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    
            For Each drawObj As DrawObject In Me.drawobjects
    
                drawObj.Draw(e.Graphics)
    
            Next
            PictureBox1.DrawToBitmap(bmp, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
        End Sub
        Private Sub PictureBox1_mousedown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    
            Dim drawObj As DrawObject = New DrawObject()
            drawObj.Bounds = New Rectangle()
            If crsrO.Checked Then
                drawObj.Shape = DrawObject.Shapes.Cross
                drawObj.Color = Color.Blue
            Else
                drawObj.Shape = DrawObject.Shapes.Ellipse
                drawObj.Color = Color.Red
            End If
            drawobjects.Add(drawObj)
            PictureBox1.Invalidate()
        End Sub
    End Class
    
    
    
        Public Class DrawObject
    
            Public Enum Shapes
                Ellipse = 0
                Cross = 1
            End Enum
    
            Public Sub New()
                Me.Color = Drawing.Color.Black
                Me.Shape = Shapes.Ellipse
                Me.Bounds = Rectangle.Empty
            End Sub
    
            Public Sub New(ByVal clr As Color, ByVal s As Shapes, ByVal bounds As Rectangle)
                Me.Color = clr
                Me.Shape = s
                Me.Bounds = bounds
            End Sub
    
            Private _Color As Color
            Public Property Color() As Color
                Get
                    Return _Color
                End Get
                Set(ByVal value As Color)
                _Color = value
            End Set
            End Property
    
            Private _Shape As Shapes
            Public Property Shape() As Shapes
                Get
                    Return _Shape
                End Get
                Set(ByVal value As Shapes)
                    _Shape = value
                End Set 
            End Property
    
            Private _Bounds As Rectangle
            Public Property Bounds() As Rectangle
                Get
                    Return _Bounds
                End Get
                Set(ByVal value As Rectangle)
                    _Bounds = value
                End Set
        End Property
    
        Public Sub Draw(ByVal g As Graphics)
    
            Using b As New SolidBrush(Me.Color)
    
                If Me.Shape = Shapes.Cross Then
    
                    'Draw cross with brush 'b', and rectangle 'Me.Bounds'
    
                Else
    
                    g.FillEllipse(b, Me.Bounds)
    
                End If
    
            End Using
    
        End Sub
    
        End Class

  14. #14

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    Code:
    Public Class Form1
    
    
        'List holding all our rectangles to paint
        Private drawobjects As New List(Of DrawObject)
    
        'Bitmap holding our final image (updated each Paint event)
        Private bmp As Bitmap = Nothing
    
        'Constructor:
        Public Sub New()
    
            ' This call is required by the Windows Form Designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
    
            'Create a new Bitmap object so we can use it
            bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
        End Sub
    
        Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnload.Click
            Using ofd As New OpenFileDialog
                If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
                    'Load image
                    PictureBox1.ImageLocation = ofd.FileName
                    PictureBox1.ImageLocation = ofd.FileName
                    PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
                    PictureBox1.BorderStyle = BorderStyle.Fixed3D
                End If
            End Using
        End Sub
    
        Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnsave.Click
            Using sfd As New SaveFileDialog With {.Filter = "JPG Files (*.jpg)|*.jpg"}
                If sfd.ShowDialog = Windows.Forms.DialogResult.OK Then
                    'Save image
                    bmp.Save(sfd.FileName)
                End If
            End Using
        End Sub
    
        Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    
            For Each drawObj As DrawObject In Me.drawobjects
    
                drawObj.Draw(e.Graphics)
    
            Next
            PictureBox1.DrawToBitmap(bmp, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
        End Sub
        Private Sub PictureBox1_mousedown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    
            Dim drawObj As DrawObject = New DrawObject()
            drawObj.Bounds = New Rectangle()
            If crsrO.Checked Then
                drawObj.Shape = DrawObject.Shapes.Cross
                drawObj.Color = Color.Blue
            Else
                drawObj.Shape = DrawObject.Shapes.Ellipse
                drawObj.Color = Color.Red
            End If
            drawobjects.Add(drawObj)
            PictureBox1.Invalidate()
        End Sub
    End Class
    
    
    
        Public Class DrawObject
    
            Public Enum Shapes
                Ellipse = 0
                Cross = 1
            End Enum
    
            Public Sub New()
                Me.Color = Drawing.Color.Black
                Me.Shape = Shapes.Ellipse
                Me.Bounds = Rectangle.Empty
            End Sub
    
            Public Sub New(ByVal clr As Color, ByVal s As Shapes, ByVal bounds As Rectangle)
                Me.Color = clr
                Me.Shape = s
                Me.Bounds = bounds
            End Sub
    
            Private _Color As Color
            Public Property Color() As Color
                Get
                    Return _Color
                End Get
                Set(ByVal value As Color)
                _Color = value
            End Set
            End Property
    
            Private _Shape As Shapes
            Public Property Shape() As Shapes
                Get
                    Return _Shape
                End Get
                Set(ByVal value As Shapes)
                    _Shape = value
                End Set 
            End Property
    
            Private _Bounds As Rectangle
            Public Property Bounds() As Rectangle
                Get
                    Return _Bounds
                End Get
                Set(ByVal value As Rectangle)
                    _Bounds = value
                End Set
        End Property
    
        Public Sub Draw(ByVal g As Graphics)
    
            Using b As New SolidBrush(Me.Color)
    
                If Me.Shape = Shapes.Cross Then
    
                    'Draw cross with brush 'b', and rectangle 'Me.Bounds'
    
                Else
    
                    g.FillEllipse(b, Me.Bounds)
    
                End If
    
            End Using
    
        End Sub
    
        End Class

  15. #15
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Drawing shapes onto a pic box and saving the modified image

    You create a New Rectangle, but you never set it's x, y, width and height! Now you simply have an empty rectangle (0,0,0,0). You can set in the constructor like I showed before:
    Code:
    drawObj.Bounds = New Rectangle(e.X - 5, e.Y - 5, 10, 10)
    Replace the 10, 10 with the width and height of your object to draw. Then replace e.X - 5 and e.Y - 5 by e.X - (half of width) and e.Y - (half of height), to center the object around the mouse click. For example, if you want to draw a shape of 20 width and 14 height, you would use
    Code:
    drawObj.Bounds = New Rectangle(e.X - 10, e.Y - 7, 20, 14)

  16. #16

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    working now. now i just need to get the cross drawing working. Ellipses i can do, change the colour and size etc. Thats for another thread.
    Thanks for your help and patience


  17. #17
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Drawing shapes onto a pic box and saving the modified image

    You might be amazed how little drawing things has to do with programming. It is mainly calculations and math (although it's not too bad on a cross).

    A cross is just two lines. You draw a line using the DrawLine function. You need to specify a Pen to use for drawing. You can change both the Color and Width of the Pen. To draw the line, you need to specify the start position (x1, y1) and the end position (x2, y2). The 'hardest' part is figuring out what those should be. Here's a diagram that should help. The red dots indicate the start and end position of the two lines. In the future, try to make a diagram like that and it will become clear in seconds. Don't do like me, and just try it, because you will spend ages trying to fix something that was inherently wrong



    If you still can't figure it out, then yes, it's probably best for a new thread.

    If you're thread is resolved, please mark it as resolved from the Thread Tools above your first post.

  18. #18

    Thread Starter
    New Member
    Join Date
    Aug 2009
    Posts
    12

    Re: Drawing shapes onto a pic box and saving the modified image

    Ok, i get the drawline function, specifying a pen and two points is fine, but how do i tie that in with the mouse coordinates,

    Also i assume you left this in the code so i knew where to put it, im putting it just below this line
    vb.net Code:
    1. 'Draw cross with brush 'b', and rectangle 'Me.Bounds'
    So, i have tried
    vb.net Code:
    1. g.Drawline(b, Me.Bounds)
    , didnt work for obvious reasons

    then this
    vb.net Code:
    1. g.DrawLine(b, e.x - 2, e.y - 2, e.x + 2 e.y + 2)
    2. g.DrawLine(b, e.x + 2, e.y - 2, e.x - 2 e.y + 2)
    which did not recognise "e" (which i assume is the curent location of the mouse) so i added this
    vb.net Code:
    1. ByVal e As System.Windows.Forms.MouseEventArgs)
    from the mouse down event and tried the following
    vb.net Code:
    1. Public Sub Draw(ByVal g As Graphics, ByVal e As System.Windows.Forms.MouseEventArgs)
    2.         Using b As New SolidBrush(Me.Color)
    3.             If Me.Shape = Shapes.Cross Then
    4.  
    5.                 'Draw cross with brush 'b', and rectangle 'Me.Bounds'
    6.                 g.DrawLine(b, e.x - 2, e.y - 2, e.x + 2 e.y + 2)
    7.                 g.DrawLine(b, e.x + 2, e.y - 2, e.x - 2 e.y + 2)
    8.             Else
    9.                 g.FillEllipse(b, Me.Bounds)
    10.             End If
    11.         End Using
    which did not work either

    So i think ill just open up a new thread

  19. #19
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Drawing shapes onto a pic box and saving the modified image

    You already know the location of the mouse click implicitly, from the Bounds property. We set the Bounds property to the be a rectangle centered around the mouse click. So, the center of the Bounds rectangle is the mouse click!

    However, you don't need the center at all. You just have to make sure that you draw your cross inside the Bounds rectangle, and since that rectangle is located at the mouse click, so will your cross.

    I'll give you one example, the top-right corner. Notice the blue triangle I edited into my last picture (couldn't use photoshop but had to use Paint, don't mind the quality lol).

    It has two sides a, and one side p/2, where p stands for the pen width.
    You will need the value a if you want to calculate the coordinates of the red point, because they will be:
    Code:
    x-coord: Bounds.X + Bounds.Width - a
    y-coord: Bounds.Y + a
    Now, the value a is easily found, because:
    a^2 + a^2 = (p/2)^2
    2a^2 = p^2/4
    a^2 = p^2/8
    a = p/sqrt(8)

    So, the coordinste of that point is:
    Code:
    Dim a As Double = penWidth / Math.Sqrt(8)
    Dim topRight As PointF = New PointF(Bounds.X + Bounds.Width - a, _
    				  Bounds.Y + a)
    Notice that I used a PointF rather than a Point structure. The PointF structure can use floating point values (Singles) rather than only Integers. I'm pretty sure the DrawLine method can use PointF values.

    Now, I think you can find the other 3 points too, no?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width