Performing calculations with random numbers - vba

I am trying to make a maths practice powerpoint where students are presented with random addition problems using numbers 1 – 20. I have been working through tutorials by David Marcovtiz (and others) and was using his code as a starting point. As my audience is young students, I would like the maths problems to not be in a message box but in something like text boxes or shapes that I can customise and make large and visually appealing for young students.
So, what I'm wanting to do...
In a powerpoint show
Student can click a ‘get started’ button that takes them to next slide
Next slide automatically generates 2 random numbers that student must add together.
Student enters the answer
If answer is correct – I would like something to signify the answer was correct but not something they have to click on to close. Ideally, a little star flashes in the corner then disappears
If the answer is incorrect, a message or picture flashes then disappears.
A new addition problem is automatically/randomly generated
I would like to set the number of addition problems to e.g. 20, then have the slide move to a scoring slide that shows their score in pictures e.g. a star for every correct answer.
Update:
Using Activex text Boxes:
I have had success with activex text boxes in being able to randomly show two numbers and have them multiply and show the answer in a third activex text box, which I hid off the slide. I used a fourth as an input box for students to type in their answer. If this is the same as the answer in the third box, I can show a star and clear the boxes then move to the next slide. If it's not the same, I can go show another picture then move to the next slide. (I originally wanted the slide to update and use one slide to ask 20 questions but was finding this difficult.)
At present, this requires clicking three command buttons.
What I have managed so far (I know it will seem quite sad to you and possibly unstable, but a major achievement for me and the 'bits' are working) I can manage it for multiplication but when I + the values e.g. 9 + 3, I get 93
Private Sub CommandButton1_Click()
TextBox1.Value = Int(10 * Rnd)
TextBox2.Value = Int(10 * Rnd)
TextBox3.Value = TextBox1.Value * TextBox2.Value
End Sub
Private Sub CommandButton2_Click()
If TextBox4.Value = TextBox3.Value Then
ActivePresentation.Slides("problem").Shapes("badge5").Visible = True
ActivePresentation.Slides("score").Shapes("badge5").Visible = True
Else
ActivePresentation.Slides("problem" _).Shapes("incorrect").Visible = True
TextBox1.Value = ""
TextBox2.Value = ""
TextBox3.Value = ""
TextBox4.Value = ""
End If
End Sub
Private Sub CommandButton3_Click()
SlideShowWindows(1).View.Next
End Sub
What I need
I would like the random numbers in command button 1 to activate automatically.
I would like to combine command button 2 and 3 and include a wait time after the star or incorrect shapes appear before moving to the next slide but the code I have found applies the wait time to the whole sequence as I'm not sure how to include it.
Private Sub Time_Click()
iTime = 2#
Start = Timer
While Timer < Start + iTime
Wend
With SlideShowWindows(1).View.Next
End With
End Sub
Using Shapes:
I would prefer to work with ordinary text boxes or shapes but...
I have managed to produce random numbers in shapes but haven't been able to multiply them and have students type into an activex text box that determines whether it is correct or incorrect yet. I think the problem is in trying to use both shapes and an activex textbox.
I would like to use shapes because I would like to create master slide layouts that can be selected using the following code - though this isn't a deal breaker.
Sub background()
ActivePresentation.Slides.Range(Array(2, 3, 4, 5)).CustomLayout_
= ActivePresentation.Designs(1).SlideMaster.CustomLayouts(6)
End Sub
I feel this is something that other educators could use and am happy to post my finished show if someone is willing and able to assist with the coding. I really appreciate the tolerance and patience of contributors shown to people like myself who have jumped in head first, excited and giving it a go but struggling.

So, to break down the pieces you requested in the "What I Need" section, I will split my answer into two sections:
"I would like the random numbers in command button 1 to activate automatically."
I assume what you mean by "automatically" is that you would like the "next" slide to automatically be populated with values after the user answers the question on the previous slide. To accomplish this functionality, I would call the method that the CommandButton1 currently calls after all the logic in the CommandButton2 has been run.
"I would like to combine command button 2 and 3 and include a wait time after the star or incorrect shapes appear before moving to the next slide..."
I would simply combine the code of the two functions with a wait function in between the two bits of code. I'm not sure where you found the code you posted for the "Timer_Click" function, I don't think that would work as currently posted. I would typically use the method of "wait" mentioned in this answer.
The result, after changing the code for the two new requirements would be something like this:
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Sub CommandButton2_Click()
'Command Button 2(code)
If TextBox4.value = TextBox3.value Then
ActivePresentation.slides("problem").Shapes("badge5").visible = True
ActivePresentation.slides("score").Shapes("badge5").visible = True
Else
ActivePresentation.slides("problem").Shapes("incorrect").visible = True
TextBox1.value = ""
TextBox2.value = ""
TextBox3.value = ""
TextBox4.value = ""
End If
'Wait code here(1000ms)
Sleep 1000
'Command Button 3(code)
SlideShowWindows(1).View.Next
'Call the command for CommandButton1,
'this will "automatically" populate the slide with new values
CommandButton1_Click
End Sub

Related

Getting Values from Controls in MS Excel Custom Dialog Boxes

first question here. I've been racking my brains all morning for the simplest thing to do in Excel's VBA: get the value of what a user types into a text box (list box, etc.) in a custom dialog box and copy that, via a macro, into a cell. Not sure why it has to be so ridiculously tough. I've tried the .Value property, the .Text property, everything, but it all comes up blank.
I'd post an image of my dialog box, but I don't have the reputation yet to do so. At any rate, just assume it's a banking dialog box with an Amount text box and two buttons: Ok and Cancel.
And here's my code, cut down to the necessary bit:
Sub AddTransaction()
frmAddTransaction.Show
ActiveCell.Offset(0, 1).Range("A1").Select
ActiveCell.FormulaR1C1 = frmAddTransaction.txtAmount.Value
End Sub
Private Sub cmdCancel_Click()
Unload frmAddTransaction
End Sub
Private Sub cmdOk_Click()
Unload frmAddTransaction
End Sub
As I've said, I've tried the .Value and .Text properties and everything else that came to mind. I've tried throwing it up into a MsgBox or just sticking it into a cell and, at this point, I'm racking my brains not only to find the answer but to figure out why Microsoft made is so tough just to take a value from one thing and put it into a cell.
Same thing with the buttons: I'd like to know how to tell a macro what button was pushed. I've tried using any property that even remotely looks promising, as well as adjusting the .Top property so I can compare that number. Everything. Nothing is working.
Any help would be great. I've been stuck on this literally all morning.
You want to add the buttons to the form, not to the sheet.
So you have 1 button on the sheet that says "Enter Amount" which runs the following:
Private Sub CommandButton1_Click()
frmAddTransaction.Show
End Sub
and the user form has 3 elements: an input box (txtAmount) and two buttons.
Private Sub Cancel_Click()
Me.Unload
End Sub
Private Sub OK_Click()
'modify this to add it to the correct cell
ActiveCell.Offset(0, 0).Value = txtAmount.Value
Me.Unload
End Sub

Hide specific sheets when closing workbook

I'm creating some VBA code which should do the following:
Users press a button a are required to input a code.
When the input the correct code the team relevant code they get access to certain sheets.
The sheets they get access to differs according to the team number and code they enter. So when they enter he password "banana": the sheets "Team_1" & Team_1_sub become visible.
I now created the following code to achieve this:
Sub filter_tabs()
Dim answer As String
answer = InputBox("Please enter your password")
If answer = "Password" Then
MsgBox "Correct, je krijgt nu de goede tabs te zien!"
Worksheets("Team_1").Visible = True
Worksheets("Team_1_sub").Visible = True
Else
MsgBox "Wrong password"
End If
End Sub
Two questions about the code above:
When the users close the document all sheet should "disappear" again. Does anybody know how to do this? So when opening the document sheets "Team_1" and "Team_1_sub" should be be standard
Worksheets("Team_1").Visible = False
Worksheets("Team_1_sub").Visible = False
Could you guys give me some feedback on whether the procedure I follow above (different if statements where users are prompted for a password and then get to see certain tabs) is the most efficient one to reach my goal? End goal is to make sure certain team leader can only see certain sheets.
Here for setting visible false, you can use Workbook_BeforeClose method as follow:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Worksheets("Team_1").Visible = False
Worksheets("Team_1_sub").Visible = False
'must save, if not save, it is not effect.
Me.Save
End Sub
Reference for that method is here.
One thing is that this method must have in the ThisWorkBook module.
For next question, you should say more like, which sheets for which user and password. Because you code is enough for your question. It can use for your requirement.
As you aren't using passwords you should at least make the sheets VeryHidden rather than Hidden - much harder for the average user to unhide.
The Me.Save proposed by the other answer also isn't necessary.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next
Worksheets("Team_1").Visible = VeryHidden
Worksheets("Team_1_sub").Visible = VeryHidden
End Sub
ad 1)
you best use a Workbook_BeforeSave() routine to code the hiding of all sheets ... in the VBAProject view you find this under ThisWorkbook
ad 2)
The code you post looks very nice - my point of concern would be the hard coding of user names vs. sheet names. I would consider putting this in a sheet/table using headers /code/ /sheetname/ ... this way you can adapt your logic at any time without having to modify the code.
With such a table at hand (in an all time hidden sheet if need be) you traverse it (one single piece of code) and - upon code entering - you unhide If CodeInTable = CodeEntered ... in the other case you unconditionally hide that sheet ... because hiding/unhiding differs only by 2 simple conditions.

Is it possible set my Excel Userform Combo box to begin narrowing the fields while data is entered?

VBA Newbie here.
I have searched high and low for this answer, and even come across other questions very similar to mine, but cannot get an answer. So I am hoping that this is my lucky day.
I have a Userform in excel that has Four combo boxes. Each combo box has a drop down with several choices. In two of these boxes, there are many business names and a lot of these names are similar. I was wanting to have the feature where are the data was being typed into the box, it would begin to narrow the options. EXAMPLE: if I type "heating and air" it begins to only show items in the list that include that word or phrase.
Is this a properties change in the box, or a code written, or something else?
Please help- I am stumped and no one seems to have the answer.
Very grateful-
Excel Newbie
Yes this is very possible. All you have to do is create a sub that populates that combo box, set it up so that when adding it checks the value of the box for example if it was the basic typing example. basic format. This assumes the possible values are stored in an array. This would add any item that has the string entered in it. (in any position)
For I = 0 to Number of Values
If instr(Value(I), ComboBox.Text) > 0 then
add item
endif
next
I played around a bit and came up with something to get you started. This basically functions as an "auto search". It is not autocomplete because it will search entire terms, not just terms which begin with whatever you've typed in. Basically I assume you have a range of cells (in this example cells A2:A121) that have the date for your drop down in it.
Setup
Add a new generic module (I named mine GlobalVars and add the following code:
Option Explicit
Public IgnoreChange As Boolean
Public RangeOfData As Variant
The Code
Open the code to your UserForm.
Add the following code:
Private Sub UserForm_Initialize()
RangeOfData = Application.WorksheetFunction.Transpose(Sheet1.Range("A2:A121").Value)
IgnoreChange = False
End Sub
Be sure to update A2:A121 and Sheet1 (I am using code name, but Worksheets("Sheet1") would work just as well) to point to the data which contains your combobox choices.
Now, the meat of the job is handled in the Combobox_Change event
Private Sub ComboBox1_Change()
If Me.ComboBox1.Text = vbNullString Then
Me.ComboBox1.Clear
SendKeys ("{Enter}")
End If
If Me.ComboBox1.TextLength > 2 Then
Dim i As Long, j As Long
If IgnoreChange = False Then
Me.ComboBox1.Clear
SendKeys ("{Enter}")
DoEvents 'Bug with NumLock
For i = LBound(RangeOfData) To UBound(RangeOfData)
If UCase(RangeOfData(i)) Like "*" & UCase(Me.ComboBox1.Text) & "*" Then
Me.ComboBox1.AddItem RangeOfData(i)
End If
Next i
Me.ComboBox1.DropDown
End If
End If
IgnoreChange = False
End Sub
Be sure to change ComboBox1 to the name of your combobox control.
Basically, what this does is it handles user input when it reaches two characters or longer. The code will search through your input data range and then return results that match the string as the user is entering it. The results is like a suggestions box.
I should note that with this method, the combobox is NOT pre-populated with data, so users must begin typing something into the combobox.
Additionally, I added the following code to handle the backspace key:
Private Sub ComboBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 8 Then
IgnoreChange = True
End If
End Sub
Again be sure to change ComboBox1 as appropriate.
For my example, I loaded all 120 crayola crayon colors into a spreadsheet (that is what is in Sheet1 from A2:A121).
Here is example output for when I start typing, first I input blu:
As you can see I am getting all values that contain blu, including those that don't start with blu such as Cadet Blue or Midnight blue.
As another example, I will search for flower
So as you can see, instead of being a combobox with 120 static options, it is updated based on what the user types and tied to a list of values in your cells.
I did notice that SendKeys sometimes toggled my NumLock, this is a known issue. The point of that line is to collapse the drop down after the user deletes all of the text or continues texting so as to "refresh" the auto-generated list.

how to write thusands of sub vba code quickly changing references

I want a module in my workbook to write about a thousand combinations of the below
Sub trade0001open()
Sheets("TRADEDIARY").Range("AO2").Value = 1
Sheets("TRADEDIARY").Range("AD3").Value = _
Sheets("TRADEDIARY").Range("AJ2").Value
Sheets("TRADEDIARY").Range("AD4").Value = _
Sheets("Sheet8").Range("HA1").Value + 1
Sheets("TRADEDIARY").Range("AO3").Value = 0
End Sub
Sub trade0001close()
Application.ScreenUpdating = False
Sheets("TRADEDIARY").Range("AI3").Value = Sheets("TRADEDIARY").Range("AI3").Value + 1
Sheets("TRADEDIARY").Range("AO3").Value = 1
Application.Wait (Now + 0.000001)
Sheets("TRADEDIARY").Range("AO3").Value = 0
Sheets("TRADEDIARY").Range("AO2").Value = 0
Sheets("TRADEDIARY").Range("AI2").Value = Sheets("TRADEDIARY").Range("AI2").Value + 1
Application.ScreenUpdating = True
End Sub
Changing changing the cell references by a cumulator of four rows down each time. So every AO2 would become AO6 in the next every AD3 becomes AD7. Everything apart from HA1 would change so that includes AO2,AD3,AJ2,AD4,AO3 for the first sub and then that includes AI3, AO3, AO2, AI2 for the second sub.
So since my code above contains the two subs I'd like copied a thousand times - each copy will add 4 rows to each cel reference in each sub.
I am quite new to vba so I guess I am after a similar autofill function like in excel except for my code to do this quickly instead of typing thousands of times unless of course I guess somebody could suggest how to do this differently. hint hint. bare in mind I obviously want all the values pasted without a clipboard so that when those values from where they are copied change, the destination doesn't change. Which is what my above code achieves.
Then I'd like to asign each individual sub within each of the two separately to a developer button control in the spread sheet ( again asigned to change four rows down each time)
#matteo to clarify ''well I envisioned the only way was to have 1000 trade0001open() and 1000 trade001close() possibly defined as trade0001open() , trade0002open() etc ditto close etc etc in order to right click for each one on a vba developer for control button alligned to each cell AK4 for open button and AM4 for close button so AK8 and AM8 etc etc which is long winded again and Im refraining from assuming a developer button could be alligned to each of those cells frm within vba and assigned to each of the sub at the moment. I guess one workaround might be to configure the j somehow into the sub name .''
matteo's reply: ''What you ask is complex to answer here, i will give you a tip to get started: use always the same macro but intercept the reference of the cell from which the call starts in order to add dinamically the 4 rows as I showed you above. You don't need 2000 macros, only 2 that are readapting themselves depending on the caller parent''
me : ''so I guess this is more complicated than it seems if I could somehow make form button's alligned to cells to reference the j value within the 2 macros without need for making thousands of sub macros. As far as I know form buttons in excel can only reference sub functions without reference and not UDFs or anything else or even cell references although I probably am wrong about this. ''
a form button to call the sub based on a cell's reference that is what I need right?
http://www.mrexcel.com/forum/excel-questions/843078-loop-visual-basic-applications-sub-call-form-button-each-nth-row-based-cell-value-row-reference.html#post4105072
I don't know for the life of me where to begin Trying to call a Sub with a String - VBA
You just need to make every string dinamically redefined and loop 1000 times the same macro. This is an example to get started:
For j = 1 To 1000 '<-- do this 1000 times
'...
Sheets("TRADEDIARY").Range("AO" & 2 + (j-1)*4).Value = 1 '<-- if j=1 then row = 2, if j=2 then row = 2+4 = 6 etc.
'...
Next j

VBA: Displaying Row Numbers Completed in Run Time

I couldn't observe the number of rows completed during run time. Hence I was thinking why not just come out few line of codes to display the number of rows completed in run time.
Follow are my implementation:
Dim ownCntrl As Control
Set ownCntrl = UserForm1.Controls.Add("Forms.TextBox.1")
With ownCntrl
.Name = "RowNoTextBox"
.Value = "test"
.Width = 150
.Height = 25
.Top = 10
.Left = 10
.ZOrder (0)
End With
UserForm1.Show
Following are my queries:
1)Beside TextBox Object, is there any other Object like label in Java to display information in VBA?
2)Without Created a UserForm called "UserForm1" initially, can I create the TextBox Object or other suitable Object Directly during run time? Cause, without called the UserForm1.Show function, the TextBox Object won't display
3)How can I remain the UserForm or TextBox to display during run time without users' interaction to close it to proceed?
I'm just start to learn VBA. Appreciate you guys' suggestions. Thanks a lot.
According to some additional information placed in comments the simplest idea to keep information about progress of your subroutine is to use Excel status bar. Therefore we put within our subroutine something like this:
Application.StatusBar = "Current progress- Row No.: " & rowNum
where rowNum is a variable (loop variable) representing current row.
Which is important- you need to return standard status bar behaviour calling this line before end of your procedure:
Application.StatusBar = False