|
|
Title | Select random files from a set of directories to build a MP3 player mix in VB.NET |
Description | This example shows how to select random files from a set of directories to build a MP3 player mix in VB.NET. |
Keywords | mp3, mix, random, random files, browse, SaveSetting, GetSetting, DeleteSetting |
Categories | Files and Directories, Software Engineering, Multimedia, VB.NET |
|
|
My MP3 player only has 164 MB of memory so it cannot hold all of my music at once. This application randomly picks files from a set of directories and copies them into a new mix directory. My MP3 player looks like a directory in the file system so I can copy files directly onto it until it is full.
This application demonstrates several useful techniques including:
- Loading and saving settings when the application starts and stops.
- Tracking multiple selected directories.
- Managing ListBox choices.
- Quickly listing the files in a directory with API functions.
- Converting long file names to short file names.
- Letting the user browse to select a directory.
- Randomizing an array.
- Generating a list of random files picked from the selected directories.
- Copying files.
When the program starts, it calls its LoadSettings routine. That routine uses GetSetting to loads saved settings. It loads source directory names and their selected state by looping through the setting values Source0, Source1, ... and Selected0, Selected1, ...
|
|
Private Sub LoadSettings()
txtDestination.Text = GetSetting(APP_NAME, _
"Settings", "DestinationDirectory", CurDir)
txtNumFiles.Text = GetSetting(APP_NAME, _
"Settings", "NumFiles", "1")
lstSources.Items.Clear()
Dim txt As String
Dim new_index As Integer
Dim is_selected As Boolean
For i As Integer = 0 To 100
txt = GetSetting(APP_NAME, "Settings", "Source" & _
Format$(i), "")
If Len(txt) < 1 Then Exit For
new_index = lstSources.Items.Add(txt)
is_selected = CBool(GetSetting(APP_NAME, _
"Settings", "Selected" & Format$(i), "False"))
lstSources.SetSelected(new_index, is_selected)
Next i
End Sub
|
|
When the form is closing, it calls the SaveSettings routine. This routine uses DeleteSetting to remove any previously saved settings. This clears out the source data and is necessary if the new source list is smaller than the previous one.
Next the program uses SaveSetting to save the current settings.
|
|
Private Sub SaveSettings()
On Error Resume Next
DeleteSetting(APP_NAME)
On Error GoTo 0
SaveSetting(APP_NAME, "Settings", _
"DestinationDirectory", txtDestination.Text)
SaveSetting(APP_NAME, "Settings", "NumFiles", _
txtNumFiles.Text)
For i As Integer = 0 To lstSources.Items.Count - 1
SaveSetting(APP_NAME, "Settings", "Source" & _
Format$(i), lstSources.Items(i).ToString)
SaveSetting(APP_NAME, "Settings", "Selected" & _
Format$(i), lstSources.GetSelected(i).ToString)
Next i
End Sub
|
|
When the user clicks the Add button, the program displays a dialog that lets the user select a new source directory. The dlgPickFolder form lets the user enter or select the directory. The main program calls subroutine CenterFormOnForm to center the dialog over the main program's form and then displays the dialog.
The main form checks the dialog's txtDir text box to see if the user made a selection. If txtDir is not blank, then the program uses ChDir to try to move to that directory. If it succeeds, the program adds the directory to the source list.
|
|
Private Sub btnAdd_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnAdd.Click
Dim dlg As New dlgPickFolder
dlg.txtDir.Text = CurDir()
CenterFormOnForm(dlg, Me)
dlg.ShowDialog(Me)
If Len(dlg.txtDir.Text) > 0 Then
On Error Resume Next
ChDir(dlg.txtDir.Text)
If Err.Number <> 0 Then
MessageBox.Show("Error moving to directory '" & _
_
dlg.txtDir.Text & "'", _
"Directory Error", _
MessageBoxButtons.OK, _
MessageBoxIcon.Error)
Else
lstSources.Items.Add(dlg.txtDir.Text)
End If
On Error GoTo 0
End If
dlg.Close()
End Sub
|
|
Subroutine CenterFormOnForm centers a form above another form. It calculates the position the form needs and then adjusts it if necessary to make the form fit on the screen.
|
|
Public Sub CenterFormOnForm(ByVal frm_above As Form, ByVal _
frm_below As Form)
Dim working_area As Rectangle = _
Screen.GetWorkingArea(New Point(0, 0))
Dim x As Integer
x = (frm_below.Left + frm_below.Right - _
frm_above.Width) \ 2
If x < 0 Then x = 0
If x + frm_above.Width > working_area.Right Then
x = working_area.Right - frm_above.Width
End If
Dim y As Integer
y = (frm_below.Top + frm_below.Bottom - _
frm_above.Height) \ 2
If y < 0 Then y = 0
If y + frm_above.Height > working_area.Bottom Then
y = working_area.Bottom - frm_above.Height
End If
frm_above.SetBounds(x, y, frm_above.Width, _
frm_above.Height)
End Sub
|
|
When the user clicks the Remove button, the program confirms that the user wants to remove the selected source directories from the list and then removes them.
|
|
Private Sub btnRemove_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnRemove.Click
If lstSources.Items.Count < 1 Then
MessageBox.Show("No sources selected to delete", _
"No Sources Selected", MessageBoxButtons.OK, _
MessageBoxIcon.Information)
ElseIf MessageBox.Show("Delete selected sources?", _
"Delete Sources?", MessageBoxButtons.YesNo, _
MessageBoxIcon.Question) = vbYes Then
For Each source As Object In _
lstSources.SelectedItems
lstSources.Items.Remove(source)
Next source
End If
End Sub
|
|
When the user clicks the Browse button, the program uses its FolderBrowserDialog control to let the user select a destination directory. (This is a lot easier than it is in Visual Basic 6.)
|
|
Private Sub btnBrowse_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnBrowse.Click
dlgFolder.SelectedPath = CurDir()
If dlgFolder.ShowDialog(Me) = DialogResult.OK Then
txtDestination.Text = dlgFolder.SelectedPath
ChDir(dlgFolder.SelectedPath)
End If
End Sub
|
|
When the user clicks the Load Files button, the program make a collection to hold the names of the files in the selected source directories. For each currently selected source, the program calls subroutine ListFiles to get the file and directory names.
It then makes an array containing the indexes of the files and uss subroutine RandomizeArray to randomize the indexes. Next it uses the indexes to access the files in random order and copies them to the destination directory.
|
|
Private Sub btnLoadFiles_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles _
btnLoadFiles.Click
Dim file_names As Collection
Dim num_files As Integer
Dim indexes() As Integer
Dim dest_dir As String
Dim files_to_copy As Integer
' Make a list of all of the files.
file_names = New Collection
For Each source As String In lstSources.SelectedItems
ListFiles(source, file_names)
Next source
' See how many files we found.
num_files = file_names.Count
If num_files < 1 Then
MessageBox.Show("No files found", "No Files", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
Exit Sub
End If
' Make the indexes array.
ReDim indexes(num_files - 1)
For i As Integer = 0 To num_files - 1
indexes(i) = i + 1
Next i
' Randomize the indexes array.
RandomizeArray(indexes)
' Grab the first files.
files_to_copy = CInt(txtNumFiles.Text)
If files_to_copy > num_files Then files_to_copy = _
num_files
' Start copying files.
Me.Cursor = Cursors.WaitCursor
Application.DoEvents()
dest_dir = txtDestination.Text
Dim file_name, file_title As String
Dim files_copied As Integer = 0
On Error Resume Next
For i As Integer = 0 To files_to_copy - 1
Me.Text = APP_NAME & " (" & i + 1 & ")"
Me.Refresh()
file_name = DirectCast(file_names(indexes(i)), _
String)
file_title = _
file_name.Substring(file_name.LastIndexOf("\"))
FileCopy(file_name, dest_dir & file_title)
If Err.Number <> 0 Then
MessageBox.Show("Error copying file '" & _
file_name & "' to '" & _
dest_dir & file_title & "'" & vbCrLf & _
Err.Description, _
"Copy Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit For
End If
files_copied += 1
'Debug.WriteLine(i & ": FileCopy """ & _
' file_name & """, """ & _
' dest_dir & file_title & """")
Next i
On Error GoTo 0
Me.Text = APP_NAME
Me.Cursor = Cursors.Default
MessageBox.Show("Copied " & files_copied & " files", _
"Done", MessageBoxButtons.OK, _
MessageBoxIcon.Information)
End Sub
|
|
Subroutine ListFiles uses the Directory class's GetFiles method to list the files that match the pattern *.mp3. It adds the files' names to the file_names collection. (This is a lot easier than it is in Visual Basic 6.)
|
|
Public Sub ListFiles(ByVal start_dir As String, ByVal _
file_names As Collection)
Dim new_files As String() = _
Directory.GetFiles(start_dir, "*.mp3")
For Each file_name As String In new_files
file_names.Add(file_name)
Next file_name
End Sub
|
|
Subroutine RandomizeArray randomizes an array. For each entry in the array, it selects a random item at that point or later and swaps it into this position. The result is a randomized array.
|
|
' Randomize an array of integers indexed from 0.
Public Sub RandomizeArray(ByVal indexes() As Integer)
Dim num_items As Integer
Dim j As Integer
Dim tmp As Integer
' Randomize the array.
Randomize()
num_items = indexes.GetUpperBound(0)
For i As Integer = 0 To num_items - 2
' Pick a random entry.
j = CInt(Int((num_items - i) * Rnd() + i))
' Swap the numbers.
tmp = indexes(i)
indexes(i) = indexes(j)
indexes(j) = tmp
Next i
End Sub
|
|
While this program is intended to be useful, it's still not perfect and doesn't handle every possible error condition. It also doesn't save every possible useful setting such as the program's size and position.
|
|
|
|
|
|