I have some code where I am trying to use variables in a tabpage. The first tabpage only has one text box for user entry (miles.text) and a button to do a calculation: traveltime = mileage/speed. The value from miles.text is stored into a variable called mileage while the speed used is stored in a variable called speed (me.speedtextbox.text).
Ordinarily, doing val(variable.text) works like a charm and it's not doing it in this case. When the user enters 100 for the mileage, it should be divided by 65 (the number in the database) and, therefore, the answer should be 1.53 hours. In my case, I'm getting "infinity" and whenever I do anything else with the variable, I get "when casting from a number, the value must be a number less than infinity." But it is! It's only 65 and I double-checked that the dataset said that too, which it does. Not sure why I am getting this error...thank you!
Public Class Form1
Private Property Traveltime As Decimal
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'fooDataSet.testdata' table. You can move, or remove it, as needed.
Me.TestdataTableAdapter.Fill(Me.foouDataSet.testdata)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim mileage As Integer
Dim speed As Integer
mileage = Val(miles.Text)
speed = Val(Me.SpeedTextBox.Text)
traveltime = mileage / speed
txttraveltime.text = Traveltime.ToString
End Sub
Private Sub txtrate_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txttraveltime.TextChanged
End Sub
End Class
So I did a test program where it did only one thing and that was to simply read one data column in a one row database and store it to a local variable and multiply it by 1.60 except now I am getting "reference to a non-shared member requires an object reference" and it doesn't seem to recognize Me.Speed when I declare it. What am I doing wrong?
Public Class Form1
Dim Speed As Object
Dim Me.Speed As New Speed
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.Speed = CDec(fooDataSet.testdataRow.Item("speed"))*1.60
Speedtextbox.text = Me.Speed.tostring
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'fooDataSet.testdata' table. You can move, or remove it, as needed.
Me.TestdataTableAdapter.Fill(Me.fooDataSet.testdata)
End Sub
End Class
Before you do anything else, you should do the following:
Open the project's properties (right-click on the Project, then select Properties)
Click on the Compile tab (left-hand side)
Select All Configurations from the dropdown menu
Select On from the Option Explicit menu.
Select On from the Option Strict menu.
Save the project
This will more than likely cause a lot of errors to be displayed, but fixing these errors will substantially improve your application's health.
Now, that that is done, the following code will fix the problems in the button click:
Dim mileage As Integer
Dim speed As Integer
If IsNumeric(Me.Miles.Text) Then
mileage = CInt(Me.Miles.Text)
End If
If IsNumeric(Me.SpeedTextBox.Text) Then
speed = CInt(Me.SpeedTextBox.Text)
End If
If speed <> 0 Then
Traveltime = CDec(mileage / speed)
Else
Traveltime = 0
End If
txtTravelTime.Text = Traveltime.ToString
However, the code as you have it will produce correct results, so there must be something else amiss. Try the above first and if there are still issues, you can update your question with the details.
I would implement the calculation in a separate class and then use object-binding. Here is how the travel time calculator would look like:
Imports System.ComponentModel
Public Class TraveltimeCalculator
Implements INotifyPropertyChanged
Private _miles As Double
Public Property Miles() As Double
Get
Return _miles
End Get
Set(ByVal value As Double)
If _miles <> value Then
_miles = value
OnPropertyChanged("Miles")
OnPropertyChanged("Traveltime")
End If
End Set
End Property
Private _speed As Double
Public Property Speed() As Double
Get
Return _speed
End Get
Set(ByVal value As Double)
If _speed <> value Then
_speed = value
OnPropertyChanged("Speed")
OnPropertyChanged("Traveltime")
End If
End Set
End Property
Public ReadOnly Property Traveltime() As Double
Get
Return If(_speed = 0.0, 0.0, _miles / _speed)
End Get
End Property
#Region "INotifyPropertyChanged Members"
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Private Sub OnPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
#End Region
End Class
In Visual Studio, add a data source in the Data Sources panel. Choose "Object" and then select the TraveltimeCalculator (it has to be compiled, before you can do that). Now you can drag the speed, mileage and travel time fields from the data sources panel to your form. All the wire-up will happen automatically. VS automatically inserts a BindingSource and a navigator into your form. You will not need the navigator and can safely remove it. The only thing you still have to do is to add the following code in the form load event handler or in the form constructor:
Private Sub frmTravelTime_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
TraveltimeCalculatorBindingSource.DataSource = New TraveltimeCalculator()
End Sub
When you enter speeds and mileages, the travel time textbox will automatically be updated. Non-numeric entries will automatically be rejected and all the text-number conversions happen automatically.
I discovered what the problem was.
To store a field from a one-line database to a local variable for calculations, apparently it has to happen in the form1_load event, after the dataadapter fill statement, like so:
Me.TestdataTableAdapter.Fill(Me.foouDataSet.testdata)
speed = Me.fooDataSet.testdata(0).speed
and just DIM speed as Decimal after the Public Class line. The same could be done for any other field you want to work with in a similar kind of single datarow:
yourvarname = Me.yourdatasetname.yourtablename(0).the_database_field_you_want_to_fetch
(Wow! Did I just write something textbooky? LOL)
Then, after the button click, to do a calculation, it is:
traveltime = CDec(miles.Text/ speed)
txttraveltime.Text = traveltime.ToString
making sure to DIM traveltime as Decimal.
Works! The problem was the (0) to indicate row 0 (because it's only one row.) Thank you everyone for your help, especially Competent_Tech. I learned something and I'm happy that I could get back to you guys and share.
Related
So i am currently in process of adding a basic calculator that allows the user to define 2 variables and then press a button that puts the variables into a basic math equation and presents the result but i think i have gone about it completely wrong.
this is my first time using math functions in VB and would appreciate it if someone can show me where im going wrong.
this is my code so far:
Imports System.Math
Public Class SOGACALC
Dim soga As String = Math.Abs(72 - months.Text) * opp.Text
Private Sub SOGACALC_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SOGAValue.Text = soga
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
HOME.Show()
Me.Close()
End Sub
End Class
Where you have written
Dim soga As String = Math.Abs(72 - months.Text) * opp.Text
I suspect that you are anticipating that soga will be a function of the properties referred to in that and will change when those properties change. It does not work that way.
The way to get a value which varies depending on its parameters is to define a function, so you might have:
Friend Function Soga(monthValue As Control, oppThing As Control) As String
Dim month As Integer = CInt(monthValue.Text)
Dim opp As Decimal = CDec(oppThing.Text)
Return (Math.Abs(72 - month) * opp).ToString()
End Function
and call it like:
'TODO: Give Button1 a meaningful name.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SOGAValue.Text = Soga(months, opp)
End Sub
where there are controls names "months" and "opp" on the form.
I strongly recommnend that you use Option Strict On - it points out problems in code and suggests corrections for you.
Notice that I used the Decimal type for opp - I had to guess at a suitable type because nowhere in the code you showed us was there any indication of what type it needs to be.
An improvement would be to use TryParse methods instead of CInt/CDec, so that you can inform the user if they have made a simple typing error.
This is my first time using visual studio and I'm running into an error with my tax calulator application.
The problem is that visual studio is saying that the multiplication line using "*" and "+" can not be done due to the variables being text boxes. So my question to the community, is should I change the text box to something else? Or where in my code did I mess up.
Public Class Form1
Private Sub btnCalc_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalc.Click
If (IsNumeric(txtSale) And IsNumeric(txtSalesTaxRate)) Then
lblTax = txtSale * txtSalesTaxRate
lblTotal = txtSale + lblTax
Else
MsgBox("Please enter valid numbers, thank you!")
End If
End Sub
End Class
If you need me to give you the full layout of my application, do ask.
I can see multiple problems in your code. I will explain how the "vs" works.The textboxes that you've made are controls.You can't just take their value so simple.They have many property and one of them is .text which allows you to take the value inside them.Another mistake you've made is what you've tried to do with the textboxes.What you type in those textboxes is ..well text. The program can't tell if the value inside is a number or just text. You must convert that value in a number using Cint.So you're code will look like this:
Public Class Form1
Private Sub btnCalc_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalc.Click
If (IsNumeric(txtSale.text) And IsNumeric(txtSalesTaxRate.text)) Then
lblTax.text= cint(txtSale.text) * cint(txtSalesTaxRate.text)
lblTotal.text= cint(txtSale.text) + cint(lblTax.text)
Else
MsgBox("Please enter valid numbers, thank you!")
End If
End Sub
End Class
What cint does is to convert every type of data to integer. Also the .text property lets you to set the value of the control (in our case the label caption)
I tried Electric-web's code and ran into a problem with the output. I changed "CInt" to "CDbl" and the tax calculator worked.
Public Class Form1
Private Sub btnCalc_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalc.Click
If (IsNumeric(txtSale.text) And IsNumeric(txtSalesTaxRate.text)) Then
lblTax.text= cdbl(txtSale.text) * cdbl(txtSalesTaxRate.text)
lblTotal.text= cdbl(txtSale.text) + cdbl(lblTax.text)
Else
MsgBox("Please enter valid numbers, thank you!")
End If
End Sub
End Class
In my main program (form) I have two list boxes, one text box, and a button.
When I pick two items in each list boxes and enter a number in the text box, it is suppsoed to be stocked in an array. I wanted to do this using a class. (I just asked a question about this, it works well now). The problem is I want to show the results in a different form.
The code in my class looks like this:
Public Class Stocking
Public sale(3, 4) As Integer
Public numberSellers(3) As Integer
Public 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()
For sellerLineInteger = 0 To 3
For productColumnInteger = 0 To 4
numberSellers(sellerLineInteger) += sale(sellerLineInteger, productColumnInteger)
Next productColumnInteger
Next sellerLineInteger
End Sub
Public Sub showItems(ByRef my_label)
my_label.Text = numberSellers(0).ToString 'using this as a test to see if it works for now
End Sub
End Class
My main form looks like this:
Public Class showForm
Public sale(3, 4) As Integer
Public numberSellers(3) As Integer
Public numberProducts(4) As Integer
Dim StockClass As New Stocking
Public Sub addButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles addButton.Click
StockClass.addItem(sellerListBox, producttListBox, saleTextBox)
End Sub
Public Sub SalesByMonthToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SalesByMonthToolStripMenuItem.Click
saleForm.Show()
And in my second form, to show the results stocked in the array is:
Public Class saleForm
Dim StockClass As New Stocking
Public Sub saleForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
StockClass.showItems(Label00)
'Only using one label as a test for now.
End Sub
End Class
End Sub
I tested it and tried to see if the results shows on the main form, it does. So I'm guessing the problem is because I use a different form. Also I think it might be because I call the class again in my different form and doesn't keep the data.
The problem is that your saleForm is instantiating a new Stocking object. You need to send the Stocking object that is created in your primary form to the new form, during the creation of saleForm, or you need to make the Stocking object in your main form publically available, perhaps through a property.
So, in your main form, you might have something like this:
Public StockClass As New Stocking
then, because it's not protected as a private variable, you could access it from your secondary form through something like
showForm.StockClass.showItems(Label00)
The danger, of course, is that this tightly binds the two forms together. It would be better, in the long run, to learn how to send the StockClass that is populated in the first form to the second form during initialization, but I don't remember enough on WinForms development to help with that, sorry.
I am new to Visual Basic. I have installed Microsoft Visual Studio 2010. Created a new Windows Form Application. As an example, I made a simple program which will ask the end user to input 2 numbers and allow them to either add them or subtract the second number from the first one and display the output in a Textbox.
Now, I added another Subroutine which would be executed automatically when the Windows Form loads. This would calculate the width of the output Textbox and the Form Width and display at the bottom.
This is how the code looks like right now:
Public Class Form1
' Run this Subroutine initially to display the Form and Text box width
Private Sub Form_Load()
Label5.Text = TextBox3.Width
Label7.Text = Me.Width
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim a As Integer
Dim b As Integer
a = TextBox1.Text
b = TextBox2.Text
TextBox3.Text = a + b
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim a As Integer
Dim b As Integer
a = TextBox1.Text
b = TextBox2.Text
TextBox3.Text = a - b
End Sub
End Class
While everything works correctly for the addition and subtraction, it does not display the Form and output Textbox width in the Windows Form.
I think, Form_Load() is not executing properly.
I also tried, Form_Activate() but that did not work either.
Once I am able to do this, I would like to extend this concept to resize the output Textbox along with the Form resize. However, for the purpose of understanding I wanted to see if I can execute Form_Load() successfully.
Thanks.
Form_Load doesn’t execute. For now, it’s just any other method. In order to tell VB to make this method handle the Load event, you need to tell it so:
Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Loasd
Label5.Text = TextBox3.Width
Label7.Text = Me.Width
End Sub
(And add the required parameters for the event.)
A few other remarks:
Ensure that Option Strict On is enabled in your project options at all times. This will make the compiler much stricter with your code and flag more errors. This is a good thing since these errors are potential bugs. In particular, your code is very lax with conversions between different data types, these should be made explicit.
Initialise variables when you declare them, don’t assign a value in a separate statement. That is, write this:
Dim a As Integer = Integer.Parse(TextBox1.Text)
(Explicit conversion added as well.)
If you want to make a control fill the form, you can just set its Dock property appropriately in the forms editor, instead of having to program this manually.
You need to add the Handle so the app executes it automatically:
Private Sub Form_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
'...
End Sub
When I load the form where some text has been given to text box. All the text in that textbox is highlighted. I want vb not to load it this way.
How to fix it.
Thanks
Furqna
You could set the tab index on your textbox to something else so that it's not the lowest index.
You could set the TextBox1.SelectionLength = 0 in the form.activated event.
I don't like this as much because if the user had the text hilited and minized the application then they will lose the hilite, but is fairly easy to do. I guess you could use a flag to make sure it only did it on the first activate.
You could set a timer event in the load to clear it immediately after the load event, but that seems like overkill. I have worked at places where they had a standard function that happened on every form 100 ms after load because of problems such as this.
You could try this(it looks like a workaround):
Private Sub TextBox1_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.GotFocus
TextBox1.SelectionStart = TextBox1.Text.Length
End Sub
It depends on the TabIndex of your TextBox, if it has the lowest TabIndex it gets focus and therefore it's Text is selected.
' VS.net 2013. Use the "Shown" event.
' GotFocus isn't soon enough.
Private Sub Form_Shown(sender As Object, e As EventArgs) Handles Me.Shown
TB.SelectionLength = 0
End Sub
Type 1 Method
Dim speech = CreateObject("sapi.spvoice")
speech.speak(TextBox1.Text)
Type 2 Method
Dim oVoice As New SpeechLib.SpVoice
Dim cpFileStream As New SpeechLib.SpFileStream
'Set the voice type male or female and etc
oVoice.Voice = oVoice.GetVoices.Item(0)
'Set the voice volume
oVoice.Volume = 100
'Set the text that will be read by computer
oVoice.Speak(TextBox1.Text, SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault)
oVoice = Nothing
Type 3 Method
Imports System.Speech.Synthesis
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim spk As New SpeechSynthesizer
For Each voice As InstalledVoice In spk.GetInstalledVoices
ListBox1.Items.Add(voice.VoiceInfo.Name)
Next
ListBox1.SelectedIndex = 0
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim spk As New SpeechSynthesizer
spk.SelectVoice(ListBox1.SelectedItem.ToString)
spk.Speak(TextBox1.Text)
End Sub
End Class
This will also happen sometimes if The TextChanged or other similar Event is fired twice for the control.
When creating each form. Each object is indexed you can set the tab Index higher then the indexed object. Example: On the third form you put a text box in.
private void textBox1_TextChanged(object sender, EventArgs e)
This was the 12th object in the project, it would be indexed at 12. if you put the tab index higher then the indexed objects throughout the project. Tab index 1000 (problem solved.)
Have a great day.
Scooter