|
-
Aug 25th, 2009, 04:58 PM
#1
Thread Starter
New Member
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:
Public Class Form1 Private Sub LoadImage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LoadImage.Click With OpenFileDialog1 '.InitialDirectory = "C:\" .Filter = "All Files|*.*|Bitmaps|*.bmp|GIFs|*.gif|JPEGs|*.jpg" .FilterIndex = 4 End With If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then PictureBox1.Image = Image.FromFile(OpenFileDialog1.FileName) PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage PictureBox1.BorderStyle = BorderStyle.Fixed3D End If End Sub Private Sub SaveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveButton.Click With SaveFileDialog1 .InitialDirectory = Environment.SpecialFolder.Desktop .Title = "Save As image file" .Filter = "Portable Network Graphics (JPG/JPEG Format (*.JPG)|*.JPG|All files (*.*)|*.*" .FilterIndex = 1 If .ShowDialog() = DialogResult.OK Then PictureBox1.Image.Save(.FileName) End If End With End Sub Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click Dim p As New System.Drawing.Pen(Color.Red, 1) Dim g As System.Drawing.Graphics Dim x As Integer Dim y As Integer x = MousePosition.X y = MousePosition.Y MousePosition.Offset(250, 600) If crsrO.Checked Then g = PictureBox1.CreateGraphics g.DrawEllipse(p, x, y, 3, 3) ElseIf crsrsq.Checked Then g = PictureBox1.CreateGraphics g.DrawRectangle(p, x, y, 3, 3) End If End Sub
Last edited by Robbyod; Aug 25th, 2009 at 06:11 PM.
-
Aug 25th, 2009, 05:24 PM
#2
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:
Using g As Graphics = PictureBox1.CreateGraphics ... 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:
Private Rectangles As New List(Of Rectangle) Private Sub PictureBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown Rectangles.Add(New Rectangle(e.X - 5, e.Y - 5, 10, 10)) PictureBox1.Invalidate() End Sub Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint For Each r As Rectangle In Me.Rectangles e.Graphics.FillRectangle(Brushes.Black, r) Next 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:
'List holding all our rectangles to paint Private Rectangles As New List(Of Rectangle) '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 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_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown 'Add a new Rectangle and repaint the Picturebox Rectangles.Add(New Rectangle(e.X - 5, e.Y - 5, 10, 10)) PictureBox1.Invalidate() End Sub Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint 'Use a loop to draw all rectangles For Each r As Rectangle In Me.Rectangles e.Graphics.FillRectangle(Brushes.Black, r) Next 'Update the bmp object so we can save it PictureBox1.DrawToBitmap(bmp, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height)) End Sub
-
Aug 25th, 2009, 07:21 PM
#3
Thread Starter
New Member
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:
'Load image PictureBox1.ImageLocation = ofd.FileName PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage 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:
Private Rectangles As New List(Of Rectangle) Private elipses As New List(Of elipses)
and that just illustrates my complete lack of mastery of VB.
I also tried
vb.net Code:
'Use a loop to draw all rectangles If crsrO.Checked Then For Each r As Rectangle In Me.Rectangles e.Graphics.FillRectangle(Brushes.Red, r) Next ElseIf crsrX.Checked Then For Each r As Rectangle In Me.Rectangles e.Graphics.FillRectangle(Brushes.Black, r) Next ElseIf crsrsq.Checked Then For Each r As Rectangle In Me.Rectangles e.Graphics.FillRectangle(Brushes.Blue, r) Next 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.
-
Aug 26th, 2009, 04:15 AM
#4
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:
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 End Class
Now, instead of creating a List(Of Rectangle), you create a List(Of DrawObject).
vb.net Code:
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:
Dim drawObj As DrawObject = New DrawObject() drawObj.Bounds = New Rectangle(e.X - 5, e.Y - 5, 10, 10) 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()
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:
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
Now, in the Paint event, all you do is call this method several times in a loop:
vb.net Code:
For Each drawObj As DrawObject In Me.drawObjects drawObj.Draw(e.Graphics) Next
Hope it helps. I also hope you try to understand what I wrote instead of just copy/pasting it
-
Aug 26th, 2009, 05:07 PM
#5
Thread Starter
New Member
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:
Public Class Form1
'List holding all our rectangles to paint
Private Rectangles 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
Dim drawObj As DrawObject = New DrawObject()
drawObj.Bounds = New Rectangle(e.X - 3, e.Y - 3, 5, 5)
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
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.
-
Aug 27th, 2009, 06:41 AM
#6
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:
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 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.
-
Aug 27th, 2009, 06:31 PM
#7
Thread Starter
New Member
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:
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
Dim drawObj As DrawObject = New DrawObject()
drawObj.Bounds = New DrawObject(e.X - 3, e.Y - 3, 5, 5)
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
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
End Sub
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
End Class
End Class
Once again thank you for your patience in teaching the programming ignorant
-
Aug 28th, 2009, 01:39 AM
#8
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).
-
Aug 28th, 2009, 01:53 PM
#9
Thread Starter
New Member
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:
'Mouse down event triggers the sub Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown 'Define drawobj as a new instance of the class/sub "drawobject" with () for input of mouse coords Dim drawObj As DrawObject = New DrawObject() 'set size/location property of the new object as mouse coord x -3, y - 3, & height 5, width 5 drawObj.Bounds = New DrawObject(e.X - 3, e.Y - 3, 5, 5) 'then conditions for the radio buttons 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 'dont get this bit, but i think it might be adding the object just drawn to the pic box, drawobjects.Add(drawObj) 'this as you said redraws it immediately so we can see it straight away PictureBox1.Invalidate() End Sub 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?
-
Aug 28th, 2009, 02:22 PM
#10
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.
-
Aug 28th, 2009, 02:42 PM
#11
Thread Starter
New Member
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.
-
Aug 28th, 2009, 02:53 PM
#12
Re: Drawing shapes onto a pic box and saving the modified image
Can you post your entire code? Please post it in [code][/code] tags so I can copy it and try it
-
Aug 28th, 2009, 03:35 PM
#13
Thread Starter
New Member
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
-
Aug 28th, 2009, 03:44 PM
#14
Thread Starter
New Member
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
-
Aug 28th, 2009, 03:48 PM
#15
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)
-
Aug 28th, 2009, 04:04 PM
#16
Thread Starter
New Member
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
-
Aug 28th, 2009, 04:46 PM
#17
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.
-
Sep 1st, 2009, 11:14 AM
#18
Thread Starter
New Member
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:
'Draw cross with brush 'b', and rectangle 'Me.Bounds'
So, i have tried
, didnt work for obvious reasons
then this
vb.net Code:
g.DrawLine(b, e.x - 2, e.y - 2, e.x + 2 e.y + 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:
ByVal e As System.Windows.Forms.MouseEventArgs)
from the mouse down event and tried the following
vb.net Code:
Public Sub Draw(ByVal g As Graphics, ByVal e As System.Windows.Forms.MouseEventArgs)
Using b As New SolidBrush(Me.Color)
If Me.Shape = Shapes.Cross Then
'Draw cross with brush 'b', and rectangle 'Me.Bounds'
g.DrawLine(b, e.x - 2, e.y - 2, e.x + 2 e.y + 2)
g.DrawLine(b, e.x + 2, e.y - 2, e.x - 2 e.y + 2)
Else
g.FillEllipse(b, Me.Bounds)
End If
End Using
which did not work either
So i think ill just open up a new thread
-
Sep 1st, 2009, 12:10 PM
#19
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|