Storing the path of a file in a listbox - vba

I am making a music player application. I am using a ListBox to display the songs. When the user adds a song, it displays the full path of the song. But I want it to only display the song name(The songs can be located in any folder in any drive). A windows media player control is playing the songs. Thanks in advance!

So You want to extract only the song name from the whole path of the song. A simple tricky logic will do these. This is VBA
sub song_name_extractor()
song_path = "c:\songs\favret\mylove.mp3" ' Assume this is where the song is
song_name = Right(song_path, Len(song_path) - InStrRev(song_path, "\"))
Msgbox song_name 'outputs mylove.mp3
song_name = Left(song_name, InStrRev(song_name, ".") - 1)
Msgbox song_name ' outputs only mylove removes extensions of file
end sub
Explaination:
Right Func, cuts the right part of the string into sub-string of given number
Len Func, To find the length of the string
InStrRev Fun, gives the point of occurrence, of the given character in a string
searching from right to left
Left Func, cuts the Left part of the string into sub-string of given number

I would do it something like this:
1. Create an object that can hold the info of the song.
2. Create an list that holds all songs in the playlist.
3. Add that list as a datasource to the listbox, By setting .DisplayMember, you are telling wich property will be visible as listitemtext in the listbox.
4. When listindex changes, get the object stored in listbox.SelectedItem and ctype it to an songobject to work with it.
Public Class Form1
Structure SongObject
Public SongPath As String
Public NameNoExtension As String
Public SongLength As Integer
Public SongRating As Integer
Private _FileName
Public Property FileName() As String
Get
Return _filename
End Get
Set(ByVal value As String)
_FileName = value
End Set
End Property
Public Sub New(ByVal path As String)
SongPath = path
FileName = IO.Path.GetFileName(path)
NameNoExtension = IO.Path.GetFileNameWithoutExtension(path)
SongLength = 0 'fix
SongRating = 5 'fix
End Sub
End Structure
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim musicpath As String = "C:\Users\Public\Music\Sample Music\"
'Load songs into listbox
ListBox1.DisplayMember = "FileName"
Dim songs As New List(Of SongObject)
For Each f As String In IO.Directory.GetFiles(musicpath, "*.mp3")
songs.Add(New SongObject(f))
Next
ListBox1.DataSource = songs
End Sub
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
'Get songitem
Dim SelectedSong As SongObject = CType(ListBox1.SelectedItem, SongObject)
MsgBox("Path:" & SelectedSong.SongPath & vbCrLf & "FileName:" & SelectedSong.FileName)
'Todo: play selected song...
End Sub
End Class
Use IO.Path.GetFileName(path) and IO.Path.GetFileNameWithoutExtension(path) to get filename instead of right/left/instr/mid and so on.

Related

Utilizing wildcards and variables for getFiles

I am kinda new to VB.net, so I am not sure if I try this the right way. I have the following piece of code.
Dim objReader As New System.IO.StreamReader(FILE_NAME)
Dim TextLine As String
Do While objReader.Peek() <> -1
Dim newString As String = TextLine.Replace(vbCr, "").Replace(vbLf, "") & ".wav"
Dim SongName As String = My.Computer.FileSystem.GetName(newString)
Dim MyFile As String = Dir("C:\AllSongs\" & newString)
Dim Searchquery As IEnumerable(Of String) = IO.Directory.EnumerateFiles("C:\AllSongs", "*", IO.SearchOption.AllDirectories).Where(Function(f) IO.Path.GetFileNameWithoutExtension(f).IndexOf(SongName, StringComparison.CurrentCultureIgnoreCase) >= 0)
For Each Result In Searchquery
ListBox1.Items.Add(Result)
Next
I am trying to use the lines in the text file, and get the .wav in AllSongs dir that partially correspond in these files. Can it be done?
Edit: Part of the code contains a media player. I want to be able to play songs from this player, by choosing files in the list.
Private Sub ListBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.DoubleClick
AxWindowsMediaPlayer1.URL = ListBox1.SelectedItem
Dim variables As New Dictionary(Of String, String)()
Dim selectedItem As Object = ListBox1.SelectedItem
variables("MyDynamicVariable") = selectedItem ' Set the value of the "variable"
selectedItem1 = selectedItem
Dim value As String = variables("MyDynamicVariable") ' Retrieve the value of the variable
End Sub
Incidental to the question, but important, is that when you're working with files it's often necessary to clean up some resources (file handles, I guess) that the operating system uses even though you don't see it directly in the code as written. There is a way of doing that automatically with the Using statement, as shown in the following code.
To find out if a filename contains some text (string), you can extract the filename with no path or extension with Path.GetFileNameWithoutExtension and check if it contains the desired string with the IndexOf function, which lets you ignore uppercase/lowercase by specifying how to do the check.
I notice from an update to the question that some improvements can be made, such as using a Class for the song entries so that the displayed list can have more information behind it, which means that the song name can be shown on its own but you can get the full path to the file when you click on it.
I made a new Windows Forms project and added just a ListBox to it, and used this code to show the full path (which you can use for your media player) to the song when its name is double-clicked:
Imports System.IO
Public Class Form1
Public Class SongEntry
Property Name As String
Property FullName As String
End Class
Sub PopulateSongList(musicDirectory As String, songsList As String)
Dim songList As New List(Of SongEntry)
Using sr As New System.IO.StreamReader(songsList)
Do While Not sr.EndOfStream
Dim thisSong = sr.ReadLine()
If thisSong <> "NaN" Then
Dim fs = Directory.EnumerateFiles(musicDirectory, "*.wav", SearchOption.AllDirectories).
Where(Function(f) Path.GetFileNameWithoutExtension(f).IndexOf(thisSong, StringComparison.CurrentCultureIgnoreCase) >= 0).
Select(Function(g) New SongEntry With {.Name = Path.GetFileNameWithoutExtension(g), .FullName = g})
songList.AddRange(fs)
End If
Loop
End Using
ListBox1.DataSource = songList
ListBox1.DisplayMember = "Name"
ListBox1.ValueMember = "FullName"
End Sub
Private Sub ListBox1_DoubleClick(sender As Object, e As EventArgs) Handles ListBox1.DoubleClick
Dim lb = DirectCast(sender, ListBox)
If lb.SelectedIndex >= 0 Then
Dim fullPathToSong = lb.SelectedValue.ToString()
MsgBox(fullPathToSong)
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim songsList = "C:\temp\AllSongs\songsList.txt"
Dim musicDirectory = "C:\temp\AllSongs"
PopulateSongList(musicDirectory, songsList)
End Sub
End Class

How to transfer data from parallel arrays into a textbox?

I'm trying to write a program that splits data from a text file into parallel arrays and then writes the content of each array in a textbox. The text file is something like this:
Title1, Genre1, Director1,
Title2, Genre2, Director2,
Title3, Genre3, Director3,
Imports System.IO
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sr As New StreamReader("MovieData.txt")
Dim movieTitles(9), genre(9), directors(9), itemsRead() As String
Dim i As Integer = 0
Do Until sr.Peek = -1
itemsRead = sr.ReadLine.Split(",")
movieTitles(i) = itemsRead(0)
genre(i) = itemsRead(1)
directors(i) = itemsRead(2)
TextBox1.Text = movieTitles(i).PadRight(20) & genre(i).PadRight(20) & directors(i)
i += 1
Loop
sr.Dispose()
End Sub
End Class
When I click on the button, the textbox shows only:
Title3 Genre3 Director3
How can I fix this?
If you want your data to line up nicely, use a DataGridView. The extra functionality of a StreamReader is not necessary when you only need to pull data from a text file.
Now that classes and there properties are so easy you really don't need parallel arrays.
I added a custom constructor to the class so you can create a new instance and set all the properties in one line.
The list of Movie can be used as a data source for the grid. No need to set up columns.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Movies As New List(Of Movie)
Dim lines = File.ReadAllLines("MovieData.txt")
For Each line In lines
Dim MovieProperties = line.Split(","c)
Dim M As New Movie(MovieProperties(0).Trim, MovieProperties(1).Trim, MovieProperties(2).Trim)
Movies.Add(M)
Next
DataGridView1.DataSource = Movies
End Sub
Public Class Movie
Public Property Title As String
Public Property Genre As String
Public Property Director As String
Public Sub New(T As String, G As String, D As String)
Title = T
Genre = G
Director = D
End Sub
End Class
EDIT as per OP comment
'**EDIT** Move the declaration of Movies to Form level
Private Movies As New List(Of Movie)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'**EDIT** Remove local declaration of Movies
Dim lines = File.ReadAllLines("MovieData.txt")
For Each line In lines
Dim MovieProperties = line.Split(","c)
Dim M As New Movie(MovieProperties(0).Trim, MovieProperties(1).Trim, MovieProperties(2).Trim)
Movies.Add(M)
Next
DataGridView1.DataSource = Movies
'To return the movies by Director, I strongly suggest you fill a list box with the
'director names so spelling errors won't frustate users
ListBox1.DataSource = GetUniqueDirectors()
End Sub
Private Function GetUniqueDirectors() As List(Of String)
'A bit of Linq using Distinct so we don't get duplicate listing of director names.
Dim Directors = ((From m In Movies
Order By m.Director
Select m.Director).Distinct()).ToList
Return Directors
End Function
Private Function GetMoviesByDirector(sDirector As String) As List(Of String)
'A little Linq magic to get the movies for selected director
Dim DirectorsMovies = (From s In Movies
Where s.Director = sDirector
Order By s.Title
Select s.Title).ToList
Return DirectorsMovies
End Function
Public Class Movie
Public Property Title As String
Public Property Genre As String
Public Property Director As String
Public Sub New(T As String, G As String, D As String)
Title = T
Genre = G
Director = D
End Sub
End Class
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If ListBox1.SelectedIndex = -1 Then
MessageBox.Show("Please select a Director from the list.")
Return
End If
ListBox2.DataSource = Nothing
ListBox2.Items.Clear()
ListBox2.DataSource = GetMoviesByDirector(ListBox1.SelectedItem.ToString)
End Sub
It is done, just replace the code of the TextBox1.Text line like this one:
TextBox1.Text += movieTitles(i).PadRight(20) & genre(i).PadRight(20) & directors(i) & vbNewLine
I hope this answers your question bro,
^_^

How to save many object (with the same class) to txt file and binding those object with listbox VB.NET

I try to program a simple project to save data to txt file, read it and use binding data to show it. My project like this.
When I add ID Person to "Add ID" textbox (Textbox which near Button "Add ID"). It will add ID to Listbox and "ID Name" textbox. With this IDName, I insert FirstName and LastName for first person and Save Person's Name. Then, I Add new ID in "Add ID" textbox and fill First,last name and save it again
I refer this page http://vbnetsample.blogspot.de/2007/12/serialize-deserialize-class-to-file.html?m=1 to save and read data to txt file. It's run ok. But my problem is that when I save Person 2 with ID 2, Person 1 is overwrited. I think I can save Person to List Person. But it will make difficult when I want to update any Person's data. I don't know whether Is there any way to save and update each person. And by the way How can I show data by binding data in listbox.
Here is my code
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.IO
Public Class Form1
Public pPerson As New Person
'Serialize and Save Data to txt file
Private Sub SaveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveButton.Click
pPerson.IDName = IDNameTextBox.Text
pPerson.FirstName = FirstNameTextBox.Text
pPerson.LastName = LastNameTextBox.Text
Dim fs As FileStream = New FileStream("C:\Users\Bruce\Desktop\test.txt", FileMode.OpenOrCreate)
Dim bf As New BinaryFormatter()
bf.Serialize(fs, pPerson)
fs.Close()
End Sub
'Deserialize and Read Data from txt file
Private Sub ReadButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ReadButton.Click
If FileIO.FileSystem.FileExists("C:\Users\Bruce\Desktop\test.txt") Then
Dim fsRead As New FileStream("C:\Users\Bruce\Desktop\test.txt", FileMode.Open)
Dim bf As New BinaryFormatter()
Dim objTest As Object = bf.Deserialize(fsRead)
fsRead.Close()
IDNameTextBox.Text = objTest.IDName
FirstNameTextBox.Text = objTest.FirstName
LastNameTextBox.Text = objTest.LastName
End If
End Sub
Private Sub AddIDButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddIDButton.Click
ListBox1.Items.Insert(0, AddIDTextBox.Text)
IDNameTextBox.Text = AddIDTextBox.Text
End Sub
End Class
'Create Class Person
<System.Serializable()>
Public Class Person
Private m_sIDName As String
Private m_sFirstName As String
Private m_sLastName As String
Public Sub New()
End Sub
Public Property IDName() As String
Get
Return Me.m_sIDName
End Get
Set(ByVal value As String)
Me.m_sIDName = value
End Set
End Property
Public Property FirstName() As String
Get
Return Me.m_sFirstName
End Get
Set(ByVal value As String)
Me.m_sFirstName = value
End Set
End Property
Public Property LastName() As String
Get
Return Me.m_sLastName
End Get
Set(ByVal value As String)
Me.m_sLastName = value
End Set
End Property
End Class
To me it seems like the issue here is
Dim fs As FileStream = New FileStream("C:\Users\Bruce\Desktop\test.txt", FileMode.OpenOrCreate)
you have to change it to this:
If not File.Exists("C:\Users\Bruce\Desktop\test.txt") Then
File.create("C:\Users\Bruce\Desktop\test.txt")
End If
Dim fs As FileStream = New FileStream("C:\Users\Bruce\Desktop\test.txt", FileMode.Append)
The whole problem was that your file was simply open (or created if it was not there before) and being written from the first line.By using FileMode.Append your File will be opened and anything new will be tried to be written at the end of the file.
Let me know if this worked :)

Multiple Search Criteria (VB.NET)

So my problem is:
I have a List of a custom Type {Id as Integer, Tag() as String},
and i want to perform a multiple-criteria search on it; eg:
SearchTags={"Document","HelloWorld"}
Results of the Search will be placed a ListBox (ListBox1) in this format:
resultItem.id & " - " & resultItem.tags
I already tried everything i could find on forums, but it didn't work for me (It was for db's or for string datatypes)
Now, i really need your help. Thanks in advance.
For Each MEntry As EntryType In MainList
For Each Entry In MEntry.getTags
For Each item As String In Split(TextBox1.Text, " ")
If Entry.Contains(item) Then
If TestIfItemExistsInListBox2(item) = False Then
ListBox1.Items.Add(item & " - " & Entry.getId)
End If
End If
Next
Next
Next
Example Custom Array:
(24,{"snippet","vb"})
(32,{"console","cpp","helloworld"})
and so on...
I searched for ("Snippet vb test"):
snippet vb helloWorld - 2
snippet vb tcpchatEx - 16
cs something
test
So, i'll get everything that contains one of my search phrases.
I expected following:
snippet vb tcp test
snippet vb dll test
snippet vb test metroui
So, i want to get everything that contains all my search phrases.
My entire, code-likely class
Imports Newtonsoft.Json
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Dim MainList As New List(Of EntryType)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MainList.Clear()
Dim thr As New Threading.Thread(AddressOf thr1)
thr.SetApartmentState(Threading.ApartmentState.MTA)
thr.Start()
End Sub
Delegate Sub SetTextCallback([text] As String)
Private Sub SetTitle(ByVal [text] As String) ' source <> mine
If Me.TextBox1.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetTitle)
Me.Invoke(d, New Object() {[text]})
Else
Me.Text = [text]
End If
End Sub
Sub thr1()
Dim linez As Integer = 1
Dim linex As Integer = 1
For Each line As String In System.IO.File.ReadAllLines("index.db")
linez += 1
Next
For Each line As String In System.IO.File.ReadAllLines("index.db")
Try
Application.DoEvents()
Dim a As saLoginResponse = JsonConvert.DeserializeObject(Of saLoginResponse)(line) ' source <> mine
Application.DoEvents()
MainList.Add(New EntryType(a.id, Split(a.tags, " ")))
linex += 1
SetTitle("Search (loading, " & linex & " of " & linez & ")")
Catch ex As Exception
End Try
Next
SetTitle("Search")
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim searchTags() As String = TextBox1.Text.Split(" ")
Dim query = MainList.Where(Function(et) et.Tags.Any(Function(tag) searchTags.Contains(tag))).ToList
For Each et In query
ListBox1.Items.Add(et.Id)
Next
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) ' test
MsgBox(Mid(ListBox1.SelectedItem.ToString, 1, 6)) ' test
End Sub 'test, removeonrelease
End Class
Public Class EntryType
Public Property Id As Integer
Public Property Tags() As String
Public Sub New(ByVal _id As Integer, ByVal _tags() As String)
Me.Id = Id
Me.Tags = Tags
End Sub
Public Function GetTags() As String
'to tell the Listbox what to display
Return Tags
End Function
Public Function GetId() As Integer
'to tell the Listbox what to display
Return Id
End Function
End Class
I also edited your EntryType class; I added a constructor, removed toString and added GetTags and GetID.
Example "DB" im working with ("db" as "index.db" in exec dir):
{"tags":"vb.net lol test qwikscopeZ","id":123456}
{"tags":"vb.net lol test","id":12345}
{"tags":"vb.net lol","id":1234}
{"tags":"vb.net","id":123}
{"tags":"cpp","id":1}
{"tags":"cpp graphical","id":2}
{"tags":"cpp graphical fractals","id":3}
{"tags":"cpp graphical fractals m4th","id":500123}
Error:
Debugger:Exception Intercepted: _Lambda$__1, Form2.vb line 44
An exception was intercepted and the call stack unwound to the point before the call from user code where the exception occurred. "Unwind the call stack on unhandled exceptions" is selected in the debugger options.
Time: 13.11.2014 03:46:10
Thread:<No Name>[5856]
Here is a Lambda query. The Where filters on a predicate, since Tags is an Array you can use the Any function to perform a search based on another Array-SearchTags. You can store each class object in the Listbox since it stores Objects, you just need to tell it what to display(see below).
Public Class EntryType
Public Property Id As Integer
Public Property Tags() As As String
Public Overrides Function ToString() As String
'to tell the Listbox what to display
Return String.Format("{0} - {1}", Me.Id, String.Join(Me.Tags, " "))
End Function
End Class
Dim searchTags = textbox1.Text.Split(" "c)
Dim query = mainlist.Where(Function(et) et.Tags.Any(Function(tag) searchTags.Contains(tag))).ToList
For Each et In query
Listbox1.Items.Add(et)
Next

Retrieve a object from a list of objects in visual basic and use it to fill text/combo boxes

I have a class as seen below:
Public Class parameters
Public Property test As String
Public Property test_type As String
Public Property user_test_name As String
Public Property meas As String
Public Property spec As String
...etc
End Class
I make a list of objects that I import from a csv somewhere. The user_test_name's from the list gets sent to a list box:
For Each parameters In param
' MsgBox(parameters.user_test_name)
ListBox1.Items.Add(parameters.user_test_name)
Next
now when the user selects something from the list i want the rest of the properties of that particular user_test_name object to populate in certain text/combo boxes in the application. Here is how I grab what is selected.
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Dim selected_name As String = ListBox1.SelectedItem()
' MsgBox(selected_name)
find_object_by_user_test_name(selected_name)
End Sub
Now i'm having difficulty finding the object with the selected_name from the list and using its properties to fill the text.combo boxes. I tried the following to no success:
Public Sub find_object_by_user_test_name(ByVal description)
MsgBox(description)
Dim matches = From parameters In param
Where parameters.user_test_name = description
Select parameters
' MsgBox(matches)
' MsgBox(matches.user_test_name)
TextBox1.Text = matches.test
TextBox2.Text = matches.test_name
etc,,, on and on
' populate_area(matches)
End Sub
Instead of adding the name (a string) to the ListBox, add your actual INSTANCE to it.
First, override ToString() in your class so that it displays properly in your ListBox:
Public Class parameters
Public Property test As String
Public Property test_type As String
Public Property user_test_name As String
Public Property meas As String
Public Property spec As String
Public Overrides Function ToString() As String
Return user_test_name
End Function
End Class
Next, add each instance to the ListBox:
For Each parameters In param
ListBox1.Items.Add(parameters)
Next
Now, the SelectedIndexChanged() event, you can cast the SelectedItem() item back to parameters and you already have everything at your disposal:
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
If ListBox1.SelectedIndex <> -1 Then
Dim P As parameters = DirectCast(ListBox1.SelectedItem, parameters)
' ... do something with "P" ...
Debug.Print(P.user_test_name & " --> " & P.test)
End If
End Sub
If the user_test_names are unique, it may be easier to use a dictionary and retrieve the objects that way.
Dim params As New Dictionary(Of String, parameters)
params.add(MyParameterObject.user_test_name, MyParameterObject)
Then
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Dim selected_name As String = ListBox1.SelectedItem()
Dim selected_param as parameters = params(selected_name)
End Sub
Something like this should do it:
Public Sub find_object_by_user_test_name(ByVal description As String)
' assuming param is your list of parameter objects
For Each p In param
If p.user_test_name = description Then
TextBox1.Text = p.test
TestBox2.Text = p.test_name
...
Exit For
End If
Next
End Sub
A few notes about your code. First, you can't allow two objects to have the same user_test_name. Second, you can't use parameters as a variable name if you already have a class called parameters in your current namespace (which you do).
There is a simpler solution than any of these--just do the following:
Dim i as Integer = ListBox1.SelectedIndex
Then you can use i as an index to your original list of objects.