Play different MP3 files one by one in VB.Net 2019 - vb.net

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

Related

How do I use VB Application.DoEvent?

I have a process that works well when it's running against small files but gives an "Message=Managed Debugging Assistant 'ContextSwitchDeadlock' : 'The CLR has been unable to transition from COM context 0xa5b8e0 to COM context 0xa5b828 for 60 seconds." error when running against large files. I'm pretty new to VB and did some investigating and found that using Application.DoEvent seemed to be recommended. I was hoping that someone could show me an example of how to use that. If I'm executing a Sub called "Process1", how would I use the DoEvent to prevent it from timing out. Ideally I'd like to add a progress bar as well but I have ot idea on that one either. I'd appreciate any help. Please keep it simple as I'm new to VB/VS.
This is the comment from my first question showing the code. Process1 calls a sub named ArchDtlCopyFile1 which scrolls through the values in a list view, copying the files named in the items to a different location. It then calls ArchDtlCheckCopy1 to scroll through the list view again to ensure that the copy was done. It then decides if the source file should be deleted and do it if required. Finally it inserts a row in an Access table documenting the change made.
Private Sub Process1()
If ReturnCode = 0 Then
ArchDtlCopyFile1()
Else
' MessageBox.Show("Error code coming in is: " & CStr(ReturnCode))
End If
If ReturnCode = 0 Then
ArchDtlCheckCopy1()
Else
' MessageBox.Show("Error code for check copy is: " & CStr(ReturnCode))
End If
End Sub
Private Sub ArchDtlCopyFile1()
intLVIndex = 0
' Copy the file from the source computer onto the NAS
Do While intLVIndex < intMaxFileIndex
Try
' Select the row from the LVFiles ListView, then move the first column (0) into strSourceFilePath and the last
' column (3) into strDestFilePath. Execute the CopyFile method to copy the file.
LVFiles.Items(intLVIndex).Selected = True
strSourceFilePath = LVFiles.SelectedItems(intLVIndex).SubItems(0).Text
strDestFilePath = LVFiles.SelectedItems(intLVIndex).SubItems(3).Text
My.Computer.FileSystem.CopyFile(strSourceFilePath, strDestFilePath, overwrite:=False)
Catch ex As Exception
' Even if there's an error with one file, we should continue trying to process the rest of the files
Continue Do
End Try
intLVIndex += 1
Loop
End Sub
Private Sub ArchDtlCheckCopy1()
intLVIndex = 0
intLVError = 0
' ' Check each file was copied onto the NAS
Do While intLVIndex < intMaxFileIndex
' Select the row from the LVFiles ListView, then move the last column (3) into strDestFilePath.
' Use the FileExists method to ensure the file was created on the NAS. If it was, call the
' ADetDelete Sub to delete the source file from the user's computer.
LVFiles.Items(intLVIndex).Selected = True
strSourceFilePath = LVFiles.SelectedItems(intLVIndex).SubItems(0).Text
strDestFilePath = LVFiles.SelectedItems(intLVIndex).SubItems(3).Text
strSourceFile = LVFiles.SelectedItems(intLVIndex).SubItems(1).Text
Try
If My.Computer.FileSystem.FileExists(strDestFilePath) Then
' Archive file was created so go ahead and delete the source file
'If strSourceFile = myCheckFile Then
' strDestFile = LVFiles.SelectedItems(intLVIndex).SubItems(3).Text
'End If
If RBArchive.Checked = True Then
ArchDtlDeleteFile(strSourceFilePath)
End If
PrepareDtlVariables()
ADtlAddRow()
Else
MessageBox.Show("File not found. " & strDestFilePath)
End If
Catch ex As Exception
ErrorCode = "ARC6"
MessageCode = "Error while checking file copy"
ReturnCode = 8
End Try
intLVIndex += 1
Loop
End Sub
Here's a simplified example:
Imports System.ComponentModel
Imports System.IO
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BackgroundWorker1.WorkerReportsProgress = True
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For i As Integer = 1 To 20
BackgroundWorker1.ReportProgress(i) ' you can pass anything out using the other overloaded ReportProgress()
System.Threading.Thread.Sleep(1000)
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
' you can also use e.UserState to pass out ANYTHING
Label1.Text = e.ProgressPercentage
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
MessageBox.Show("Done!")
Button1.Enabled = True
End Sub
End Class

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. :-)

How to turn over cards in card game?

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

Visual Basic Sequential Access Files

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

Process.Start open too many multiple windows

I started to program a couple of months ago and I'm having hard time with Process.Start command.
In the first form I've made a timer that can set a time and opens the program, that i defined it location in my TextBox box (another vb app that i built),
according to the time one enters and presses the "Set" button, when its time it opens the file that you choose.
For some reason it opens 10 multiple windows and on browsing for JPG file, it opens it only once, the multiple windows issues occurs only with .exe files.
Does anyone know the reason?
Here is my code so far:
Public Class startup
Dim iSetTime As Date
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If txtTMinute.Text <> String.Empty Then
Clipboard.SetText(txtTMinute.Text)
Else
Clipboard.Clear()
End If
txtTSecond.Clear()
txtTSecond.Paste()
If (Timer1.Enabled = True) Then
Timer1.Enabled = False
End If
iSetTime = txtTHour.Text + ":" + txtTMinute.Text + ":" + txtTSecond.Text
Timer1.Enabled = True
Label6.Text = "Timer not activated."
Me.Refresh()
System.Threading.Thread.Sleep(1000)
'MessageBox.Show("Activated Succesfully")
Label6.Text = "Timer Activated!"
Label6.ForeColor = Color.Green
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If (TimeOfDay = iSetTime) Then
Process.Start(TextBox1.Text)
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Using ofd As New OpenFileDialog
ofd.Filter = "All files (*.*)|*.*"
ofd.Title = "Select File"
If ofd.ShowDialog() = Windows.Forms.DialogResult.OK Then
Me.TextBox1.Text = ofd.FileName
End If
End Using
End Sub
End Class
You don't use enabled = true or false , you use timer.start or timer.stop , i don't know why are you even using a timer to do this? Anywho what's happening is the timer is continously looping through the code after little intervals because IT IS A TIMER and that's what it does until you stop it. If you really want to use a timer for this task then after this line Process.Start(TextBox1.Text) use this code: Timer1.Stop
By the way if you haven't changed the default interval of the timer then it would be set to 100 which is in milliseconds. it is equal to the same time as System.Threading.Thread.Sleep(100) and if you are stopping your timer after System.Threading.Thread.Sleep(1000) then it would've already looped the code: Process.Start(TextBox1.Text) 10 times because 1000/100 = 10
"When im browsing for JPG file, it opens it only once, only with exe
it multiple it."
I'm going to guess that it's trying to open anything you tell it to 10 times, the difference is that when you open an image, it is getting displayed in a single-instance program (like Preview, or Windows Image Viewer, or whatever it happens to be called), and then "reopened" in the same viewer instance 9 more times.
Set a breakpoint at this line:
Process.Start(TextBox1.Text)
When the breakpoint is encountered after running your application in the debugger, mouseover the two variables in the previous line, TimeOfDay and iSetTime in the IDE, and compare their values. I'd be willing to bet you're getting multiple True cases because of the implicit conversion between TimeOfDay's TimeSpan data format, and iSetTime as a Date.