Search code examples
vb.netwinformsgraphicsdrawing

I draw image to form, but it is limited to top left corner of form


I have created a form and imported two square images saved as PNG files in resources. when I run the code below the black box which is drawn will only go about 200 pixels in the x coordinate and 150 pixels in the Y coordinate from where the image is drawn, after that the background remains white, and it seems I am unable to draw anything and anything I do draw stops around this point.

I have tried redrawing the image in a completely different location on the screen and It will not be visible if it is not within the region to the top left of the form, I have also tried drawing other images, but they also cease to exist when not in the top left of my form.

What I want is for the black box/other images to be drawn across the whole form, and not just in the top left corner, which something is preventing me from doing.

Public Class Form1
   Dim gameGraphics As System.Drawing.Graphics = Me.CreateGraphics

   Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
       'Draws black square which I have saved as resource 
       gameGraphics.DrawImage(My.Resources.black_Background, 0, 80, 1600, 600)
       'Draws green square which I have saved as resource 
       gameGraphics.DrawImage(My.Resources.greenSquare, 2, 82, 40, 40)
   End Sub

   'makes the form fullscreen
   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
       Me.FormBorderStyle = FormBorderStyle.None
       Me.WindowState = FormWindowState.Maximized
   End Sub


   'closes form if quitbutton is clicked
   Private Sub QuitButton_Click(sender As Object, e As EventArgs) Handles QuitButton.Click
       Me.Close()
   End Sub
End Class

Thanks for your time!


Solution

  • The Graphics Object cannot be stored. It's Erased/Updated constantly. You'll end up with an invalid one. It's really useless and, you could say, a mistake.
    You can use a Graphics Object created with Control.CreateGraphics(), but you have to remember that it's not persistent; it will be erased when the Control you have painted it on needs to re-Paint() itself (e.g. you drag something over it, if it's a Form, when it's minimized etc.).

    Those Properties, Me.FormBorderStyle = FormBorderStyle.None and Me.WindowState = FormWindowState.Maximized are better set in the designer.
    There's no reason to set them on a Form.Load() event. Their state is not even subject to a condition.
    In general, leave the Load event of a Form as lightweight as possible and avoid setting properties that can cause cascading events.

    An example:

    Define an object to store your images:
    (The DrawBitmaps flag is used to let your Form know when to draw those Bitmaps).

    Public Class MyBitmap
        Public Property Image As Bitmap
        Public Property Position As Point
        Public Property Size As Size
    End Class
    
    Public MyBitmaps As List(Of MyBitmap)
    Public DrawBitmaps As Boolean = False
    

    Somewhere (even in Form.Load()), fill the list with you bitmaps:
    (Here, the bitmap size is set to original size, but you can set it to whatever dimension you see fit).

    MyBitmaps = New List(Of MyBitmap)
    MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.black_Background,
                                     .Position = New Point(0, 80),
                                     .Size = New Size(My.Resources.black_Background.Width,
                                                      My.Resources.black_Background.Height)})
    MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.greenSquare,
                                     .Position = New Point(2, 82),
                                     .Size = New Size(My.Resources.greenSquare.Width,
                                                      My.Resources.greenSquare.Height)})
    

    The Paint() event e.Graphics of the Form performs all the painting:
    (Note that it will not paint its surface unless the DrawBitmaps flag is set to True => It will not paint those Bitmaps when it's loading/showing. The other condition is a basic fail-safe.

    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
        If DrawBitmaps = True AndAlso MyBitmaps.Count > 0 Then
            For Each _Item As MyBitmap In MyBitmaps
                e.Graphics.DrawImage(_Item.Image, New Rectangle(_Item.Position, _Item.Size))
            Next
        End If
    End Sub
    

    When Button1 is clicked, the Form will draw your list of Bitmaps:

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        DrawBitmaps = True
        Me.Invalidate()
    End Sub
    

    Somewhere in your code, add a new Bitmap and tell the Form to Invalidate only a region of the size of this new Bitmap:

    MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.[AnotherBitmap],
                                     .Position = New Point(50, 50),
                                     .Size = New Size(200, 200)})
    
    Me.Invalidate(New Rectangle(MyBitmaps.Last().Position, MyBitmaps.Last().Size))
    

    Remove a Bitmap from the list and repaint:

    MyBitmaps.RemoveAt(0)
    Me.Invalidate()