I am stuck and have tried re-writing my code multiple times and cannot figure out a solution. The application has a text file containing items and prices in a sequential access file. The app should display the price corresponding with the item when it is selected from the list box. Each line in the text file contains the item's number followed by a comma and then the price.
I need to define a structure named item. The structure has 2 member variables, a string to store the item number and a decimal storing the price. I also need to declare a class level array with 5 item structure variables. The load even should read the items and prices and store this info in the class-level array. Then it should add the item numbers to the list box.
This is what I have so far but nothing is working.
Option Explicit On
Option Strict On
Option Infer Off
Public Class frmMain
'declare structure with 2 member variables
Structure Item
Public strItemNum As String
Public decPrice As Decimal
End Structure
'declare array for 5 item structure variables
Private items(4) As Item
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Me.Close()
End Sub
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles Me.Load
'declare variables
Dim inFile As IO.StreamReader
Dim strLineofText As String
Dim intSub As Integer
'check if the file exists
If IO.File.Exists("ItemInfo.txt") Then
'open the file
inFile = IO.File.OpenText("ItemInfo.txt")
'read the file
Do Until inFile.Peek = -1 OrElse
intSub = items.Length
strLineofText = inFile.ReadLine.Trim
'add item to list box
lstNumbers.Items.Add(items(intSub).strItemNum)
Loop
'close the file
inFile.Close()
Else
MessageBox.Show("Can't find the ItemInfo.txtfile",
"Kensington Industries",
MessageBoxButtons.OK,
MessageBoxIcon.Information)
End If
End Sub
Private Sub lstNumbers_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstNumbers.SelectedIndexChanged
lblPrice.Text = items(lstNumbers.SelectedIndex).decPrice.ToString("C2")
End Sub
End Class
I think that you need to change the name of Structure. Item can be used in another references.
Try to change the name to itemstr (for example)
Do Until inFile.Peek = -1 OrElse
intSub = items.Length
strLineofText = inFile.ReadLine.Trim
'add item to list box
Dim arr As String() = str.Split(","C)
Dim valitem As New itemstr()
valitem.text = arr(0)
valitem.value = Convert.ToDecimal(arr(1))
lstNumbers.Items.Add(valitem)
Loop
Thanks everyone. I ended up starting over again and trying something different that works finally!
Option Explicit On
Option Strict On
Option Infer Off
Public Class frmMain
'declare structure
Structure Item
Public strItemNum As String
Public decPrice As Decimal
End Structure
'declare class level array
Public itemList(4) As Item
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Me.Close()
End Sub
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles Me.Load
'declare variables
Dim inFile As IO.StreamReader
Dim strLineOfText As String
Dim decPrice As Decimal
Dim strInfo(4, 1) As String
'check to see if the file exists
If IO.File.Exists("ItemInfo.txt") Then
'open the file
inFile = IO.File.OpenText("ItemInfo.txt")
For intRow As Integer = 0 To strInfo.GetUpperBound(0)
'read the line
strLineOfText = inFile.ReadLine
'assign substring from comma to first coloumn
strInfo(intRow, 0) = strLineOfText.Substring(0, strLineOfText.IndexOf(","))
Dim intSep As Integer = strLineOfText.IndexOf(",") + 1
'assign substring after comma to 2nd column
strInfo(intRow, 1) = strLineOfText.Substring(intSep)
'assign first column value to strItemNum variable
itemList(intRow).strItemNum = (strInfo(intRow, 0))
Decimal.TryParse(strInfo(intRow, 1), decPrice)
'assign 2nd columnn value to decPrice variable
itemList(intRow).decPrice = decPrice
'add item to listbox
lstNumbers.Items.Add(itemList(intRow).strItemNum)
Next intRow
'clost the file
inFile.Close()
Else
'error message if file cannot be found
MessageBox.Show("Can't find the ItemInfo.txtfile",
"Kensington Industries",
MessageBoxButtons.OK,
MessageBoxIcon.Information)
End If
End Sub
Private Sub lstNumbers_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles lstNumbers.SelectedIndexChanged
'display the price
lblPrice.Text = itemList(lstNumbers.SelectedIndex).decPrice.ToString("C2")
End Sub
End Class
Related
I am trying to stay ahead of my Year 12 Software class. Starting to work with records and arrays. I have answered the question, but the solution feels very clunky. I am hoping someone has suggestions/links for completing this task in a more efficient way.
The task: read in lines from a text file and into a structure, and then loop through that, populating four list boxes if an animal hasn't been vaccinated.
Here's the code:
Imports System.IO
Public Class Form1
'Set up the variables - customer record, total pets not vaccinated, total records in the file, and a streamreader for the file.
Structure PetsRecord
Dim custName As String
Dim address As String
Dim petType As String
Dim vacced As String
End Structure
Dim totNotVac As Integer
Dim totalRecCount As Integer
Dim PetFile As IO.StreamReader
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
'set an array of records to store each record as it comes in. Limitation: you need to know how many records in the file. Set the array at 15 to allow for adding more in later.
Dim PetArray(15) As PetsRecord
'variables that let me read in a line and split it into sections.
Dim lineoftext As String
Dim i As Integer
Dim arytextfile() As String
'tell them what text file to read
PetFile = New IO.StreamReader("patients.txt")
totNotVac = 0
Try
totalRecCount = 0
' read each line in and split the lines into fields for the records. Then assign the fields from the array. Finally, reset the array and loop.
Do Until PetFile.Peek = -1
'read in a line of text
lineoftext = PetFile.ReadLine()
'split that line into bits separated by commas. these will go into the array.
arytextfile = lineoftext.Split(",")
'dunno whether this is the best way to do it, but stick the array bits into the record, and then clear the array to start again.
PetArray(totalRecCount).custName = arytextfile(0)
PetArray(totalRecCount).address = arytextfile(1)
PetArray(totalRecCount).petType = arytextfile(2)
PetArray(totalRecCount).vacced = arytextfile(3)
totalRecCount += 1
Array.Clear(arytextfile, 0, arytextfile.Length)
Loop
For i = 0 To PetArray.GetUpperBound(0)
If PetArray(i).vacced = "No" Then
lstVaccinated.Items.Add(PetArray(i).vacced)
lstCustomer.Items.Add(PetArray(i).custName)
lstAddress.Items.Add(PetArray(i).address)
lstPetType.Items.Add(PetArray(i).petType)
totNotVac += 1
lblVacTotal.Text = "The total number of unvaccinated animals is " & CStr(totNotVac)
End If
Next
Catch ex As Exception
MsgBox("Something went wrong with the file")
End Try
PetFile.Close()
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Close()
End Sub
End Class
And one line from the patient.txt file:
Richard Gere,16 Sunset Blvd,Gerbil,No
I hope this isn't out of place.
Regards,
Damian
If you want to use Streams be aware that they need to be disposed.
File.ReadAllLines returns an array of lines. Since the array is initialized where it is declared we don't need to specify a size.
If you use List(Of T) you do not have to know in advance the number of elements in the list. Avoids the limitation of array.
Using a For Each avoids having to use the size. The small c following "," tells the compiler that this is a Char which is what .Split is expecting. If you had Option Strict On, which you always should, you would have seen an error. You add items to the list by creating a New PetsRecord. The parametrized Sub New receives the values and sets the properties.
Don't change the display in the label on each iteration. Use an interpolated string (preceded by a $) which allows embedded variables surrounded by braces { }. It is not necessary to change the number to a string as it is implied by the interpolator. (Available in VS2015 and later)
Public Structure PetsRecord
Public Property custName As String
Public Property address As String
Public Property petType As String
Public Property vacced As String
Public Sub New(name As String, add As String, pType As String, vac As String)
custName = name
address = add
petType = pType
vacced = vac
End Sub
End Structure
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
Dim lines = File.ReadAllLines("patients.txt")
Dim lstPet As New List(Of PetsRecord)
For Each line In lines
Dim splits = line.Split(","c)
lstPet.Add(New PetsRecord(splits(0), splits(1), splits(2), splits(3)))
Next
Dim totNotVac As Integer
For Each pet In lstPet
If pet.vacced = "No" Then
lstVaccinated.Items.Add(pet.vacced)
lstCustomer.Items.Add(pet.custName)
lstAddress.Items.Add(pet.address)
lstPetType.Items.Add(pet.petType)
totNotVac += 1
End If
Next
lblVacTotal.Text = $"The total number of unvaccinated animals is {totNotVac}"
End Sub
If you don't need the 'PetsRecord' array to store data, take a look at the following code:
Dim totNotVac As Integer
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
File.ReadAllLines("your text file path").ToList().ForEach(Sub(x)
lstVaccinated.Items.Add(x.Split(","c)(0))
lstCustomer.Items.Add(x.Split(","c)(1))
lstAddress.Items.Add(x.Split(","c)(2))
lstPetType.Items.Add(x.Split(","c)(3))
totNotVac += 1
End Sub)
lblVacTotal.Text = "The total number of unvaccinated animals is " & CStr(totNotVac)
End Sub
l have a data source that contains two columns
block_name total_lands
A-0 5
A-1 15
A-2 18
A-3 18
And I have two combo boxes one for the block name and the other for the no of lands
the first one is loaded with the block names
Private Sub LoadItems()
SQL.ExecQuery("SELECT block_name FROM blocks;")
For Each i As DataRow In SQL.DBDTable.Rows
ComboBox1.Items.Add(i("block_name"))
Next
End Sub
I want the second one to be loaded with numbers from 1 to whatever is in the data source row total_lands
For example if the user chose the block name as A-1 I want the second combo box to have the items from 1 to 15 add in it
My code trying to do so
Private Sub LoadNoOfLands()
SQL.AddParam("#blockname", ComboBox1.Text)
SQL.ExecQuery("SELECT totla_lands FROM blocks WHERE total_lands LIKE #blockname;")
For Each no As DataRow In SQL.DBDTable.Rows
Dim lands As Integer = no("block_lands")
'For Each i As Integer In lands
'
'
'Next
Next
End Sub
Load required data at once and use Enumerator.Range to generate collection of numbers for second combobox
Public Class Block
Public ReadOnly Property Name As String
Public ReadOnly Property TotalLands As Integer
Public ReadOnly Property Lands As Integer()
Public Sub New(name As String, totalLands As Intger)
Name = name
TotalLands = totalLands
Lands = Enumerable.Range(1, totalLands).ToArray()
End Sub
End Class
Private Function LoadBlocks() As Block()
Dim query = "SELECT block_name, total_lands FROM table"
Dim rows = SQL.ExecuteQuery(query)
Return rows.AsEnumerable().
Select(Function(row) New Block(row.Field(Of String)("block_name"), row.Field(Of Integer)("total_lands"))).
ToArray()
End Function
Private Sub SetupComboBox()
cmbBlocks.DisplayMemeber = "Name"
cmbBlocks.DataSource = LoadBlocks()
End Sub
Private Sub cmbBlocks_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles cmbBlocks.SelectionChangeCommitted
Dim combobox As ComboBox = DirectCast(sender, ComboBox)
Dim block As Block = DirectCast(combobox.SelectedValue, Block)
cmbLands.DataSource = block.Lands
End
I have come up with a simple answer
Private Sub LoadNoOfLands()
cmbLands.Items.Clear()
SQL.AddParam("#blockname", cmbBlocks.Text)
SQL.ExecQuery("SELECT total_lands FROM blocks WHERE block_name LIKE #blockname;")
If SQL.HasException(True) Then Exit Sub
For Each i As DataRow In SQL.DBDTable.Rows
Dim lands = i("total_lands")
Dim r = 1
For r = 1 To lands
cmbLands.Items.Add(r).ToString()
Next
Next
End Sub
This function just adds number to combobox form 1 to the total_lands value
I created a class for the data.
Public Class Block
Public Property Name As String
Public Property TotalLands As Integer
Public Sub New(BlockName As String, Lands As Integer)
Name = BlockName
TotalLands = Lands
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
The combo box will call .ToString on the items to determine what to display.
We get the data from the database and add it to the List(Of Block)
Public Function FillBlocksList() As List(Of Block)
Dim lst As New List(Of Block)
Using cn As New SqlConnection("Your connection string"),
cmd As New SqlCommand("Select block_name, total_lands From BlockTable;", cn)
cn.Open()
Using reader = cmd.ExecuteReader
Do While reader.Read
Dim b As New Block(reader.GetString(0), reader.GetInt32(1))
lst.Add(b)
Loop
End Using
End Using
Return lst
End Function
To fill the first combo we get the list then loop through it adding the Block objects to the combo. You would probably call this from Form.Load.
Public Sub FillBlocksCombo()
Dim lst = FillBlocksList()
For Each item In lst
ComboBox1.Items.Add(item)
Next
End Sub
To fill the second combo cast the select item back its underlying type, Block and use the TotalLands property to add the numbers.
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim NumberOfLands = DirectCast(ComboBox1.SelectedItem, Block).TotalLands
For i = 1 To NumberOfLands
ComboBox2.Items.Add(i.ToString)
Next
End Sub
Im currently working on getting this piece of code to work so that I can read a text file, move the contents into an array and then display a certain column (such as price)
Imports System.IO
Public Class Form1
Dim FileName As String
Dim i As Integer = 0
Dim Alpha As Integer = 0
Dim Products(31) As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
FileName = "Products.txt"
End Sub
Private Sub btnCreateArray_Click(sender As Object, e As EventArgs) Handles btnCreateArray.Click
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser("Products.txt")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
While Not MyReader.EndOfData
currentRow = MyReader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
'MsgBox(currentField)
'txtShowNo.Text = currentField
'txtShowP.Text = i
i = i + 1
Products(i) = currentField
Next
End While
End Using
Do While Alpha <= i
If InStr((txtFileSearch.Text), (Products(Alpha))) Then
lstDisplayFile.Items.Add(Products(Alpha))
Alpha = Alpha + 1
End If
Loop
End Sub
Private Sub btn_Click(sender As Object, e As EventArgs) Handles btn.Click
txtFileSearch.Text = ""
End Sub
Private Sub btnAddToFilePrintFile_Click(sender As Object, e As EventArgs) Handles btnAddToFilePrintFile.Click
Dim Name As String
Dim SName As String
Dim IDNo As Integer
Name = txtName.Text
SName = txtSName.Text
IDNo = txtIDNo.Text
FileOpen(1, FileName, OpenMode.Append) ' create a new empty file & open it in append mode'
WriteLine(1, IDNo, Name, SName) ' Writes a line of data'
FileClose(1)
txtName.Text = ""
txtSName.Text = ""
txtIDNo.Text = ""
txtName.Focus()
End Sub
End Class
The program crashes on this line of code:
lstDisplayFile.Items.Add(Products(Alpha))
along with the following message :
An unhandled exception of type 'System.ArgumentNullException' occurred in System.Windows.Forms.dll
Alpha is my counter, and my thought process behind this was that if the input within the textbox is currently in the array, it will display the completed text in the array.
Here is the current contents within my text file :
"£5.00","50"
"£2.50","30"
If anyone could help me solve this I would be appreciative :)
I have a CSV file that is formatted as (name,number) on each line.
I'm creating an app that loads all names, index(0), into a listbox at form-load and when a name is selected the number, index(1), is displayed in a .textbox.
I start by filling an array and displaying index(0) in the box. No Prob. But when the selected text changes I have problems. If you cant tell I'm new to VB. If I could assign a var to the selected text I could use a while loop but I'm not sure how to assign that. Is there a better way to go about this? Below is my source. Any help would be great.
Public Class Form1
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each line As String In IO.File.ReadAllLines("MembershipPhone.txt")
Dim myData = line.Split(","c)
Dim mName = myData(0)
Dim mPhone = myData(1)
ListBox1.Items.Add(mName)
Next
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
For Each line As String In IO.File.ReadAllLines("MembershipPhone.txt")
Dim query = line.Split(","c)
Dim mName = query(0)
Dim mPhone = query(1)
TextBox2.Text = mPhone
Next
End Sub
I have to code a WPF application for college which reads from a csv file. I get a null reference exception when I want to output the parts of the CSV lines into arrays. You can find the line where the error happens in commentary. Here is the code.
Imports System.Windows.Forms
Imports System.IO
Imports System.Globalization
Class MainWindow
Private foldername As String
Private arrGemeenten As String()
Private arrOppervlakte As Double()
Private arrInwoners As Integer()
Private arrDeelgemeenten As Integer()
Private Sub cboProvincie_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles cboProvincie.SelectionChanged
CSVInlezen()
End Sub
Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
FileBrowserAanmaken()
comboBoxVullen()
End Sub
Private Sub comboBoxVullen()
For Each file As String In IO.Directory.GetFiles(foldername)
If file.EndsWith(".csv") Then
Dim filenaam As String = System.IO.Path.GetFileNameWithoutExtension(file)
cboProvincie.Items.Add(filenaam)
End If
Next
End Sub
Private Sub FileBrowserAanmaken()
'folderbrowserdialog aanmaken
Dim fbd As New FolderBrowserDialog
fbd.SelectedPath = AppDomain.CurrentDomain.BaseDirectory
' Show the FolderBrowserDialog.
Dim result As DialogResult = fbd.ShowDialog()
If (result = Forms.DialogResult.OK) Then
foldername = fbd.SelectedPath
End If
End Sub
Private Sub CSVInlezen()
Dim filepath As String = foldername & "\" & cboProvincie.SelectedValue & ".csv"
If File.Exists(filepath) Then
fileInlezenHulpMethode(filepath)
End If
End Sub
Private Sub fileInlezenHulpMethode(ByVal path As String)
'declarations
Dim sr As New StreamReader(path)
Dim iTeller As Integer = 0
Dim arrLijn As String()
Dim culture As New System.Globalization.CultureInfo("nl-BE")
'eerste lijn meteen uitlezen, dit zijn kolomkoppen en hebben we niet nodig
'read out first line, these are titles and we don't need them
sr.ReadLine()
Do While sr.Peek <> -1
Dim lijn As String = sr.ReadLine()
arrLijn = lijn.Split(";")
arrGemeenten(iTeller) = Convert.ToString(arrLijn(0)) 'HERE I GET THE ERROR!
arrOppervlakte(iTeller) = Double.Parse(arrLijn(2), NumberStyles.AllowDecimalPoint, culture.NumberFormat)
arrInwoners(iTeller) = Integer.Parse(arrLijn(3), NumberStyles.Integer Or NumberStyles.AllowThousands, culture.NumberFormat)
arrDeelgemeenten(iTeller) = Convert.ToString(arrLijn(4))
Loop
End Sub
End Class
You haven't created the array, you have only created a reference for it. To create the array you need to specify a size, for example:
Private arrGemeenten As String(100)
However, to specify the size, you need to know the size when you create the array. (Well, actually you put all data in the first item, so just the size 1 would keep it from crashing, but I don't thing that's what you intended.) You probably want to use lists instead:
Private gemeenten As New List(Of String)()
Then you use the Add method to add items to the list:
gemeenten.Add(Convert.ToString(arrLijn(0)))
Also, consider putting the data in a single list of a custom object, instead of having several lists of loosely coupled data.