Question How to add a .gif image from ressources using GDI+?

NKN

Member
Joined
Dec 9, 2011
Messages
19
Programming Experience
Beginner
I want to load a .gif image with no background at the pointer's location on the form every time the user clicks on the form.
I tried using a picturebox but when two of this same image overlap the background of the picturebox covers the image behind..

How can i do this using GDI+ ?

Dim PB As New PictureBox
With PB
.Name = "Bullet"
.Image = bullet
.Size = New Size(42, 39)
.SizeMode = PictureBoxSizeMode.StretchImage
.BackColor = System.Drawing.Color.Transparent
.Location = New Point(Me.PointToClient(Cursor.Position).X - PB.Width / 2, Me.PointToClient(Cursor.Position).Y - PB.Height / 2)


End With


Me.Controls.Add(PB)
PB.BringToFront()
End If
 

IanRyder

Well-known member
Joined
Sep 9, 2012
Messages
1,130
Location
Healing, NE Lincs, UK
Programming Experience
10+
Hi,

The first thing to ensure is that your image supports and has a a transparent background, such as a PNG image. After adding your image to your project you can then use the following code to draw the image to the graphics pallet of the form:-

VB.NET:
Private Sub Form1_Click(sender As System.Object, e As System.EventArgs) Handles MyBase.Click
    Dim GP As Graphics = Me.CreateGraphics
    Dim myImage As New Bitmap(My.Resources.Bee, 42, 39)
    Dim CurrentPoint As New Point(CInt(Me.PointToClient(Cursor.Position).X - myImage.Width / 2), CInt(Me.PointToClient(Cursor.Position).Y - myImage.Height / 2))
 
    GP.DrawImage(myImage, CurrentPoint)
End Sub

Hope that helps.

Cheers,

Ian
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,589
Location
Norway
Programming Experience
10+
Do not use CreateGraphics to draw to a control surface, use the Paint event for that. You would need to record the locations where all images is to be drawn each event.
As alternative you can draw to a static image (Graphics.FromImage > Graphics.DrawImage) that for example a PictureBox control displays.
 

IanRyder

Well-known member
Joined
Sep 9, 2012
Messages
1,130
Location
Healing, NE Lincs, UK
Programming Experience
10+
Hi,

I suppose I was cutting corners a bit there and to be specific JohnH is correct. Here is another way to do it using the Paint event of the form:-

VB.NET:
Public Class Form1
  Private DoPaint As Boolean
 
  Private Sub Form1_Click(sender As System.Object, e As System.EventArgs) Handles MyBase.Click
    DoPaint = True
    Me.Invalidate()
  End Sub
 
  Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    Static myImagePoints As New List(Of Point)
    Dim myImage As New Bitmap(My.Resources.Bee, 42, 39)
 
    If DoPaint Then
      Dim CurrentPoint As New Point(CInt(Me.PointToClient(Cursor.Position).X - myImage.Width / 2), CInt(Me.PointToClient(Cursor.Position).Y - myImage.Height / 2))
      myImagePoints.Add(CurrentPoint)
      DoPaint = False
    End If
 
    For Each EnteredPoint As Point In myImagePoints
      e.Graphics.DrawImage(myImage, EnteredPoint)
    Next
  End Sub
End Class

Hope that helps.

Cheers,

Ian
 

NKN

Member
Joined
Dec 9, 2011
Messages
19
Programming Experience
Beginner
It worked great, but is there a way where i could insert the "Me.Invalidate" into a sub that handles all the controls at once?
 
Last edited:

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,589
Location
Norway
Programming Experience
10+
IanRyder said:
Dim myImage As New Bitmap(My.Resources.Bee, 42, 39)
In case you didn't know, you must dispose both these image objects before end sub.
Dim CurrentPoint As New Point(CInt(Me.PointToClient(Cursor.Position).X - myImage.Width / 2), CInt(Me.PointToClient(Cursor.Position).Y - myImage.Height / 2))
A little refactor :)
Dim pt = Me.PointToClient(Cursor.Position)
Dim CurrentPoint As New Point(CInt(pt.X - myImage.Width / 2), CInt(pt.Y - myImage.Height / 2))
 

IanRyder

Well-known member
Joined
Sep 9, 2012
Messages
1,130
Location
Healing, NE Lincs, UK
Programming Experience
10+
Hi,

Thanks for the disposing tip JohnH. I was not aware of the importance of disposing image objects after using them but after a quick read up on the net I understand the importance now. Cheers.

NKN,
To begin with and to accommodate JohnH's point above you need to add these two lines of code to the end of the paint event to make sure that resources are not retained after the paint event:-

VB.NET:
myImage.Dispose()
My.Resources.Bee.Dispose()

As to your other point:-

is there a way where i could insert the "Me.Invalidate" into a sub that handles all the controls at once?

I am not sure if we understand what you mean here? By calling Me.Invalidate when you click the form using the Form.Click event you are effectively forcing a redraw of the form which automatically fires the Paint event. This, in turn, then redraws all the previous images on the form including the new image specified at the current cursor position. Does that answer the question?

Hope that helps.

Cheers,

Ian
 

NKN

Member
Joined
Dec 9, 2011
Messages
19
Programming Experience
Beginner
I added this code:

Private Sub AllCtrls()
For Each Ctrl As Control In Me.Controls

AddHandler Ctrl.Click, AddressOf Ctrl_Click

Next
End Sub

Private Sub Ctrl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
DoPaint = True
Me.Invalidate()
End Sub


But it paints behind the controls, how can i make it paint on top off the controls?
 

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,602
Location
Sydney, Australia
Programming Experience
10+
This would be the proper way to do this. Create one and only one Image object, keep a list of the positions the user clicks and invalidate only the necessary area each time, e.g.
Private picture As Image = My.Resources.MyImage
Private imageLocations As New List(Of Point)

Private Sub Form1_MouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
    'Get the point at which the user clicked.
    Dim p = e.Location

    imageLocations.Add(p)

    'Repaint the area that the new picture will be drawn.
    Invalidate(New Rectangle(p, picture.Size))
    Update()
End Sub

Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    'Draw the picture at each clicked point.
    For Each imageLocation In imageLocations
        e.Graphics.DrawImage(picture, imageLocation)
    Next
End Sub
 
Last edited:

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,589
Location
Norway
Programming Experience
10+
IanRyder said:
My.Resources.Bee.Dispose()
No! Each time you access the Bee property it returns a new image object.
 

IanRyder

Well-known member
Joined
Sep 9, 2012
Messages
1,130
Location
Healing, NE Lincs, UK
Programming Experience
10+
Hi JohnH,

I had already realised that the myImage variable created a new image object from the Bee property in My.Resources so I knew that variable had to be disposed, but I also had a funny feeling that disposing the My.Resources.Bee was incorrect. However at the point I wrote that I did not have the concrete knowledge to question your previous comment, which, after quoting the variable declaration in my post, you did say:-

you must dispose both these image objects before end sub

Notice the word "both" in your quote. That is why I disposed the bee property, but no problems, at least I know now.

Cheers,

Ian
 
Top Bottom