I'm doing an IT course for college and one of the assignments requires you to create a BMI calculator in Visual Basic with the use of object orientated techniques. I'm not a very good programmer and thus I'm stuck on a problem I keep receiving. The code I'm using was given to me by someone who claimed it works, however when I run the program any results given are NaN.
Anyone have an idea as to what is wrong with the code in order to give me this result?
Here is the code I'm using:
Public Class Form1
Private Sub Button_Calculate_Click(sender As Object, e As EventArgs) Handles
Button_Calculate.Click
Dim height As Double = Double.Parse(TextBox_Height.Text)
Dim weight As Double = Double.Parse(TextBox_Weight.Text)
bmi.SetWeight(weight)
bmi.SetHeight(height)
TextBox_BMI.Text = Format(bmi.GetBMI(), "0.00")
End Sub
Private bmi As New BMI
End Class
In a separate class:
Public Class BMI
Public Function GetBMI()
Return (weight / (height ^ 2))
End Function
Public Function GetWeight()
Return weight
End Function
Public Function GetHeight()
Return height
End Function
Public Function SetWeight(_weight As Double)
Return weight = _weight
End Function
Public Function SetHeight(_height As Double)
Return height = _height
End Function
Private weight As Double
Private height As Double
End Class
There are a few problems with your (meaning kushlord420) solution.
Visual Basic code in case insensitive so bmi is the same as BMI
You never use the Form level variable bmi so delete.
You tried to write a custom constructor but in vb.net it is Sub New
You are converting the values in the weight and height text boxes to Double but your properties are type Single. Actually this should
be Single.TryParse but that is for another day.
Functions in vb.net must have a data type for the return value. This is provided in the first line of the function. Since you are
using Format on the return value I made the value a String and
converted the return value.
Fixed the constructor parameters to avoid ambiguity.
Sub Button_Calculate_Click(sender As Object, e As EventArgs) Handles Button_Calculate.Click
Dim bmi As New BMI(CSng(TextBox_Weight.Text), CSng(TextBox_Height.Text))
TextBox_BMI.Text = Format(bmi.GetBMI(), "0.00")
End Sub
Public Class BMI
Public Function GetBMI() As String
Return (Weight / (Height ^ 2)).ToString
End Function
Public Property Weight As Single
Public Property Height As Single
Public Sub New(wght As Single, hght As Single)
Weight = wght
Height = hght
End Sub
End Class
You really need something more like this:
Public Class BMI
Public Function GetBMI() As Double
Return (weight / (height ^ 2))
End Function
Public Property Weight As Double
Public Property Height As Double
Public Sub New(weight As Double, height As Double)
Me.Weight = weight
Me.Height = height
End Sub
End Class
Public Class Form1
Private Sub Button_Calculate_Click(sender As Object, e As EventArgs) Handles Button_Calculate.Click
Dim bmi As New BMI(CDbl(TextBox_Weight.Text), CDbl(TextBox_Height.Text))
TextBox_BMI.Text = Format(bmi.GetBMI(), "0.00")
End Sub
End Class
Or better yet, this:
Public Class BMI
Public Property Weight As Double
Public Property Height As Double
Public ReadOnly Property BMI As Double
Get
Return (Weight / (Height ^ 2))
End Get
End Property
Public Sub New()
End Sub
Public Sub New(weight As Double, height As Double)
Me.Weight = weight
Me.Height = height
End Sub
End Class
With the help of a friend, figured out my problem.
If anyone is curious, here is the code that made it work:
Public Class Form1
Sub Button_Calculate_Click(sender As Object, e As EventArgs) Handles
Button_Calculate.Click
Dim bmi As New BMI With {.Weight = CDbl(TextBox_Weight.Text), .Height =
CDbl(TextBox_Height.Text)}
TextBox_BMI.Text = Format(bmi.GetBMI(), "0.00")
End Sub
Private bmi As New BMI
End Class
And:
Public Class BMI
Public Function GetBMI()
Return (weight / (height ^ 2))
End Function
Property Weight As Single
Property Height As Single
Public Sub BMI(weight As Single, height As Single)
Me.Weight = weight
Me.Height = height
End Sub
End Class
Related
I have a class which inherit from Panel, and below are some member in this class
Public ItemName As String
Public Quantity As Integer
Public Price As Decimal
Public DiscountAmount As Decimal
How can I create a event when Quantity or DiscountAmount changed then run a function?
I try to write in this way but I get error:-
Private Sub info_Changed(sender As Object, e As EventArgs) Handles Quantity.Changed, DiscountAmount.Changed
myFunction()
End Sub
Error:
Handles clause requires a WithEvents variable defined in the
containing type or one of its base types.
You need to declare the events in user control and then consume those. See below code. I have created a user control UserControl1. This control raises events when Price or DiscountAmount is changed. The usercontrol is then used in Form1. You can use the same approach to change the Quantity.
Public Class Form1
Private WithEvents userCntrl As New UserControl1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ChangeValues()
End Sub
Private Sub ChangeValues()
userCntrl.Price = 100
userCntrl.DiscountAmount = 12
End Sub
Private Sub userCntrl_Price_Changed(newValue As Decimal) Handles userCntrl.Price_Changed, userCntrl.DiscountAmount_Changed
MessageBox.Show("New value = " & newValue.ToString)
End Sub
End Class
Public Class UserControl1
Public Event Price_Changed(ByVal newValue As Decimal)
Public Event DiscountAmount_Changed(ByVal newValue As Decimal)
Public ItemName As String
Public Quantity As Integer
Private Price_ As Decimal
Public Property Price() As Decimal
Get
Return Price_
End Get
Set(ByVal value As Decimal)
If value <> Price_ Then
RaiseEvent Price_Changed(value)
End If
Price_ = value
End Set
End Property
Private DiscountAmount_ As Decimal
Public Property DiscountAmount() As Decimal
Get
Return DiscountAmount_
End Get
Set(ByVal value As Decimal)
If value <> DiscountAmount_ Then
RaiseEvent DiscountAmount_Changed(value)
End If
DiscountAmount_ = value
End Set
End Property
End Class
How to call the base functions in vb.net?
Imports System.Data.Sql
Imports System.Data.SqlClient
Public Class Box
Public length As Double ' Length of a box
Public breadth As Double ' Breadth of a box
Public height As Double ' Height of a box
Public function setLength(ByVal len As Double)
length = len
End Sub
Public Sub setBreadth(ByVal bre As Double)
breadth = bre
End Sub
Public Sub setHeight(ByVal hei As Double)
height = hei
End Sub
Public Function getVolume() As Double
Return length * breadth * height
End Function
End Class
It says syntax error when I use MyBase to call the base functions
Public Class myChild : Inherits Box
'box 1 specification
MyBase.setLength(6.0)
MyBase.setBreadth(7.0)
MyBase.setHeight(5.0)
'box 2 specification
MyBase.setLength(12.0)
MyBase.setBreadth(13.0)
MyBase.setHeight(10.0)
'volume of box 1
volume = MyBase.getVolume()
Console.WriteLine("Volume of Box1 : {0}", volume)
'volume of box 2
volume = MyBase.getVolume()
End Class
You can't call MyBase from there as the object hasn't yet been constructed.
A better implementation would be:
Box.vb
Public Class Box
Private mLength As Double ' Length of a box
Private mBreadth As Double ' Breadth of a box
Private mHeight As Double ' Height of a box
Public Sub New(ByVal length As Double, ByVal breadth As Double, ByVal height As Double)
Me.mLength = length
Me.mBreadth = breadth
Me.mHeight = height
End Sub
Public Property Length As Double
Get
Return Me.mLength
End Get
Set(ByVal value As Double)
Me.mLength = value
End Set
End Property
Public Property Breadth As Double
Get
Return Me.mBreadth
End Get
Set(ByVal value As Double)
Me.mBreadth = value
End Set
End Property
Public Property Height As Double
Get
Return Me.mHeight
End Get
Set(ByVal value As Double)
Me.mHeight = value
End Set
End Property
Public Function getVolume() As Double
Return Length * Breadth * Height
End Function
End Class
Child.vb
Public Class Child : Inherits Box
Public Sub New(ByVal length As Double, ByVal breadth As Double, ByVal height As Double)
MyBase.New(length, breadth, height)
End Sub
End Class
Example
Sub Main()
Dim box1 As New Child(6.0, 7.0, 5.0)
Dim box2 As New Child(12.0, 13.0, 10.0)
Console.WriteLine("box1 volume is: {0}", box1.getVolume())
Console.WriteLine("box2 volume is: {0}", box2.getVolume())
End Sub
Is it possible (using COM and regasm.exe) to have a vba function call a vb.net function - which creates the class in vb.net and then passes the class back to vba, where it is recognised as a vba class?
In VBA, I can work with classes by using Insert>Class Module. I have set up a function that creates a class.
Private length As Double
Private height As Double
Public Sub init(ByRef hgt As Double)
height = hgt
length = dbl_height()
End Sub
Public Function dbl_height()
dbl_height = height * 2
End Function
I can initialize it accordingly using this function:
Public Function CreateClassFunction(foo As Integer)
Dim my_rect As Rectangle
Set my_rect = New Rectangle
my_rect.init (foo)
Set CreateClassFunction = my_rect
End Function
I can also do the same thing in vb.net with virtually identical code.
Public Class Rectangle
Private length As Double
Private height As Double
Public Sub init(ByRef hgt As Double)
height = hgt
length = dbl_height()
End Sub
Public Function dbl_height()
dbl_height = height * 2
End Function
End Class
where this vb.net function creates the class:
Public Function CreateClassFunction(foo As Integer) As Rectangle
Dim my_rect As Rectangle
my_rect = New Rectangle
my_rect.init(foo)
CreateClassFunction = my_rect
End Function
I can pull in a Variant/Object/Rectangle into vba using:
Function MyCreateClass(a As Double)
Dim classLib As New MyAnalytics.Class1
Set MyCreateClass = classLib.CreateClassFunction(a)
End Function
However this object does not have the height or length variables. (It says "no variables" on the watch window)
Edit:
Amended code as per Mat's Mug answer:
Public Class Rectangle
Private plength As Double
Private pheight As Double
Public Property length() As Double
Get
Return plength
End Get
Set(ByVal value As Double)
plength = value
End Set
End Property
Public Property height() As Double
Get
Return pheight
End Get
Set(ByVal value As Double)
pheight = value
End Set
End Property
Public Sub init(ByRef hgt As Double)
height = hgt
length = dbl_height()
End Sub
Public Function dbl_height()
dbl_height = height * 2
End Function
End Class
and testing in VBA:
Function MyCreateClass(a As Double)
Dim classLib As New MyAnalytics.Class1
Set MyCreateClass = classLib.CreateClassFunction(a)
Debug.Print MyCreateClass.Height()
Debug.Print MyCreateClass.length()
MyCreateClass.Height = 30
MyCreateClass.length = 20
Debug.Print MyCreateClass.Height()
Debug.Print MyCreateClass.length()
MyCreateClass.init (100)
Debug.Print MyCreateClass.Height()
Debug.Print MyCreateClass.length()
End Function
It won't be recognized as a VBA class - it's not a VBA class, but a COM object.
Your Rectangle class has private fields. Private fields are, well, Private. This is, roughly, what VBA sees:
Public Class Rectangle
Sub init(ByRef hgt As Double)
Function dbl_height()
End Class
Where are the fields?
Private length As Double
Private height As Double
You haven't exposed them - as far as VBA goes, they don't exist.
Now, you could make them Public - but then you would be breaking encapsulation by exposing fields; don't do that!
Expose property getters instead, and setters if you want VBA code to be able to change the Length and Height properties of a Rectangle instance.
I am working on a payroll program. The first base class is bonus the class should contain 2 public properties salesid and sales.
Include a default constructor and a parameeterized constructor in the class.Also include a a getbonus method(function) that calculates a salespersons bonus using the formula sales*0.05
create a derived class named Premiumbonus the derived clas getbonus mothod calculate the bonus as follows sales0.05 +(sales-2500)).01 also include a default and parameterized constructorin this derived class.
if the sales is over 2500 use this
I feel like my math is off can someone please double check it? I need some suggestions and also i tried to debug and getbonus seems like it stays on 0 no matter what number i put but I get results in the calculated box.
below is the code
Option Explicit On
Option Strict On
Option Infer Off
' base class
Public Class Bonus
Public Property SalesId As String
Public Property Sales As Double
Public Sub New()
_Sales = 0
_SalesId = String.Empty
End Sub
Public Sub New(ByVal dblB As Double,
ByVal strId As String)
_Sales = dblB
_SalesId = strId
End Sub
Public Overridable Function GetBonus() As Double
' returns sales
Return _Sales * 0.05
End Function
End Class
' derived class
Public Class PremiumBonus
Inherits Bonus
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal dblB As Double,
ByVal strId As String)
MyBase.New(dblB, strId)
End Sub
Public Overrides Function GetBonus() As Double
Return MyBase.GetBonus + (Sales - 2500) * 0.01
End Function
End Class
Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
' calculates and displays a bonus
Dim myBonus As New Bonus
Dim myPremiumBonus As New PremiumBonus
Dim Sales As Double
' if the sales are over $2500, instantiate a PremiumBonus object
' and then calculate the bonus
' otherwise, instantiate a Bonus object and then calculate the bonus
If Sales > 2500 Then
Double.TryParse(txtSales.Text, myBonus.Sales)
Sales = myBonus.GetBonus
Else
Double.TryParse(txtSales.Text, myPremiumBonus.Sales)
Sales = myPremiumBonus.GetBonus
End If
Based on your title:
Payroll program not displaying correct amount results
and part of your description:
getbonus seems like it stays on 0 no matter what number i put but I get results in the calculated box
I am pretty certain your question is "My output is zero regardless of input. What's wrong?"
I see in your code:
Dim Sales As Double
If Sales > 2500 Then
Double.TryParse(txtSales.Text, myBonus.Sales)
Sales = myBonus.GetBonus
You should probably look at populating Sales with a value prior to evaluating it, and it's probably a good idea not to use the same variable name in so many places, as it makes your code more difficult to read. You might try something like this:
Dim myNewBonus As Double
Dim Sales As Double
Double.TryParse(txtSales.Text, Sales)
If Sales > 2500 Then
myBonus.Sales = Sales
myNewBonus = myBonus.GetBonus()
Any if that still fails try using the debugger, or at least some strategically placed MessageBox.Show(someValueIShouldCheck.ToString)'s
thanks anyway I fixed it I had the bonuses in the wrong spots
Public Class Bonus
Public Property SalesId As String
Public Property Sales As Double
Public Sub New()
_Sales = 0
_SalesId = String.Empty
End Sub
Public Sub New(ByVal dblB As Double,
ByVal strId As String)
_Sales = dblB
_SalesId = strId
End Sub
Public Overridable Function GetBonus() As Double
' returns sales
Return _Sales * 0.05
End Function
End Class
' derived class
Public Class PremiumBonus
Inherits Bonus
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal dblB As Double,
ByVal strId As String)
MyBase.New(dblB, strId)
End Sub
Public Overrides Function GetBonus() As Double
Return MyBase.GetBonus + (Sales - 2500) * 0.01
End Function
End Class
Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
' calculates and displays a bonus
Dim myBonus As New Bonus
Dim myPremiumBonus As New PremiumBonus
Dim Sales As Double
' if the sales are over $2500, instantiate a PremiumBonus object
' and then calculate the bonus
' otherwise, instantiate a Bonus object and then calculate the bonus
If Val(txtSales.Text) > 2500 Then
Double.TryParse(txtSales.Text, myPremiumBonus.Sales)
Sales = myPremiumBonus.GetBonus
Else
Double.TryParse(txtSales.Text, myBonus.Sales)
Sales = myBonus.GetBonus()
End If
I'm new to programming, OOP and Unit Test so please forgive me for my lack of knowledge.
As part of my Rock, Paper and Scissors game I have a abstract superclass (Weapon) which has subclasses (Rock, Paper and Scissors) in VB.NET like:
Public MustInherit Class Weapons
Public MustOverride Function compareTo(ByVal Weapons As Object) As Integer
End Class
Public Class Paper
Inherits Weapons
Public Overrides Function compareTo(ByVal Weapons As Object) As Integer
If TypeOf Weapons Is Paper Then
Return 0
ElseIf TypeOf Weapons Is Rock Then
Return 1
Else
Return -1
End If
End Function
End Class
Public Class Rock
Inherits Weapons
Public Overrides Function compareTo(ByVal Weapons As Object) As Integer
If TypeOf Weapons Is Rock Then
Return 0
ElseIf TypeOf Weapons Is Scissors Then
Return 1
Else
Return -1
End If
End Function
End Class
Public Class Scissors
Inherits Weapons
Public Overrides Function compareTo(ByVal Weapons As Object) As Integer
If TypeOf Weapons Is Scissors Then
Return 0
ElseIf TypeOf Weapons Is Paper Then
Return 1
Else
Return -1
End If
End Function
End Class
Also have a superclass Player which has subclasses (PlayerComputerRandom, PlayerHumanPlayer and PlayerComputerTactical) like:
Imports RockPaperScissors.Weapons
Public Class Player
Private pName As String
Private pNumberOfGamesWon As String
Public pWeapon As Weapons
Property Name() As String
Get
Return pName
End Get
Set(ByVal value As String)
pName = value
End Set
End Property
Property NumberOfGamesWon As String
Get
Return pNumberOfGamesWon
End Get
Set(ByVal value As String)
pNumberOfGamesWon = value
End Set
End Property
Property getWeapon As Weapons
Get
Return pWeapon
End Get
Set(ByVal value As Weapons)
pWeapon = value
End Set
End Property
Public Sub pickWeapon(ByVal WeaponType As String)
If WeaponType = "Rock" Then
pWeapon = New Rock()
ElseIf WeaponType = "Paper" Then
pWeapon = New Paper()
Else
pWeapon = New Scissors()
End If
End Sub
End Class
Imports RockPaperScissors.Weapons
Public Class PlayerComputerRandom
Inherits Player
Private Enum weaponsList
Rock
Paper
Scissors
End Enum
Public Overloads Sub pickWeapon()
Dim randomChoice = New Random()
Dim CompChoice As Integer = randomChoice.Next(0, [Enum].GetValues(GetType(weaponsList)).Length)
If CompChoice = "0" Then
pWeapon = New Rock()
ElseIf CompChoice = "1" Then
pWeapon = New Paper()
Else
pWeapon = New Scissors()
End If
End Sub
End Class
Public Class PlayerComputerTactical
Inherits Player
Private plastMove As String
Property lastMove() As String
Get
Return plastMove
End Get
Set(ByVal value As String)
plastMove = value
End Set
End Property
Public Overloads Sub pickWeapon()
' Add tactical player functionality
End Sub
End Class
Public Class PlayerHumanPlayer
Inherits Player
End Class
I have the GameForm class which instantiates the objects and performs various other logic used for the front-end as shown below:
Public Class GameForm
Private Sub btnRock_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRock.Click
findWinner("HumanPlayer", "Rock", "RandomComputer")
End Sub
Private Sub btnPaper_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPaper.Click
findWinner("HumanPlayer", "Paper", "RandomComputer")
End Sub
Private Sub btnScissors_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnScissors.Click
findWinner("HumanPlayer", "Scissors", "RandomComputer")
End Sub
Public Sub findWinner(ByVal p1name As String, ByVal p1WeaponSelected As String, ByVal p2Name As String)
Dim player1 = New PlayerHumanPlayer()
Dim player2 = New PlayerComputerRandom()
player1.Name = p1name
player1.pickWeapon(p1WeaponSelected) ' Should I be using the Rock Class???
player2.Name = p2Name
player2.pickWeapon()
Dim winner As Integer = player1.getWeapon().compareTo(player2.getWeapon())
Select Case winner
Case 1
txtGameStatus.Text = player1.Name() + " wins!"
Case -1
txtGameStatus.Text = player2.Name() + " wins!"
Case 0
txtGameStatus.Text = "Draw!"
End Select
End Sub
End Class
I need to write unit tests of this using visual studio 2010. As I have never done this, I don't know what unit tests I could include (apart from the stand adding/substract examples). Could someone kindly provide a few unit tests to get started. It will give me a starting point.
Any help would be greatly appreciated.
Manys thanks in advance
My first tip would be to change all of your methods into functions which return a value, this is for the methods you want to unit test. Doing this will ensure that you can use the function for a unit test.
I can give you help for the structure, but I'm afraid I wont be doing your unit tests for you!
Ill show you an example unit test which I have in a solution, it may not be relevant to your solution but the structure is there nevertheless. First off I have the function (add) which i would like to test, and in a unit test project i have the test.
Function to test
Public Function Add(value1 As Int32, value2 As Int32)
answer = value1 + value2
Return answer
End Function
This is the unit test I am using within my unit test class
<TestMethod()> _
Public Sub AddTest()
Dim target As Form1 = New Form1()
Dim value1 As Int32 = 10
Dim value2 As Int32 = 35
Dim actual As Int32 = 45
Dim result As Int32 = target.Add(value1, value2)
Assert.AreEqual(result, actual)
End Sub
To try to give you an example of how you might structure this:
First of all, instead of this:
Public Overloads Sub pickWeapon()
' Logic...
End Sub
You might want to do something like this:
Public Overloads Function pickWeapon() as Weapons
Dim selectedWeapon as Weapons = Nothing;
// logic to set weapon here
return selectedWeapon;
End Sub
Now you can call that from a UnitTest, and make sure it returns an object which is a valid Weapon, for instance (not necessarily the most useful test, but hopefully, you get the point! :) ).
If your restructure the method findWinner() in a similar way, you can test that the logic of that method finds the correct winner.
Note however, that you should separate the logic for finding a winner from the weapon-picking. That is, you should create the players outside of that method, and pass them in to findWinner(). This will let you pass in certain options (weapons), and check that you get the expected result. You can't do that at the moment, since the weapon "player2" will use is selected by random inside findWinner().
Start by changing it so it will have a signature similar to the following:
' Takes two players in, and returns the name of the winner
Public Sub findWinner(ByVal humanPlayer As PlayerHumanPlayer,
ByVal computerPlayer As PlayerComputerRandom) As String
A (very simple) test, assuming you've rewritten the code to fit this:
<TestMethod()> _
Public Sub ShouldReturnPlayer1AsWinner()
Dim player1 = New PlayerHumanPlayer("Human name", New Scissors())
Dim player2 = New PlayerComputerRandom("Computer", New Rock())
Dim result As String = findWinner(player1, player2)
Assert.AreEqual(result, "Computer")
End Sub
Again, this may not be the be the best test, but it should give you an idea, and help you get started.
Sidenote: I would call the super-class Weapon, not Weapons. Think of it this way: You can have many many different instances of it, and they can be different weapons (paper, scissor, etc), but each is still a single weapon.