Input textbox data into array of objects - arrays

I am using the module to declare the public class patient across all forms of my program. What do I have to do in order to input data into the array from three text boxes. One for Names, Heights, and Weights. Thanks
Public Module Module1
Public PatientCount As Integer = 0
Public Class Patient
Public Property Name As String = String.Empty
Public Property Height As Decimal = 0
Public Property Weight As Decimal = 0
End Class
End Module
Dim patients As List(Of Patient) = New List(Of Patient)
For displaying patients in listbox
For Each p As Module1.Patient In Patients
lstPatients.Items.Add(p.Name)
Next
CURRENT CODE:
MODULE
Public Module Module1
Public PatientCount As Integer = 0
Public Patients As List(Of Patient) = New List(Of Patient)
Public Class Patient
Public Property Name As String
Public Property Height As Decimal
Public Property Weight As Decimal
Public Sub New(ByVal name As String, ByVal height As Decimal, ByVal weight As Decimal)
name = _Name
weight = _Weight
height = _Height
End Sub
End Class
End Module
FORM 2 (Entry of Data)
Public Class Form2
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnMainMenu.Click
Me.Close()
End Sub
Private Sub btnEnterPatient_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnterPatient.Click
patients.Add(New Patient(txtName.Text, CDec(txtHeight.Text), CDec(txtWeight.Text)))
PatientCount = PatientCount + 1
Label1.Text = PatientCount
End Sub
End Class
FORM 3 (Listing of Data)
Public Class Form3
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each p As Patient In Patients
lstPatients.Items.Add("Name: " & p.Name)
lstPatients.Items.Add("Weight: " & p.Weight)
lstPatients.Items.Add("Height: " & p.Height)
lstPatients.Items.Add("___________")
Next
End Sub
End Class

To store the data of an x number of patients, you could have this code in a button-clicked event handler.
Private Sub ButtonOK_Click()Handles BtnOk.Click()
patients.Add(New Module1.Patient(txtName.Text, CDec(txtHeight.Text), CDec(txtWeight.text))
End Sub
And then add this to your Patient class:
Public Module Module1
Public Class Patient
Public Property Name As String = String.Empty
Public Property Height As Decimal = 0
Public Property Weight As Decimal = 0
Public Sub New(_name as String, _height as decimal, _weight as decimal)
Name = _name
Weight = _weight
Height = _height
End Sub
End Class
End Module
Dim patients As List(Of Patient) = New List(Of Patient)
With this, you will create a list of patients every time the btnOk is pressed, and you can easily access any patient and their data.
To put the data in a listbox:
Private Sub BTNLIST_Click()Handles BTNLIST.Click
For Each p As Patient in patients
lstbox.Items.Add("Name: " & p.Name)
lstbox.Items.Add("Weight: " & p.Weight)
lstbox.Items.Add("Height: " & p.Height)
lstbox.Items.Add("___________")
Next
End Sub
OPTIONAL
You could even create a PatientList Class to help you further (but remove the patients List). You could use the PatientList class to add helpful functions, such as finding a patient by name or height.:
Public Class PatientList
Public List(Of Patient) Patients = New List(Of Patient)
Public ReadOnly Property PatientCount() As Integer
Get
Return Patients.Count
End Get
End Property
Public Sub AddPatientToList(name as String, height as decimal, weight as decimal)
Patients.Add(New Patient(name, height, weight)
End Sub
End Class
Dim patients as PatientList
Then add this in your button_click Handler:
Private Sub ButtonOK_Click()Handles BtnOk.Click()
patients.AddPatientToList(New Module1.Patient(txtName.Text, CDec(txtHeight.Text), CDec(txtWeight.text))
End Sub
HTH

One option would be to have a New constructor that takes the 3 values for the properties.
Public Module Module1
Public PatientCount As Integer = 0
Public Class Patient
Public Property Name As String = String.Empty
Public Property Height As Decimal = 0
Public Property Weight As Decimal = 0
Public Sub New(_name As String, _height As Decimal, _weight As Decimal)
Name = _name
Height = _height
Weight = _weight
End Sub
End Class
End Module
Dim patients As List(Of Patient) = New List(Of Patient)
Assuming you've validated the input from the textboxes and converted them to variables(NewName, NewHeight, NewWeight), you would add a new patient something like this:
patients.Add(New Patient(NewName,NewHeight,NewWeight))

If you want to add a patient then you need to create an instance of one and set it properties with the textboxes of whatever form your using. Then add the new patient to the list of patients, so something like this.
Dim patient as new Patient()
patient.Name = txtName.Text()
patient.Height = txtHeight.Text()
patient.Weight = txtWeight.Text()
patients.Add(patient)

Related

How do I read and write this array of structure to/from a file?

I'm trying to write the array persons to a file and read it and have no clue on how to go about it. Here's my code:
Public Class Form1
Structure Person
Public name As String
Public height As Integer
Public weight As Double
End Structure
Dim persons(49) As Person
Dim arraySize As Integer = 0
Private Sub submitBtn_Click(sender As Object, e As EventArgs) Handles submitBtn.Click
If arraySize < 50 Then
Dim Name As String
Dim Height As Integer
Dim Weight As Double
Name = nameTxt.Text
Height = CInt(heightTxt.Text)
Weight = CDbl(weightTxt.Text)
nameTxt.Text = Nothing
heightTxt.Text = Nothing
weightTxt.Text = Nothing
arraySize += 1
persons(arraySize).name = Name
persons(arraySize).height = Height
persons(arraySize).weight = Weight
Else
MsgBox("The list of people is full now. You may no longer enter new people.")
End If
End Sub
Private Sub saveBtn_Click(sender As Object, e As EventArgs) Handles saveBtn.Click
End Sub
Private Sub readBtn_Click(sender As Object, e As EventArgs) Handles readBtn.Click
End Sub
End Class
Any help on how to code this would be appreciated. Thank you!
I tried coding it to save the array persons (which is linked to the structure Person) to a file, but the app freezes, and i am not sure how to get around it.
try to use list :
Public Class Form1
<Serializable()> Structure Person
Public name As String
Public height As Integer
Public weight As Double
End Structure
dim persons As List(Of Person)
Private Sub submitBtn_Click(sender As Object, e As EventArgs) Handles submitBtn.Click
If persons.length < 50 Then
Dim Name As String
Dim Height As Integer
Dim Weight As Double
Name = nameTxt.Text
Height = CInt(heightTxt.Text)
Weight = CDbl(weightTxt.Text)
nameTxt.Text = Nothing
heightTxt.Text = Nothing
weightTxt.Text = Nothing
person.name = Name
person.height = Height
person.weight = Weight
persons.add(person)
Else
MsgBox("The list of people is full now. You may no longer enter new people.")
End If
End Sub
Private Sub saveBtn_Click(sender As Object, e As EventArgs) Handles saveBtn.Click
Using fs As New IO.FileStream("d:\backup\persons.dat", IO.FileMode.Create)
Dim formatter As New BinaryFormatter
formatter.Serialize(fs, persons)
End Using
End Sub
Private Sub readBtn_Click(sender As Object, e As EventArgs) Handles readBtn.Click
Using fs As New IO.FileStream("d:\backup\persons.dat", IO.FileMode.Open)
Dim formatter As New BinaryFormatter
persons = DirectCast(formatter.Deserialize(fs), List(Of person))
End Using
End Sub
dont forget to add <Serializable()> in front of struc definition.

VBNet: List of items inside a class, I cant change the value for a single item

My Problem:
I have a Class and a list of other class inside:
Public Class Signal_Type_Read
Private c_signal_count As Integer = 0 ' counter for read signals
Private _items As List(Of Signal_Item)
Private item As New Signal_Item
Sub add_sig()
c_signal_count += 1
items.Add(item)
End Sub
Public Property items() As List(Of Signal_Item)
Get
Return _items
End Get
Set(value As List(Of Signal_Item))
_items = value
End Set
End Property
Function item_counter() As Integer
item_counter = c_signal_count
End Function
Public Sub New()
_items = New List(Of Signal_Item)
End Sub
End Class
Public Class Signal_Item
Private _original_name As String
Public Property Original_name() As String
Get
Return _original_name
End Get
Set(value As String)
_original_name = value
End Set
End Property
'Many other properties
End Class
My problem is when I use in a loop
Public Shared ReadSignals As New Signal_Type_Read
//Part of a Loop to read cells values and store in the variable
ReadSignals.add_sig()
Dim c_index As Integer = ReadSignals.item_counter - 1
ReadSignals.items.item(c_index).Original_name = c_row.Cells(e_Signame).Value
It always changes the "Original_name" Property in all items of my Variable. Where is my error? I want only that oe item is changed.
I found the cause of the problem... I need to create a new instane of item in my ADD_sig() sub
Sub add_sig()
Dim s_item As New Signal_Item
c_signal_count += 1
items.Add(s_item)
End Sub

WPF avoid adding a duplicate row

I'm using vb.net framework 4.5 and WPF project.
I have a button, the function adds a certain product info to a datagrid. In my vb code file I set a product class
Public Class MyProduct
Public Property ItemNumber As String
Public Property ItemDescription As String
Public Property ItemUnitPrice As Double
Public Property ItemQty As Integer
End Class
The button touchdown event
Private Sub Button_TouchDown(sender As Object, e As TouchEventArgs)
Dim dmb As New MyProduct
dmb.ItemNumber = "abc001"
dmb.ItemDescription = "bla bla bla"
dmb.ItemQty = 1
dmb.ItemUnitPrice = 123.45
MyDataGrid.Items.Add(dmb)
End Sub
Currently, if I tap multiple times of this button, the data grid will add multiple duplicated rows for same product. My goal is when multiple same product add to datagrid, only one row shows and each additional tap/click action on the same button will only increase the ItemQty number.
How can I do that? Thanks!
First, you need to prevent inserting twice :
Private Sub buttonAdd_Click(sender As Object, e As RoutedEventArgs) Handles buttonAdd.Click
Dim dmb As New MyProduct
dmb.ItemNumber = New Random().Next(5).ToString()
dmb.ItemDescription = "bla bla bla"
dmb.ItemQty = 1
dmb.ItemUnitPrice = 123.45
Dim dmbSearched As MyProduct = Nothing
For Each dmbs As MyProduct In MyDataGrid.Items
If dmbs.ItemNumber = dmb.ItemNumber Then
dmbSearched = dmbs
Exit For
End If
Next
If dmbSearched Is Nothing Then
MyDataGrid.Items.Add(dmb)
Else
dmbSearched.ItemQty += 1
End If
End Sub
Second the MyProduct class must raise an event when the quantity is changed, otherwise there is no visible change :
Public Class MyProduct : Implements INotifyPropertyChanged
Private Property m_ItemQty As Integer
Public Property ItemQty As Integer
Get
Return m_ItemQty
End Get
Set(value As Integer)
m_ItemQty = value
FirePropertyChanged()
End Set
End Property
Public Sub FirePropertyChanged(<CallerMemberName> Optional propName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
End Sub
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Public Property ItemNumber As String
Public Property ItemDescription As String
Public Property ItemUnitPrice As Double
End Class
Regards

Using Classes with nested arrays

I'd like to use classes instead of structures in my VBA program, but could not figure it out. Below is an example of what I'm doing, and would be grateful for any advice. Maybe classes are not good for this type of thing, because it did not seem very intuitive to me, I don't know.
Option Explicit
Public Type xYear
month(1 To 12) As Double ' Index is the month
End Type
Public Type Company
Name As String
City As String
Sales(2010 To 2020) As xYear ' Index is the year
End Type
Public SuperData(1 To 50) As Company ' An array of companies with monthly sales
Sub Test_Table()
Dim Company1_Name As String
Dim Company1_City As String
Dim Company1_2011_Sales(1 To 12) As Double
Dim Company1_2012_Sales(1 To 12) As Double
Dim Toledo_Sales_Jul_2012 As Double
' Test Data
Company1_Name = "ABC"
Company1_City = "Toledo"
Company1_2011_Sales(7) = 1000
Company1_2012_Sales(7) = 2000
' Copy test data into Structure
SuperData(1).Name = Company1_Name
SuperData(1).City = Company1_City
SuperData(1).Sales(2011).month(7) = Company1_2011_Sales(1) ' Jul 2011 sales
SuperData(1).Sales(2012).month(7) = Company1_2012_Sales(7) ' Jul 2012 sales
' Query the structure
Toledo_Sales_Jul_2012 = City_Sales("Toledo", 7, 2012)
End Sub
Public Function City_Sales(ByRef City As String, ByRef m As Double, ByRef y As Double) As Double
Dim c As Double
For c = LBound(SuperData) To UBound(SuperData)
If City = SuperData(c).City Then
City_Sales = City_Sales + SuperData(c).Sales(y).month(m)
End If
Next
End Function
I would do this with four classes: CCompany and CSale and collection classes for both.
CCompany:
Private mlCompanyID As Long
Private msCompanyName As String
Private msCity As String
Private mclsSales As CSales
Private mlParentPtr As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(dest As Any, Source As Any, ByVal bytes As Long)
Public Property Set Sales(ByVal clsSales As CSales): Set mclsSales = clsSales: End Property
Public Property Get Sales() As CSales: Set Sales = mclsSales: End Property
Public Property Let CompanyID(ByVal lCompanyID As Long): mlCompanyID = lCompanyID: End Property
Public Property Get CompanyID() As Long: CompanyID = mlCompanyID: End Property
Public Property Let CompanyName(ByVal sCompanyName As String): msCompanyName = sCompanyName: End Property
Public Property Get CompanyName() As String: CompanyName = msCompanyName: End Property
Public Property Let City(ByVal sCity As String): msCity = sCity: End Property
Public Property Get City() As String: City = msCity: End Property
Public Property Get Parent() As CCompanies: Set Parent = ObjFromPtr(mlParentPtr): End Property
Public Property Set Parent(obj As CCompanies): mlParentPtr = ObjPtr(obj): End Property
Private Function ObjFromPtr(ByVal pObj As Long) As Object
Dim obj As Object
CopyMemory obj, pObj, 4
Set ObjFromPtr = obj
' manually destroy the temporary object variable
' (if you omit this step you'll get a GPF!)
CopyMemory obj, 0&, 4
End Function
Private Sub Class_Initialize()
Set mclsSales = New CSales
End Sub
Private Sub Class_Terminate()
Set mclsSales = Nothing
End Sub
CCompanies:
Private mcolCompanies As Collection
Private Sub Class_Initialize()
Set mcolCompanies = New Collection
End Sub
Private Sub Class_Terminate()
Set mcolCompanies = Nothing
End Sub
Public Property Get NewEnum() As IUnknown
Set NewEnum = mcolCompanies.[_NewEnum]
End Property
Public Sub Add(clsCompany As CCompany)
If clsCompany.CompanyID = 0 Then
clsCompany.CompanyID = Me.Count + 1
End If
Set clsCompany.Parent = Me
mcolCompanies.Add clsCompany, CStr(clsCompany.CompanyID)
End Sub
Public Property Get Company(vItem As Variant) As CCompany
Set Company = mcolCompanies.Item(vItem)
End Property
Public Property Get Count() As Long
Count = mcolCompanies.Count
End Property
CSale:
Private mlSaleID As Long
Private mdAmount As Double
Private mlYear As Long
Private mlMonth As Long
Private mlParentPtr As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(dest As Any, Source As Any, ByVal bytes As Long)
Public Property Let SaleID(ByVal lSaleID As Long): mlSaleID = lSaleID: End Property
Public Property Get SaleID() As Long: SaleID = mlSaleID: End Property
Public Property Let Amount(ByVal dAmount As Double): mdAmount = dAmount: End Property
Public Property Get Amount() As Double: Amount = mdAmount: End Property
Public Property Let Year(ByVal lYear As Long): mlYear = lYear: End Property
Public Property Get Year() As Long: Year = mlYear: End Property
Public Property Let Month(ByVal lMonth As Long): mlMonth = lMonth: End Property
Public Property Get Month() As Long: Month = mlMonth: End Property
Public Property Get Parent() As CSales: Set Parent = ObjFromPtr(mlParentPtr): End Property
Public Property Set Parent(obj As CSales): mlParentPtr = ObjPtr(obj): End Property
Private Function ObjFromPtr(ByVal pObj As Long) As Object
Dim obj As Object
CopyMemory obj, pObj, 4
Set ObjFromPtr = obj
' manually destroy the temporary object variable
' (if you omit this step you'll get a GPF!)
CopyMemory obj, 0&, 4
End Function
CSales:
Private mcolSales As Collection
Private Sub Class_Initialize()
Set mcolSales = New Collection
End Sub
Private Sub Class_Terminate()
Set mcolSales = Nothing
End Sub
Public Property Get NewEnum() As IUnknown
Set NewEnum = mcolSales.[_NewEnum]
End Property
Public Sub Add(clsSale As CSale)
If clsSale.SaleID = 0 Then
clsSale.SaleID = Me.Count + 1
End If
Set clsSale.Parent = Me
mcolSales.Add clsSale, CStr(clsSale.SaleID)
End Sub
Public Property Get Sale(vItem As Variant) As CSale
Set Sale = mcolSales.Item(vItem)
End Property
Public Property Get Count() As Long
Count = mcolSales.Count
End Property
Public Sub AddSale(ByVal dAmount As Double, ByVal lYear As Long, ByVal lMonth As Long)
Dim clsSale As CSale
Set clsSale = New CSale
With clsSale
.Amount = dAmount
.Year = lYear
.Month = lMonth
End With
Me.Add clsSale
End Sub
Then in a standard module.
Sub Test_Class()
Dim clsCompanies As CCompanies
Dim clsCompany As CCompany
Dim clsSale As CSale
Set clsCompanies = New CCompanies
Set clsCompany = New CCompany
clsCompany.CompanyName = "ABC"
clsCompany.City = "Toledo"
'Verbose way to add a sale
Set clsSale = New CSale
clsSale.Amount = 1000
clsSale.Year = 2011
clsSale.Month = 7
clsCompany.Sales.Add clsSale
'Quickway to add a sale
clsCompany.Sales.AddSale 2000, 2012, 7
clsCompanies.Add clsCompany
For Each clsCompany In clsCompanies
For Each clsSale In clsCompany.Sales
Debug.Print clsCompany.CompanyName, clsCompany.City, clsSale.Amount, clsSale.Year, clsSale.Month
Next clsSale
Next clsCompany
End Sub
This uses some undocumented features, such as to be able to use For Each on a custom class. Here are a couple of references for you.
http://dailydoseofexcel.com/archives/2010/07/09/creating-a-parent-class/
http://www.cpearson.com/excel/classes.aspx

How do I put this code, or similar code in a different class? (VB.NET)

This is the code I have so far:
Public Class firstForm
Dim sale(3, 4) As Integer
Dim numberSellers(3) As Integer
Dim numberProducts(4) As Integer
Private Sub addButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles addButton.Click
Dim sellerLineInteger As Integer
Dim productColumnInteger As Integer
sellerLineInteger = sellerListBox.SelectedIndex
productColumnInteger = productListBox.SelectedIndex
' add in two dimensional array
If sellerLineInteger >= 0 And productColumnInteger >= 0 Then
sale(sellerLineInteger, productColumnInteger) = Decimal.Parse(saleTextBox.Text)
End If
saleTextBox.Clear()
saleTextBox.Focus()
End Sub
I would like to put this code in a different class/form instead. This class would be used to stock the information entered by the user.
I have two list boxes, one button, and one text box. The user pick an item in each list box, enter a number in the text box and then click the button to stock the information.
I tried to implement the code by using another class, but I couldn't get it to work, but it works when I put it like in the code I showed above.
edit: Thanks a lot guys! I'll try this out in a bit.
Im assuming you want to move as much as possible to another class...
if so, heres an example of how you would do that.
your modifed form code looks like:
Public Class firstForm
Dim MyOtherClass As New Class1
Private Sub addButton_Click(sender As System.Object, e As System.EventArgs) Handles addButton.Click
MyOtherClass.addItem(sellerListBox, productListBox, saleTextBox)
End Sub
End Class
and the new class would look like this:
Public Class Class1
Private sale(3, 4) As Integer
Private numberSellers(3) As Integer
Private numberProducts(4) As Integer
Public Sub addItem(ByRef my_sellerListBox As ListBox, ByRef my_productListBox As ListBox, ByRef my_saleTextBox As TextBox)
Dim sellerLineInteger As Integer
Dim productColumnInteger As Integer
sellerLineInteger = my_sellerListBox.SelectedIndex
productColumnInteger = my_productListBox.SelectedIndex
' add in two dimensional array
If sellerLineInteger >= 0 And productColumnInteger >= 0 Then
sale(sellerLineInteger, productColumnInteger) = Decimal.Parse(my_saleTextBox.Text)
End If
my_saleTextBox.Clear()
my_saleTextBox.Focus()
End Sub
End Class
note that you must create an instance of the class to use, because it contains data (it cannot be a shared sub)
There are different possibilities. I suggest creating two classes for products and sellers
Public Class Product
Public Property Name As String
Public Property Sale As Decimal
End Class
and
Public Class Seller
Public Property Name As String
Private _products As New Dictionary(Of String, Product)()
Public ReadOnly Property Products() As Dictionary(Of String, Product)
Get
Return _products
End Get
End Property
Public Sub SetProductSale(productName As String, sale As Decimal)
Dim product As Product
If _products.TryGetValue(productName, product) Then
product.Sale = sale
Else
product = New Product() With { _
.Name = productName, _
.Sale = sale _
}
_products.Add(productName, product)
End If
End Sub
Public Function GetProductSale(productName As String) As Decimal
Dim product As Product
If _products.TryGetValue(productName, product) Then
Return product.Sale
End If
Return 0D
End Function
End Class
In your form you could then do something like this (I assume that your listboxes store names of sellers and products as strings):
Public Class FirstForm
Private _sellers As New Dictionary(Of String, Seller)()
Public Sub addButtonClick(sender As Object, e As EventArgs)
If sellerListBox.SelectedIndex >= 0 AndAlso _
productListBox.SelectedIndex >= 0 Then
Dim sellerName As String = sellerListBox.SelectedItem.ToString()
Dim productName As String = productListBox.SelectedItem.ToString()
Dim sale As Decimal
If [Decimal].TryParse(saleTextBox.Text, sale) Then
Dim seller As Seller
If Not _sellers.TryGetValue(sellerName, seller) Then
seller = New Seller() With { _
.Name = sellerName _
}
_sellers.Add(sellerName, seller)
End If
seller.SetProductSale(productName, sale)
End If
End If
End Sub
End Class
But you could go one step further and use binding as DJ Burb suggests. The listboxes could be bound directly to lists of sellers and products.
As I said, there are different approaches. In this example I store the sale directly within the product and I have copies of each product in each seller. You could also think of a separate sales class combining products and the sale amount. The sellers would then have a sales dictionary instead of a product dictionary. All the products would then be stored in a separate product dictionary. This would allow you to keep unique instances of the products.

Resources