I'm new to VB. Today I'm working on entering 4 prices for items to purchase using an input box. I need to create a counter in a loop. The only 2 buttons on the form "Enter Prices" and "Exit". So far this is the code I have (see below). I know something is off. When I run it, I'm allowed to enter 4 numbers. But at the end, when the message box comes up to show my total, it just gives me my last number I entered. I know I've got to change a few things, as I need my numbers to be in currency. Any suggestions as to where I need to go from here to get this up and running?
Private Sub btnPrices_Click(sender As Object, e As EventArgs) Handles btnPrices.Click
'Declare a variable as counter and accumulator
Dim intcount As Integer = 1I
Dim intAccumulator As Integer = 0I
'Declare and intialize variable
Dim strInput As String = ""
'Number of Items
Const intNUM_PRICES As Integer = 4
'Pre-test loop will keep iterating as long as the expression is ture.
Do While intcount <= intNUM_PRICES
'Get price of each item purchased
strInput = InputBox("Enter Price " & intcount, "Price Needed")
'Add 1 to the counter
intcount += 1
Loop
'Look at the value placed in the
MessageBox.Show("Your combined Price for all 4 items is: " & strInput)
End Sub
You've only got one variable for the input and each time you call InputBox you replace the previous value each time. If you want a total then you have to add the values, so you need to add the current input to the previous total each time, not replace it. Make sure that you convert the input to a number and use a numeric variable, because adding strings will actually join them, not add them mathematically.
Related
As the 2020 tax season approaches, I'm trying to create a simple macro in Word that will take a few user inputs and populate an email template relating to stimulus checks to send to my clients. The actual macro just opens an info box with spaces for three user inputs. Inside of that box, there is an 'OK' button and a 'Cancel' button. The cancel button just hides the box, and the OK button performs the following:
Private Sub CommandButton1_Click()
Dim taxpayerName As Range
Set taxpayerName = ActiveDocument.Bookmarks("tpName").Range
taxpayerName.Text = Me.TextBox1.Value
Dim numberOfDep As Range
Set numberOfDep = ActiveDocument.Bookmarks("numDep").Range
numberOfDep.Text = Me.TextBox3.Value
Dim numberOfDep1 As Integer
numberOfDep1 = Me.TextBox3.Value
Dim maritalStatus As Range
Set maritalStatus = ActiveDocument.Bookmarks("mStatus").Range
maritalStatus.Text = Me.TextBox2.Value
Dim maritalStatus1 As Range
Set maritalStatus1 = ActiveDocument.Bookmarks("mStatus1").Range
maritalStatus1.Text = Me.TextBox2.Value
Dim maritalStatus2 As Range
Set maritalStatus2 = ActiveDocument.Bookmarks("mStatus2").Range
maritalStatus2.Text = Me.TextBox2.Value
Me.Repaint
tpInfo.Hide
Dim amount1 As Integer
If maritalStatus = "single" Then
amount1 = 1200
Else
amount1 = 2400
End If
amount1 = ActiveDocument.Bookmarks("a1").Range
End Sub
I'm trying to check my maritalStatus variable for 'single' and assign amount1 a value of either 1200 or 2400 for the first round of stimulus payments. I then want to insert that value into the Word document at bookmark a1 that I've created. However, I currently get the runtime error 13 on the last line of my code.
My end goal is to take amount1 and add it to a new variable (depAmount1) that would multiply $500 by the number of dependents, which should be stored in numberOfDep1. So a single taxpayer with 1 child would result in a total of $1,700. Then I would repeat the code with minor tweaks for the second round of stimulus payments and finally add the two totals together for the grand total.
Thanks in advance, any help would be greatly appreciated.
If the core of your question is the error on your last line of code, I think you're probably getting it because you're trying to assign a string from your bookmark to the amount1 variable, which is specified as an Integer, and I think you want to do the opposite, put the value into the document. Reversing your line of code should do the trick.
ActiveDocument.Bookmarks("a1").Range = amount1
I'm having some trouble with catching duplicates in an assignment I'm working on.
The assignment is a track and field race manager. Times are read from a text file, a bib number is then entered for each time loaded from the text file (aka, however many rows there are in the time text file)
The bib numbers and times are then synced in the order from which they were entered. A requirement is that the Bib numbers must be entered one at a time using an input box. Every time a bib number is entered, it is loaded to a list box called lstBibs.
The Issue
I have limited experience working with input boxes, and any attempts Ive made so far to check for duplicates has been ignored in Runtime. I'm also unsure where I would put a loop that checks for duplicates in the input box. Below is my code so far.
Dim i As Integer = 0
Dim Bibno As Integer = 0
Dim strrow As String = ""
Dim count As Integer = 0
Dim errorCount1 As Integer = 0
'Reads through the number of rows in the Time Text File.
'The Number of rows we have in the text file corresponds to the number
'of bib numbers we need. Thus the input box will loop through bib
'numbers until
'we reach the amount of loaded times
Try
For Each item In lstTimeEntry.Items
i += 1
For Bibno = 1 To i
count += 1
Bibno = InputBox("Enter Bib #" & count)
lstBibs.Items.Add(count & " - " & Bibno)
btnSyncTimesBibs.Enabled = True
Next
Next
Catch ex As Exception
'Catches any invalid data that isnt a number
MsgBox("Invalid Input, Please Try Again", , "Error")
lstBibs.Items.Clear()
btnSyncTimesBibs.Enabled = False
End Try
So I'm assuming that I must use a for loop that checks each list box item for a duplicate, I'm just unsure where this loop would go in relation to the code above.
Any and all help is very much appreciated. Thank you.
Don't use exception handling for something that isn't exceptional. Exceptionsl things are things beyond our control like a network connection that isn't available. A user failing to enter proper input is not at all exceptional. Validate the input. Don't make the user start all over again by clearing the list, just ask him to re-enter the last input.
I validate the user input with a TryParse. If the first condition succeeds then the AndAlso condition is checked. It the TryParse fails then the AndAlso condition is never evaluated so we will not get an exception. The second condition is checking if the number has already been used. Only if both conditions pass do we add the number to the used numbers list, update the lstBibs and increment the count.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim Bibno As Integer
Dim count As Integer = 1
Dim usedNumbers As New List(Of Integer)
Do While count <= lstTimeEntry.Items.Count
Dim input = InputBox("Enter Bib #" & count)
If Integer.TryParse(input, Bibno) AndAlso Not usedNumbers.Contains(Bibno) Then
usedNumbers.Add(Bibno)
lstBibs.Items.Add(count & " - " & Bibno)
count += 1
Else
MessageBox.Show("Please enter a number that does not appear in the list box")
End If
Loop
End Sub
As per Steven B suggestion in the comments, you can check it like this:
If Not listTimeEntry.Items.Contains(itemToBeInserted) Then
listTimeEntry.Items.Add(itemToBeInserted)
End If
I've been messing around with VBA in Excel a bit recently; and as a small project for myself, I'm trying to create a "draw names from a hat" sort of macro.
I began by generating a random number, and then choosing which entry from a Table (i.e. ListObject) would be selected using a case statement. The problem with this is that it only works of the number of Table entries is always the same.
So my question (probably a ridiculous one) is: is it possible at all to generate a dynamic 'Select Case' block, where the number of cases on the block is based on the number of entries in the Table?
Thanks.
-Sean
Edit: To clarify: what I am trying to do, exactly, is this:
I generate a random number, i, from 1 to n=10*(number of Table entries). After this, I want to display, in a cell, one of the table entries based on the random number.
Ideally, the code would work similarly to this:
if i = 1 to 10 then choose event 1
if i = 11 to 20 then choose event 2
if i = 21 to 30 then choose event 3
...
if i = (n-9) to n then choose event (n/10)
I hope this helps to clarify the goal of the code.
From our comments here is something you can use:
Sub random()
Dim used_rows As Integer
Dim random As Integer
Dim cell_array() As Integer
used_rows = Sheet1.UsedRange.Rows.Count
ReDim cell_array(used_rows)
For i = 1 To used_rows
cell_array(i - 1) = Cells(i, 1)
Next
random = Int(Rnd * (used_rows))
MsgBox cell_array(random)
End Sub
You can go ahead and change MsgBox to whatever you like, or set like Cell(1,4).Value = cell_array(random), or however you'd like to proceed. It will be based off the number of rows used. Though depending on how you implement your spreadsheet the code might have to be changed a bit.
Here's the update code from the suggestions from the comments. Also remember to use Randomize() in your form initialization or WorkBook Open functions.
Sub random()
Dim used_rows As Integer
Dim random As Integer
'Multiple ways to get the row count, this is just a simple one which will work for most implementations
used_rows = Sheet1.UsedRange.Rows.Count
random = Int(Rnd * (used_rows))
'I use the variable only for the reason that you might want to reference it later
MsgBox Cells(random, 1)
End Sub
This assumes that by "table" you mean "Table with a capital T", known in VBA as a ListObject:
Sub PickRandomTens()
Dim lo As Excel.ListObject
Dim ListRowsCount As Long
Dim RandomNumber As Long
Dim ListEvent As String
Dim Tens As Long
Set lo = ActiveSheet.ListObjects(1)
ListRowsCount = lo.DataBodyRange.Rows.Count
RandomNumber = Application.WorksheetFunction.RandBetween(10, ListRowsCount * 10)
ListEvent = lo.ListColumns("Data Column").DataBodyRange.Cells(Int(RandomNumber / 10))
MsgBox "Random number: " & RandomNumber & vbCrLf & _
"Event: " & ListEvent
End Sub
I'm running a search query that pulls the search string from one text box, then searches a listbox for the string and displays the results in a second listbox. I would like to define the number of items that it returns based on a second text box. So far I am able to get all list items with be given string to show in the second box. But I have yet to get it to limit the search to 1 item etc. The functional code I've used to show all results is:
Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
lstResults.Items.Clear()
If txtSearch.Text.Length > 0 Then
For index As Integer = 0 To lstCountries.Items.Count - 1
Dim txt = lstCountries.Items(index).ToString()
If txt.StartsWith(txtSearch.Text, StringComparison.CurrentCultureIgnoreCase) Then
lstResults.Items.Add(txt)
End If
Next
End If
I've tried using while txtnumber.text > 1 then ahead of this but seem to have created a loop. Any ideas as to what I'm missing?
The datasource is going to have the final say on how many results there are. If the user specifies 3 and there are only 2 in the source, thats all you will get. Something like this will move the results from one to the other until the max is found:
Dim Max as integer = Convert.Toint32(txtNumber.Text)
Dim Count as integer = 0
lstResults.Items.Clear()
For index As Integer = 0 To lstCountries.Items.Count - 1
if lstCountries.Items(index).StartsWith(txtSearch.Text, StringComparison.CurrentCultureIgnoreCase) Then
lstResults.Items.Add(lstCountries.Items(index))
count += 1
end if
' exit the loop if we found enough
If count>= Max Then
Exit For
End If
Next
If the listbox just contains text (strings) then you do not need the ToString: lstCountries.Items(index).StartsWith(strSearch). Basically, you need to exit the loop once the user desired number have been found OR if you run out of data...if I understood right. while txtnumber.text > 1 would not work because textboxes contain strings not numerics (23 is not the same as "23").
The LINQ extensions would work well here as well:
lstResults.Items.AddRange((From item In lstCountries.Items
Let strItem As String = item.ToString
Where strItem.StartsWith(txtSearch.Text, StringComparison.CurrentCultureIgnoreCase)
Select strItem).Take(Integer.Parse(txtnumber.Text)).ToArray)
This assumes that all your data has already been validated.
Trying to get the user to put 3 numbers in 3 text boxes and get the average.
Private Sub btnAverage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAverage.Click
Dim a As Integer = CInt(txtone.Text)
Dim b As Integer = CInt(txtTwo.Text)
Dim c As Integer = CInt(txtThree.Text)
Dim average As Integer
average = (a + b + c) / 3
lstOutput.Text = average
End Sub
Try changing the type of average from Integer to Double
Dim average as Double
Right now you're trying to store the Average in an Integer which can only hold a whole number. Averages tend to be non-whole numbers and need a data type that can represent that. Double is good for most situations. That should fix your problem.
EDIT OP mentioned that lstOutput is a ListBox
This is one of the confusing things with WinForms. Even though every single control has a Text property, not all of them actually do anything. They only apply to elements that directly display a single text block or value. Ex Button, Label, etc ...
A ListBox on the other hand displays a group of items. You want to add a new item to the list.
lstOutput.Items.Add(average.ToString())
The Text property of a list box will get or set the selected item. You haven't added your average to the listbox yet.
Try:
lstOutput.Items.Add(average)
Are you sure that txtOne.text txtTwo.text and txtThree.txt will always be an integer value?
You might need to also change the a,b,c vars to Doubles and check that the user didn't supply non-numeric values.
If the user puts "one" in the txtOne textbox, you'll get an exception kablowee.
(air coding here)
dim a as new double
try
if isnumeric(txtOne.text.tostring.trim) then
a = cdbl(txtOne.text.tostring.trim)
end if
'repeat for b and c ...
catch ex as exception
messagebox.show(ex.message.tostring)
end try
And, I'm not sure if I'm right about this, (maybe someone will enlighten me) but does .NET consider type conversion from string to int differently in these two cases
a = cint(txtOne.text)
and
a = cint(txtOne.text.tostring)
???