I need to check a picturebox for a specific image. I know you can check if the picturebox is populated with an image...
If Not pictureBox.Image is Nothing Then
Else
End If
But in my case, I need to check this picturebox for an image I loaded earlier on in the process.
Here is the current code I'm using to load the image...
PictureBox1.Image = My.Resources.TestImage1
I thought by using the following code I could check the image name, but this apparently does not work.
If PictureBox1.Image = My.Resources.TestImage1 Then
'do something
Else
'do something else
End if
Suggestions?
Image does not have any knowledge of the file name or any other name that it has been loaded from. What you can do, however, is compare images pixel-by-pixel. Try this code:
Public Function AreSameImage(ByVal I1 As Image, ByVal I2 As Image) As Boolean
Dim BM1 As Bitmap = I1
Dim BM2 As Bitmap = I2
For X = 0 To BM1.Width - 1
For y = 0 To BM2.Height - 1
If BM1.GetPixel(X, y) <> BM2.GetPixel(X, y) Then
Return False
End If
Next
Next
Return True
End Function
Credit goes here.
A useful article I found when looking for this answer:
Compare two images to find differences greater than a threshold value in VB .NET
This is how you can check if your images are less than 100% equal, i.e. similar.
Dim a as image=my.resources.image1.jpg' imported file from resources
Dim b as image=my.resources.image2.jpg' imported file from resources
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
picturebox1.image=a
picturebox2.image=b
end sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
if picturebox1.image is a and picturebox2.image=b then
picturebox2.image=a
picturebox1.image=nothing
else
picturebox2.image=b
picturebox1.image=a
end if
end sub
..................Just try it! :)
Related
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. :-)
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
Below is code for a simple voting system I am coding.
Public Class Form1
Dim winner As String
Dim maxVotes As Integer
Dim votes() As String
Dim index As String
Dim candidates As String
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
If Not isValidInput(txtNewCandidate.Text) Then
Exit Sub
End If
lstCandidates.Items.Add(txtNewCandidate.Text)
txtNewCandidate.Clear()
txtNewCandidate.Focus()
ReDim Preserve votes(index)
index += 1
End Sub
Private Function isValidInput(ByRef firstName As String) As Boolean
If IsNumeric(txtNewCandidate.Text) Or txtNewCandidate.Text = "" Then
MsgBox("Please input a valid candidate name.")
txtNewCandidate.Focus()
Return False
Else
Return True
End If
End Function
Private Sub btnTally_Click(sender As Object, e As EventArgs) Handles btnTally.Click
lstTallies.Visible = True
lblTally.Visible = True
For i = 0 To lstCandidates.Items.Count - 1
lstTallies.Items.Add(lstCandidates.Items(i).ToString & " - " & votes(i))
Next
End Sub
Private Sub lstCandidates_DoubleClick(sender As Object, e As EventArgs) Handles lstCandidates.DoubleClick
If lstCandidates.SelectedIndex = -1 Then
MsgBox("Select a candidate by double-clicking")
End If
votes(lstCandidates.SelectedIndex) += 1
MsgBox("Vote Tallied")
End Sub
Private Sub pbxWinner_Click(sender As Object, e As EventArgs) Handles pbxWinner.Click
End Sub
End Class
The voter must double click on their choice of candidate in the first list box. The user then tallies the votes by clicking on a button and a second list box will appear with the votes per candidate.
Now I need to display the winner (or winners, if there is a tie) in a picture box, pbxWinner. I am not sure how to accomplish this. Any clues?
Here is what i am trying to do, though the code below doesn't work.
Private Function candidateWinner(ByRef winner As String) As Boolean
For i As Integer = 0 To lstCandidates.SelectedIndex - 1
If votes(i) > maxVotes Then
maxVotes += 1
End If
Next
g = pbxWinner.CreateGraphics
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("Arial", 7, FontStyle.Regular), Brushes.DarkBlue, New PointF(0, 0))
Return True
End Function
Your code is actually working fine for an initial paint, but when the picture box image doesn't have its own bitmap set, a number of events can repaint its graphics behind the scenes(even as simple as minimizing/mazimizing the form, and a whole bunch of other ones), so in effect your text seems to never appear at all or disappear almost instantly when in reality it's probable getting repainted. To fix this, use a bitmap for the graphics object's reference, paint the bitmap's graphics, and then assign the bitmap to the picturebox's image property. This will make the image persistent...give this code a try in your candidateWinner function after the for loop:
Dim bmp As New Bitmap(pbxWinner.Width, pbxWinner.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("arial", 7, FontStyle.Regular), Brushes.DarkBlue, 0, 0)
pbxWinner.Image = bmp
...If you still aren't seeing text, make sure the winner string has the correct value set, I tested this code and it showed my test string correctly
Edit for Comment:
That's because of the logic you're using to calculate the winner...you are just checking to see if the currently selected candidate's vote count is higher than maxVotes and then incrementing the max by 1. If you wanted to stick with that sort of logic for picking the winner, you would want to iterate through ALL of the candidates(not just those from index 0 to the currently selected one), and if their vote count is higher than the max, then set the max EQUAL to their vote count. Then the next candidate in the loop will have their count checked against the previous max. However, tracking the winner could be done a lot easier if you just use a dictionary since you are allowing candidates to be added, and you must change your "winner" logic to actually check who has the most votes out of everyone entered. A bare bones example of that would look like this:
Dim dctTally As Dictionary(Of String, Integer)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dctTally = New Dictionary(Of String, Integer)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
dctTally.Add(txtNewCandidate.Text, 0)
lstCandidates.Items.Add(txtNewCandidate.Text)
End Sub
Private Sub lstCandidates_DoubleClick(sender As Object, e As EventArgs) Handles lstCandidates.DoubleClick
dctTally(lstCandidates.text) += 1
End Sub
Private Sub pbxWinner_Click(sender As Object, e As EventArgs) Handles pbxWinner.Click
Dim winner = dctTally.Aggregate(Function(l, r) If(l.Value > r.Value, l, r)).Key
Dim bmp As New Bitmap(pbxWinner.Width, pbxWinner.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("arial", 7, FontStyle.Regular), Brushes.DarkBlue, 0, 0)
pbxWinner.Image = bmp
End Sub
This way, the program allows as many names as you want to be added to the candidates list, and will add a vote count to their name each time their name is double-clicked on. Then, when your winner pixturebox is clicked, it will find the dictionary with the highest vote count and display their name in the winner-box.
You can try this to draw the winners:
Private Sub candidateWinner()
Dim y As Single = 0
maxVotes = votes.Select(Function(x) Convert.ToInt32(x)).Max()
For i = 0 To UBound(votes)
If votes(i) = maxVotes.ToString() Then
g = pbxWinner.CreateGraphics
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(lstCandidates.Items(i).ToString(), New Font("Arial", 7, FontStyle.Regular), Brushes.DarkBlue, New PointF(0, y))
y += 10
g.Dispose()
End If
Next
End Sub
I am trying to make a PictureBox change the image when pressed, and if pressed again it will change to the original image. How can I do that? Here is my code.
Private Sub PictureBox1_Click(sender As Object, e As EventArgs) Handles PictureBox1.Click
If (PictureBox1.Image = WindowsApplication1.My.Resources.Resources.asd) Then
PictureBox1.Image = WindowsApplication1.My.Resources.Resources._stop()
Else
PictureBox1.Image = WindowsApplication1.My.Resources.Resources.asd()
End If
End Sub
When I run it, it gives the following error:
Operator '=' is not defined for types "Image" and "Bitmap".
Well, it is the good kind of problem to have. There is a massive bear trap hidden in the My.Resources property getters, every time you use it you get a new bitmap object. That has many consequences, bitmaps are very expensive objects and calling their Dispose() method is very important to prevent your program from running out of memory. And comparing will always fail since it is new object. The difference between Image and Bitmap is just a minor problem.
It is crucial to use the bitmap object just once. Like this:
Private asd As Image = My.Resources.asd
Private _stop As Image = My.Resources._stop
Now you can correctly write this code since you are comparing objects for reference identity:
Private Sub PictureBox1_Click(sender As Object, e As EventArgs) Handles PictureBox1.Click
If PictureBox1.Image = asd Then
PictureBox1.Image = _stop
Else
PictureBox1.Image = asd
End If
End Sub
And like a good programmer you dispose the image objects when you no longer use them:
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
asd.Dispose()
_stop.Dispose()
End Sub
Also fix the code that first assigns the PictureBox1.Image property, we can't see it.
You can use the PictureBox's .Tag property to store information. For this, I will store the resource name.
If you have an array of the resource names to be used, you can get the next one (using Mod to wrap around from the last one to the first (zeroth - array indices start at zero in VB.NET) entry).
Private Sub PictureBox1_Click(sender As Object, e As EventArgs) Handles PictureBox1.Click
Dim imageResourceNames = {"Image1", "Image2"}
Dim pb = DirectCast(sender, PictureBox)
Dim tag = CStr(pb.Tag)
pb.Image?.Dispose()
Dim nextImage = imageResourceNames((Array.IndexOf(imageResourceNames, tag) + 1) Mod imageResourceNames.Length)
pb.Image = DirectCast(My.Resources.ResourceManager.GetObject(nextImage), Image)
pb.Tag = nextImage
End Sub
Please change "Image1" and "Image2" as appropriate.
Array.IndexOf will return -1 if the item searched for is not in the array, but we are adding 1 to it so it will get the first item of the array (at index 0) if the .Tag has not been set.
If you had a third image, you would simply add its name into the array.
The line PictureBox1.Image?.Dispose() disposes of the resources used by the image - the ? makes it only do that if PictureBox1.Image is not Nothing.
When you first set the image of the PictureBox, remember to set its .Tag property appropriately so that it behaves as intended.
I used Dim pb = DirectCast(sender, PictureBox) so that you can simply copy-and-paste the code for a different PictureBox and there will be very little to change in the code - otherwise you would have to update the references to PictureBox1 all through it, which can be error-prone. Of course, at that point you would start thinking about refactoring it so that you are not repeating code (the "Don't repeat yourself", or DRY, principle).
I've been working on this assignment for quite awhile, but I'm practically ripping my hair out. Before anyone jumps the gun and says I'm looking for a free handout on the assignment, please note, I've done 90% of the assignment! The program has 4 commercials in a list, you choose which one to vote for and it saves your vote and tallies it. As it tallies it in the program, it also saves it into a file. The next time you open the file, you can hit "Display vote" and it reads the file and re-tally's everything for the user.
Here's what the program looks like, at least what I have done. My issue is that when I hit display votes, nothing happens. It doesn't read in anything from the file. I tested using a message box for it to see if it displays anything from the file, and it does infact display the first item from the project. Anyone have any ideas?!
Public Class frmMain
Dim intVotes(3) As Integer
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lstCom.Items.Add("Budweiser")
lstCom.Items.Add("FedEx")
lstCom.Items.Add("E*Trade")
lstCom.Items.Add("Pepsi")
lstCom.SelectedIndex = 0
End Sub
Private Sub btnSaveVote_Click(sender As Object, e As EventArgs) Handles btnSaveVote.Click
Dim outFile As IO.StreamWriter
Dim intSub As Integer
intSub = lstCom.SelectedIndex
If intSub <= intVotes.GetUpperBound(0) Then
intVotes(intSub) += 1
If IO.File.Exists("CallerVotes.txt") Then
outFile = IO.File.CreateText("CallerVotes.txt")
If lstCom.SelectedIndex = 0 Then
outFile.WriteLine("Budweiser")
ElseIf lstCom.SelectedIndex = 1 Then
outFile.WriteLine("FedEx")
ElseIf lstCom.SelectedIndex = 2 Then
outFile.WriteLine("E*TRADE")
ElseIf lstCom.SelectedIndex = 3 Then
outFile.WriteLine("Pepsi")
End If
outFile.Close()
End If
End If
lblBud.Text = intVotes(0).ToString
lblFed.Text = intVotes(1).ToString
lblET.Text = intVotes(2).ToString
lblPep.Text = intVotes(3).ToString
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstCom.SelectedIndexChanged
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Me.Close()
End Sub
Private Sub btnDisplayVote_Click(sender As Object, e As EventArgs) Handles btnDisplayVote.Click
Dim inFile As IO.StreamReader
Dim strText As String
If IO.File.Exists("CallerVotes.txt") Then
inFile = IO.File.OpenText("CallerVotes.txt")
Do Until inFile.Peek = -1
strText = inFile.ReadLine
If strText = "Budweiser" Then
intVotes(0) += 1
ElseIf strText = "FedEx" Then
intVotes(1) += 1
ElseIf strText = "E*TRADE" Then
intVotes(2) += 1
ElseIf strText = "Pepsi" Then
intVotes(3) += 1
End If
Loop
inFile.Close()
End If
End Sub
End Class
If you look at your file I think you will see that you have only one entry. You are overwriting the file each time you click the save button by using the CreateText method.
from MSDN(emphasis mine)
This method is equivalent to the StreamWriter(String, Boolean) constructor overload with the append parameter set to false. If the file specified by path does not exist, it is created. If the file does exist, its contents are overwritten.
try using the AppendText method instead.
i.e.
If IO.File.Exists("CallerVotes.txt") Then
outFile = IO.File.AppendText("CallerVotes.txt")
You will also need to assign the values that you read in to the appropriate labels per DeanOC's answer.
I think that your problem is that you are not assigning the values from the intVotes array to the labels. At the end of btnDisplayVote_Click try adding
lblBud.Text = intVotes(0).ToString
lblFed.Text = intVotes(1).ToString
lblET.Text = intVotes(2).ToString
lblPep.Text = intVotes(3).ToString