How to turn over cards in card game? - vb.net

I have created a card game where 2 x 12 different images will be loaded into 24 picture boxes in vb forms. My intention is for the user to turn over two cards at a time, trying to find pairs to match. Each time the game is loaded, there will be different pictures and they will be in different positions. So far I have loaded the image for the back of the card in the game successfully but I can’t turn them over to see if my images have loaded successfully.
I am not concerned about shuffling them yet, I just want to see if the images have loaded and to be able to have two cards turned over at a time. I’m really confused as I’m not used to using VB for such tasks so any help is appreciated. Here is my code:
Imports System.IO
Public Class Board
' as per stackoverflow Terms of Service
' this code comes from
' http://stackoverflow.com/a/40707688
'array of picture boxes
Private pBoxes As PictureBox()
'array of images
Private imgs As String() = {"1.jpg", "2.jpg", "3.jpg", "4.jpg", "5.jpg", "6.jpg", "7.jpg", "8.jpg", "9.jpg", "10.jpg", "11.jpg", "12.jpg", "13.jpg", "14.jpg", "15,jpg", "16.jpg", "17.jpg", "18.jpg", "19.jpg", "20.jpg", "21.jpg", "22.jpg", "23.jpg", "24.jpg"}
'random number generator
Private RNG = New Random
'cover image
Private coverImg As String = "bg.jpg"
'timer
Private dt As DateTime
'turns cards
Private pbFirst As PictureBox
Private pbSecond As PictureBox
Private matches As Int32 = 0
'Folder where images are held
Private ImgFolder As String
Private Sub Board1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
RNG = New Random()
'array of picture boxes
pBoxes = New PictureBox() {PictureBox1, PictureBox2, PictureBox3, PictureBox4,
PictureBox5, PictureBox6, PictureBox7, PictureBox8,
PictureBox9, PictureBox10, PictureBox11, PictureBox12, PictureBox13, PictureBox14, PictureBox15, PictureBox16, PictureBox17, PictureBox18, PictureBox19, PictureBox20, PictureBox21, PictureBox22, PictureBox23, PictureBox24}
'where images are located
ImgFolder = "F: \COMPUTER SCIENCE\Test images"
coverImg = Path.Combine(ImgFolder, coverImg)
For Each p As PictureBox In pBoxes
p.ImageLocation = coverImg
Next
NewGame()
End Sub
'Take images from file
Private Sub PickImages()
Dim nums = Enumerable.Range(1, 12).ToArray()
Dim pool = nums.Concat(nums).OrderBy(Function(r) RNG.Next).ToArray()
End Sub
Private Sub Shuffle()
End Sub
' reset everything
Private Sub NewGame()
matches = 0
pbFirst = Nothing
pbSecond = Nothing
' repick, reshuffle
PickImages()
Shuffle()
dt = DateTime.Now
'tmrMain.Enabled = True
End Sub
End Class

I dont have the points to comments however are you clicking on the pictures to turn them over? If so I think you would just need to have an event such as the below to load the back of the card image.
Private Sub PictureBox1_Click(sender As System.Object, e As System.EventArgs) Handles PictureBox1.Click
PictureBox1.ImageLocation = ("Path to Picture of back of the card")
PictureBox1.Load()
End Sub

Don't try and over-think this - forget about "turning them over" simply change the image:
Private Sub PictureBox1_Click(sender As System.Object, e As System.EventArgs) Handles PictureBox1.Click, PictureBox2.Click 'etc
dim index as short
' to do: get the index of the PictureCard
If sender.Image is coverImg then
sender.Image = imgs(index) ' in stead of 0, use the index of the picture card
Else
sender.Image = coverImage
End if
End Sub

Related

Play different MP3 files one by one in VB.Net 2019

I am creating a small forms application in VB.Net 2019 that will scan my harddrive for MP3 files and then play them in random order.
At this moment I scan my disk and load everything in two listboxes (one for the path, one for the filename because I also want to export in CSV). Somewhere in the future this data will go in a database with extra information so I can choose the genre of music I want to randomly play at that moment.
When I click my cmdRandom commandbutton, the first file starts to play but when I want to continue with the next random file, the file is searched and loaded into media player but doesn't start playing (I have to click "play" manually).
Here's my code:
Private Sub cmdRandom_Click(sender As Object, e As EventArgs) Handles cmdRandom.Click
intaantal = ListBox2.Items.Count
Randomize()
PlayMedia()
End Sub
Private Sub PlayMedia()
intNumber = CInt(Int((intAantal * Rnd()) + 1))
ListBox1.SelectedIndex = intNumber
ListBox2.SelectedIndex = intNumber
FileName = ListBox1.SelectedItem.ToString() + "\" + ListBox2.SelectedItem.ToString()
lblSongText.Text = FileName
' mPlayer.URL = ""
' mPlayer.Refresh()
' mPlayer.close()
' mPlayer.settings.autoStart = True
' mPlayer.settings.setMode("loop", True)
' mPlayer.Ctlcontrols.play()
mPlayer.URL = FileName
End Sub
Private Sub mPlayer_PlayStateChange(sender As Object, e As _WMPOCXEvents_PlayStateChangeEvent) Handles mPlayer.PlayStateChange
If mPlayer.playState = mPlayer.playState.wmppsMediaEnded Then
PlayMedia()
End If
End Sub
All items in PlayMedia() that are commented out have already been tested but don't work. I thought that adding mPlayer.Ctlcontrols.play() in the mPlayer_playStateChange () function in an else clause of the current if would work but that gives me a compilation error (seems to not be allowed in this event).
What am I doing wrong?
Found the sollution on the web after another search: (https://social.msdn.microsoft.com/Forums/sqlserver/en-US/31082234-7161-4446-a96e-32c0314dfe0f/actions-when-a-media-player-control-finished-playing?forum=vbgeneral). It all has to do with the time between the end of the first song and the loading of the next.
I added a timer and things are fixed now, I set the timer interval to 100.
Private Sub mPlayer_PlayStateChange(sender As Object, e As _WMPOCXEvents_PlayStateChangeEvent) Handles mPlayer.PlayStateChange
If mPlayer.playState = mPlayer.playState.wmppsMediaEnded Then
mPlayer.Ctlcontrols.stop()
Timer1.Start()
End If
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Timer1.Stop()
PlayMedia()
End Sub

Download Image under the Mouse pointer via WebBrowser

I'm navigating to Google Images using a WebBrowser control. The aim is to be able to right click on any image and download and populate a PictureBox background.
I have my own ContextMenuStrip with Copy on it and have disabled the built in context menu.
The issue I am having is that the coordinate returned from CurrentDocument.MouseMove are always relative to the first (top left) image.
So my code works correctly if the Image I want is the very first image on the page, however clicking on any other Images always returns the coordinates of the first image.
It would appear that the coordinates are relative to each Image rather than the page.
Private WithEvents CurrentDocument As HtmlDocument
Dim MousePoint As Point
Dim Ele As HtmlElement
Private Sub Google_covers_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebBrowser1.IsWebBrowserContextMenuEnabled = False
WebBrowser1.ContextMenuStrip = ContextMenuStrip1
End Sub
Private Sub WebBrowser1_Navigated(sender As Object, e As WebBrowserNavigatedEventArgs) Handles WebBrowser1.Navigated
CurrentDocument = WebBrowser1.Document
End Sub
Private Sub CurrentDocument_MouseMove(sender As Object, e As HtmlElementEventArgs) Handles CurrentDocument.MouseMove
MousePoint = New Point(e.MousePosition.X, e.MousePosition.Y)
Me.Text = e.MousePosition.X & " | " & e.MousePosition.Y
End Sub
Private Sub ContextMenuStrip1_Opening(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles ContextMenuStrip1.Opening
Ele = CurrentDocument.GetElementFromPoint(MousePoint)
If Ele.TagName = "IMG" Then
CopyToolStripMenuItem.Visible = True
Else
CopyToolStripMenuItem.Visible = False
End If
End Sub
Private Sub CopyToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles CopyToolStripMenuItem.Click
Dim ToImg = Ele.GetAttribute("src")
mp3_row_edit.PictureBox1.BackgroundImage = New System.Drawing.Bitmap(New IO.MemoryStream(New System.Net.WebClient().DownloadData(ToImg)))
ToImg = Nothing
End Sub
This code allow to use a standard WebBrowser control to navigate to the Google Image search page and select/download an Image with a right-click of the Mouse.
To test it, drop a WebBrowser Control and a FlowLayoutPanel on a Form and navigate to a Google Image search page.
Things to know:
WebBrowser.DocumentCompleted: This event is raised each time one of the Sub-Documents inside a main HtmlDocument page is completed. Thus, it can be raised multiple times. We need to check whether the WebBrowser.ReadyState = WebBrowserReadyState.Complete.
Read these note about this: How to get an HtmlElement value inside Frames/IFrames?
The images in the Google search page can be inserted in the Document in 2 different manners: both using a Base64Encoded string and using the classic src=[URI] format. We need to be ready to get both.
The mouse click position can be espressed in either absolute or relative coordinates, referenced by the e.ClientMousePosition or e.OffsetMousePosition.
Read the notes about this feature here: Getting mouse click coordinates in a WebBrowser Document
The WebBrowser emulation mode can be important. We should use the most recent compatible mode available in the current machine.
Read this answer and apply the modifications needed to have the most recent Internet Explorer mode available: How can I get the WebBrowser control to show modern contents?.
Note that an event handler is wired up when the current Document is completed and is removed when the Browser navigates to another page. This prevents undesired calls to the DocumentCompleted event.
When the current Document is complete, clicking with the right button of the Mouse on an Image, creates a new PictureBox control that is added to a FlowLayouPanel for presentation.
The code in the Mouse click handler (Protected Sub OnHtmlDocumentClick()) detects whether the current image is a Base64Encoded string or an external source URI.
In the first case, it calls Convert.FromBase64String to convert the string into a Byte array, in the second case, it uses a WebClient class to download the Image as a Byte array.
In both cases, the array is then passed to another method (Private Function GetBitmapFromByteArray()) that returns an Image from the array, using Image.FromStream() and a MemoryStream initialized with the Byte array.
The code here is not performing null checks and similar fail-proof tests. It ought to, that's up to you.
Public Class frmBrowser
Private WebBrowserDocumentEventSet As Boolean = False
Private base64Pattern As String = "base64,"
Private Sub frmBrowser_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebBrowser1.ScriptErrorsSuppressed = True
WebBrowser1.IsWebBrowserContextMenuEnabled = False
End Sub
Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
If WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso WebBrowserDocumentEventSet = False Then
WebBrowserDocumentEventSet = True
AddHandler WebBrowser1.Document.MouseDown, AddressOf OnHtmlDocumentClick
End If
End Sub
Protected Sub OnHtmlDocumentClick(sender As Object, e As HtmlElementEventArgs)
Dim currentImage As Image = Nothing
If Not (e.MouseButtonsPressed = MouseButtons.Right) Then Return
Dim source As String = WebBrowser1.Document.GetElementFromPoint(e.ClientMousePosition).GetAttribute("src")
If source.Contains(base64Pattern) Then
Dim base64 As String = source.Substring(source.IndexOf(base64Pattern) + base64Pattern.Length)
currentImage = GetBitmapFromByteArray(Convert.FromBase64String(base64))
Else
Using wc As WebClient = New WebClient()
currentImage = GetBitmapFromByteArray(wc.DownloadData(source))
End Using
End If
Dim p As PictureBox = New PictureBox() With {
.Image = currentImage,
.Height = Math.Min(FlowLayoutPanel1.ClientRectangle.Height, FlowLayoutPanel1.ClientRectangle.Width)
.Width = .Height,
.SizeMode = PictureBoxSizeMode.Zoom
}
FlowLayoutPanel1.Controls.Add(p)
End Sub
Private Sub WebBrowser1_Navigating(sender As Object, e As WebBrowserNavigatingEventArgs) Handles WebBrowser1.Navigating
If WebBrowser1.Document IsNot Nothing Then
RemoveHandler WebBrowser1.Document.MouseDown, AddressOf OnHtmlDocumentClick
WebBrowserDocumentEventSet = False
End If
End Sub
Private Function GetBitmapFromByteArray(imageBytes As Byte()) As Image
Using ms As MemoryStream = New MemoryStream(imageBytes)
Return DirectCast(Image.FromStream(ms).Clone(), Image)
End Using
End Function
End Class

VB.Net populating text boxes from text file

I'm creating an inventory management system where the data is stored in a text file. I'm able to save data to the text file, however on the tracker screen it should show current inventory such as: Manufacturer, Processor, Video, Form, RAM, etc. However, all my text boxes remain blank and I'm not sure why. It's not reading properly or updating the text.
frmTracker.vb
Private Sub txtManufacturer_TextChanged(sender As Object, e As EventArgs) Handles txtManufacturer.TextChanged
Dim objMyStreamReader = System.IO.File.OpenText("inventory.txt")
Dim strInventory = objMyStreamReader.ReadLine()
objMyStreamReader.Close()
txtManufacturer.AppendText(strInventory)
End Sub
This is how I'm currently saving the data to the text file.
frmItemEntry.vb
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim objMyStreamReader As System.IO.StreamReader
Dim objMyStreamWriter As System.IO.StreamWriter = System.IO.File.CreateText("inventory.txt")
Dim strInventory As String
objMyStreamWriter.WriteLine(txtManufacturerEntry.Text)
objMyStreamWriter.WriteLine(txtProcessorEntry.Text)
objMyStreamWriter.WriteLine(txtVideoEntry.Text)
objMyStreamWriter.WriteLine(txtFormEntry.Text)
objMyStreamWriter.WriteLine(txtRamEntry.Text)
objMyStreamWriter.WriteLine(txtVramEntry.Text)
objMyStreamWriter.WriteLine(txtHdEntry.Text)
objMyStreamWriter.WriteLine(chkWirelessEntry.CheckState)
objMyStreamWriter.Close()
Me.Close()
End Sub
Example from inventory.txt
Dell
i5
Nvidia
Desktop
8
4
600
0
To be honest, controls should never be used as the primary store for your data in a program. You should really be creating a class and a list of that class to store your data.
You can then read your data into the list from your file, and then, display it from there in your form.
There are several ways of navigating through the data and saving updates. The suggestion below uses buttons for next item and previous item, and a button to save update the file.
It's all pretty self explanatory, but if there's something your not sure about, please have a google and learn something new :-D
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ReadDataFile()
DisplayItem(0)
End Sub
Private Class InventoryItem
Public Property Manufacturer As String
Public Property Processor As String
Public Property Video As String
Public Property FormFactor As String
Public Property Ram As String
Public Property VRam As String
Public Property Hd As String
Public Property Wireless As CheckState
Public Sub New()
Manufacturer = ""
Processor = ""
Video = ""
FormFactor = ""
Ram = ""
VRam = ""
Hd = ""
Wireless = CheckState.Unchecked
End Sub
End Class
Dim Inventory As New List(Of InventoryItem)
Dim currentItemIndex As Integer
Private Sub ReadDataFile()
Using objMyStreamReader As New StreamReader("k:\inventory.txt")
Do Until objMyStreamReader.EndOfStream
Dim newItem As New InventoryItem
newItem.Manufacturer = objMyStreamReader.ReadLine()
newItem.Processor = objMyStreamReader.ReadLine()
newItem.Video = objMyStreamReader.ReadLine()
newItem.FormFactor = objMyStreamReader.ReadLine()
newItem.Ram = objMyStreamReader.ReadLine()
newItem.VRam = objMyStreamReader.ReadLine()
newItem.Hd = objMyStreamReader.ReadLine()
Dim wirelessValue As String = objMyStreamReader.ReadLine()
If wirelessValue = "0" Then
newItem.Wireless = CheckState.Unchecked
ElseIf wirelessValue = "1" Then
newItem.Wireless = CheckState.Checked
End If
Inventory.Add(newItem)
Loop
End Using
End Sub
Private Sub SaveDataFile()
Using objMyStreamWriter As New System.IO.StreamWriter("k:\inventory.txt", False)
For Each item As InventoryItem In Inventory
objMyStreamWriter.WriteLine(item.Manufacturer)
objMyStreamWriter.WriteLine(item.Processor)
objMyStreamWriter.WriteLine(item.Video)
objMyStreamWriter.WriteLine(item.FormFactor)
objMyStreamWriter.WriteLine(item.Ram)
objMyStreamWriter.WriteLine(item.VRam)
objMyStreamWriter.WriteLine(item.Hd)
If item.Wireless = CheckState.Checked Then
objMyStreamWriter.WriteLine("1")
Else
objMyStreamWriter.WriteLine(0)
End If
Next
End Using
End Sub
Private Sub DisplayItem(index As Integer)
With Inventory(index)
txtManufacturerEntry.Text = .Manufacturer
txtProcessorEntry.Text = .Processor
txtVideoEntry.Text = .Video
txtFormEntry.Text = .FormFactor
txtRamEntry.Text = .Ram
txtVramEntry.Text = .VRam
txtHdEntry.Text = .Hd
chkWirelessEntry.CheckState = .Wireless
End With
End Sub
Private Sub BtnUpdateItem_Click(sender As Object, e As EventArgs) Handles BtnUpdateItem.Click
With Inventory(currentItemIndex)
.Manufacturer = txtManufacturerEntry.Text
.Processor = txtProcessorEntry.Text
.Video = txtVideoEntry.Text
.FormFactor = txtFormEntry.Text
.Ram = txtRamEntry.Text
.VRam = txtVramEntry.Text
.Hd = txtHdEntry.Text
.Wireless = chkWirelessEntry.CheckState
End With
SaveDataFile()
End Sub
Private Sub BtnPreviousItem_Click(sender As Object, e As EventArgs) Handles BtnPreviousItem.Click
If currentItemIndex > 0 Then
currentItemIndex -= 1
DisplayItem(currentItemIndex)
End If
End Sub
Private Sub BtnNextItem_Click(sender As Object, e As EventArgs) Handles BtnNextItem.Click
If currentItemIndex < Inventory.Count - 1 Then
currentItemIndex -= 1
DisplayItem(currentItemIndex)
End If
End Sub
First change the format of your text file.
Dell,i5,Nvidia,Desktop,8,2,600,True
Acer,i7,Intel,Desktop,16,4,1GB,True
HP,Pentium,Diamond Viper,Desktop,4,2,200,False
Surface Pro,i7,Intel,Laptop,8,2,500,True
Each line is a record and each field in the record is separated by a comma (no spaces so we don't have to .Trim in code) (a space within a field is fine, notice Surface Pro).
Now it is easier to read the file in code.
This solution uses a BindingSource and DataBindings. This simplifies Navigation and editing and saving the data.
Public Class Form5
Private bs As BindingSource
Private dt As New DataTable
#Region "Set Up the Form"
Private Sub Form5_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddColumnsToDataTable()
FillDataTable()
AddDataBindings()
End Sub
Private Sub AddColumnsToDataTable()
'Prepare the DataTable to hold data
dt.Columns.Add("Manufacturer", GetType(String))
dt.Columns.Add("Processor", GetType(String))
dt.Columns.Add("Video", GetType(String))
dt.Columns.Add("Form", GetType(String))
dt.Columns.Add("RAM", GetType(String))
dt.Columns.Add("VRAM", GetType(String))
dt.Columns.Add("HD", GetType(String))
dt.Columns.Add("Wireless", GetType(Boolean))
End Sub
Private Sub FillDataTable()
'ReadAllLines returns an array of the lines in a text file
'inventory.txt is stored in the bin\Debug folder of your project
'This is the current directory so it does not require a full path.
Dim lines = File.ReadAllLines("inventory.txt")
'Now it is easy to split each line into fields by using the comma
For Each line As String In lines
'Split returns an array of strings with the value of each field
Dim items = line.Split(","c)
'Each item in the array can be added as a field to the DataTable row
dt.Rows.Add(items(0), items(1), items(2), items(3), items(4), items(5), items(6), CBool(items(7)))
'Notice that the last element is changed from a string to a boolean. This is
'the Wireless field which is bound to the check box. The string "True" or "False" is
'changed to a Boolean so it can be used as the .Checked property (see bindings)
Next
End Sub
Private Sub AddDataBindings()
'Create a new instance of the BindingSource class
bs = New BindingSource()
'Set the DataSource to the DataTable we just filled
bs.DataSource = dt
'Now you can set the bindings of each control
'The .Add method takes (Name of Property to Bind, the BindingSource to use, The Field name
'from the DataTable.
txtForm.DataBindings.Add("Text", bs, "Form")
txtHd.DataBindings.Add("Text", bs, "HD")
txtManufacturer.DataBindings.Add("Text", bs, "Manufacturer")
txtProcessor.DataBindings.Add("Text", bs, "Processor")
txtRam.DataBindings.Add("Text", bs, "RAM")
txtVideo.DataBindings.Add("Text", bs, "Video")
txtVram.DataBindings.Add("Text", bs, "VRAM")
'Notice on the CheckBox we are using the Checked property.
chkWireless.DataBindings.Add("Checked", bs, "Wireless")
End Sub
#End Region
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
'Add a blank row to the DataTable
'A Boolean is like a number, a String can be Nothing but a Boolean must
'have a value so we pass in False.
dt.Rows.Add(Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, False)
'Find the position of the last row
Dim i As Integer = bs.Count - 1
'Move to the new empty row
bs.Position = i
End Sub
#Region "Navigation Code"
Private Sub btnPrevious_Click(sender As Object, e As EventArgs) Handles btnPrevious.Click
'The binding source Position determins where in the data you are
'It starts at zero
If bs.Position = 0 Then
MessageBox.Show("This is the first item.")
Return 'This exits the sub, you can use Exit Sub in vb
'but Return is common in other languages so it is good to learn
Else
'As the position of the BindingSource changes the boud TextBoxes
'change their data.
bs.Position = bs.Position - 1
End If
End Sub
Private Sub btnNext_Click(sender As Object, e As EventArgs) Handles btnNext.Click
' If you are not at the end of the list, move to the next item
' in the BindingSource.
If bs.Position + 1 < bs.Count Then
bs.MoveNext()
' Otherwise, move back to the first item.
Else
bs.MoveFirst()
End If
End Sub
#End Region
#Region "Save the Data"
Private Sub SaveDataTable()
'Resave the whole file if this was a real app you would use a database
Dim sb As New StringBuilder
'A string builder keeps the code from creating lots of new strings
'Strings are immutable (can't be changed) so every time you think you are
'changing a string, you are actually creating a new one.
'The string builder is mutable (changable)
For Each row As DataRow In dt.Rows
'The ItemsArray returns an array of objects containing all the
'values in each column of the data table.
Dim rowValues = row.ItemArray
'This is a bit of Linq magic that turns the values (objects) into strings
'Underneath it is performing a For loop on each object in the array
Dim strRowValues = From o In rowValues
Select Convert.ToString(o)
'Now that we have strings we can use the String.Join with the comma
'to get the format of the text file
sb.AppendLine(String.Join(",", strRowValues))
Next
'Finally we change the StringBuilder to a real String
'The inventory.txt is stored in the bin\Debug directory so it is current directory
'no additional path required
File.WriteAllText("inventory.txt", sb.ToString)
End Sub
Private Sub Form5_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
'Because our binding is two-way any additions or changes to the text
'in the text boxes or check box are reflected in the DataTable.
SaveDataTable()
End Sub
#End Region
End Class
Once you remove the comments, there is really very little code here. The #Region...#End Region tags make it easy to collapse code sections you are not working on and find areas quickly.

Graphics causing solid white button

I'm coding Conway's game of life. My grid is entirely in a picture box but when I load the form the back button in the upper right is completely white. Refreshing the form fixes the button but makes it incredibly laggy. Every other button shows up fine, just the back button is broken. How can I fix this?
Option Strict On
Public Class frmGame
' Declaring public variables
Public bmp As Bitmap
Public G As Graphics
Public WithEvents speed As Timer
Public grid(50, 40) As Boolean
Public input(50, 40) As Boolean
Public intGens As Integer = 0
Public change As Boolean = False
Public P As New Pen(Color.Black)
Private Sub picGrid_Paint(sender As Object, e As PaintEventArgs) Handles picGrid.Paint
' Loads bitmap, graphics, etc and prepares to begin simulation
' Creates graphics device
bmp = New Bitmap(600, 480)[enter image description here][1]
picGrid.Image = bmp
G = Graphics.FromImage(bmp)
' Defining variables for grid
Dim x As Integer = 0
Dim y As Integer = 0
' Draws grid
For y = 0 To 480
For x = 0 To 600
G.DrawRectangle(pen:=P, x:=x, y:=y, width:=12, height:=12)
x += 12
Next
x = 0
y += 12
Next
End Sub
Private Sub btnBack_Click(sender As Object, e As EventArgs) Handles btnBack.Click
' Hides rules form, shows main menu form
frmMainMenu.Show()
Me.Hide()
End Sub
Private Sub frmGame_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
' Frees memory when form is closed
G.Dispose()
bmp.Dispose()
speed.Dispose()
End Sub
End Class
I'm not exactly sure do I understand your problem, nor I can recreate it with code provided.
But I can recommend some thing's that can help you.
First of all do not use Control.Refresh() while working with drawing, use instead Control.Invalidate() & Control.Update(), that may fix lag issue.
Do you relay need 2 forms (that i understand is the root of problem)?
Instead of hiding form, hide PictureBox (.Visible = False) and show other controls you need at that moment.

Matching cards by using .tag

In this game I am creating, I have a set of "cards" as pictureboxes set to a random lot of images. When the game starts, the images in the pictureboxes are hidden and the user has to guess which image was in each card. I am having trouble with finding if the user's guess matches what was in the actual card.
In the code below, I am using a listbox to score the names of images in which the user can guess from.
https://imgur.com/a/xCg8X
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
If ClickedCard Is Nothing Then 'Make sure that a card has been clicked, otherwise the below code will fail.
MsgBox("You must select a card.")
Return 'Do not continue execution of this code.
End If
btnSubmit.Visible = True
ClickedCard.Image = imglist1.Images(ListBox1.SelectedIndex)
If ClickedCard.Tag = ListBox1.SelectedIndex Then
roundscore += 1
If roundscore = Cards.Count Then
MsgBox("All right")
End If
End If
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
Static AlreadySelected As New List(Of Integer)
If AlreadySelected.Contains(ListBox1.SelectedIndex) Then
MessageBox.Show("Already select once")
Exit Sub
End If
AlreadySelected.Add(ListBox1.SelectedIndex)
'Your other code here
End Sub
The static list will persist between calls to this sub. You will have to clear this list when you go to a new round. I hope this helps with the problem you mentioned in your comments. :-)