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

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.

Related

Performing calculations with random numbers

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

Keeping ComboBox Lists Populated

I have created a Word 2010 VBA Macro Sub with a UserForm. The Sub searches for ==Codes== in a form document, places the found ==code== as a label into the Userform and then allows the user to replace the ==code== with his or her input in the Combobox (part of the same UserForm).
Each string of inputted data is then saved to the Combobox list in the UserForm for later selection if needed.
This works fine until this Macro/Userform expires because a searched document is completed (or cancelled).
I would then like to open the next form document, and in the new launch of this same Macro/Sub retain the former combobox list of data (as options to fill this next opened document - for instance, the code ==Client Name== will come up frequently, and I'd rather select a combobox list entry rather than having to type the client name over and over)
But I can't seem to keep the combobox list in the new launch of this Macro Sub populated with the previous combobox data - even if I isolate this routine as a separate module and pre-define the variables with "Public" dimensions.
So, before I knock myself out trying to figure this out ... just a simple question:
Once a Macro terminates are all of the Public variables "dropped"? When I used to program in DOS WP.51 Macros you could keep data strings in the RAM endlessly (until you "killed" them, or closed WP)
If the Public variable are not "dropped", could someone give me a sample of code by which Public variables could be retained and populated into a duplicately launched combobox userform.
Any ideas, howsoever brief, would help
Thanks much in advance. . .
Mike
Not entirely sure what you're trying to do, but what I'd recommend is the following (Assuming that the form is named, "UserForm1" and then "UserForm2":
1) Create a Module that you use to open the form using:
Sub test()
UserForm1.Show
'Rest of things that you want to do...you will be able to access the values in your combobox in userform1
UserForm2.Show
End Sub
2) In your UserForm1, include a button that will close the form and include the following code:
Sub btn_Exit_Click()
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Then
Cancel = True
MsgBox "The X is disabled, please use a button on the form.", vbCritical
End If
End Sub
This will allow you to maintain control of the UserForm and ensure that you can keep the values. It may be possible to disable the Closing button, but I wasn't able to figure it out (my experience with forms is mostly in Access and those have different properties).
Hiding the form keeps the values so that you can look at them whereas when the user closes the form you lose the values that were in it.
*Note: Code to disable the X button taken from VBA Express

VBA listbox select worksheet by index

I have a form with listbox which dynamically provides a list of the worksheets in the current workbook (code below). I wish to take the selected Sheet and refer to it in a formula later in the process. From hours of playing around I cannot seem to accomplish this. I believe I read somewhere that you cannot take the string back to the sub and use it to refer to to an object. So I thought maybe I can create two listboxes
for sheet name
for sheet index
that I could pass the index number to and maybe use that in my formula to lookup items from the correct sheet.
For the life of my I cannot seem to find a way to connect the two since the items will always be changing; the code will be ran on multiple workbooks by multiple operators so the layout will most likely change between users. I can easily add the second list box with index #'s but I have a block on how to associate the name which will have meaning to the user and the index which I can pass back to the sub. I realize the "On click" procedure for the list box to associate the two but with the dynamic nature of the fields I cannot come up with the logic to put that into code.
For N = 1 To ActiveWorkbook.Sheets.Count
With ListBox1
.AddItem ActiveWorkbook.Sheets(N).Name
End With
Next N
Try this out.
Declare a public variable above the code for the UserForm, making it available throughout your workbook from any module or code.
Public listChoice As String
Using your code to get the sheet names for the ListBox rowsource.
Private Sub UserForm_Activate()
For n = 1 To ActiveWorkbook.Sheets.count
With ListBox1
.AddItem ActiveWorkbook.Sheets(n).name
End With
Next n
End Sub
Including an update event for the ListBox
Private Sub ListBox1_AfterUpdate()
listChoice = ListBox1.Text
End Sub
I included a test just to demonstrate that the result is still retained. You don't need this, it demonstrates the results on the screenshot.
Private Sub cmdTestChoice_Click()
MsgBox ("The choice made on the ListBox was: " & listChoice)
End Sub
edit: To access that sheet later, you can call it using something like this:
Some examples of different ways to access a cell, using .Range, or .Cells, with numbers or letters.
Using lRow & lCol as Long to set row and column numbers.
Sheets(listChoice).Cells(lRow, lCol).Value = TextBox1.Value 'Set cell on sheet from TextBox
TextBox2.Value = Sheets(listChoice).Range("A2").Value 'Set TextBox From Cell on Sheet
'Set a cell on another sheet using the selected sheet as a source.
Sheets("AnotherSheet").Cells(lRow, "D") = Sheets(listChoice).Range("D2")

Excel macro to create a command button and assign macro to the button

I am trying to build a main page for my costing model. On this page I have created a drop down list using a combo box and then I want to assign a macro that creates a list of different buttons/command buttons once an option is selected from the list. Then I want to build another macro that is assigned to those buttons which then take the user to another tab/sheet within the same workbook depending on the option they selected from the drop down.
Can someone please give me an idea as to what code I should be using, first to create a command button that refers to the selected option from the drop down and then assign a simple macro to that button which then takes me to the specified tab/sheet?
So far, I have got the following:
Option Explicit
Sub Select_Change()
With ThisWorkbook.Sheets("Main Page").Shapes("Select").ControlFormat
Select Case .List(.Value)
Case "Vehicle1": All_States1
Case "Vehicle2": All_States2
Case "Vehicle3": All_States3
Case "Vehicle4": All_States4
Case "Vehicle5": All_States5
Case "Vehicle6": All_States6
Case "Vehicle7": All_States7
End Select
End With
End Sub
I then tried to use the name All_States1 to create various buttons but it's not working properly, as all selected options are showing the same button and the button won't go away either. Also, I can't seem to assign a macro to the created button.
This is just an example of :
creating a Button
assigning a macro to it
.
Sub button_maker()
Dim r As Range
Set r = Selection
ActiveSheet.Buttons.Add(94.5, 75.75, 51, 27.75).Select
With Selection
.OnAction = "mooney"
.Characters.Text = "Bump"
End With
r.Select
End Sub
Sub mooney()
Range("A1").Value = Range("A1").Value + 3
End Sub
If I understand the problem correctly, you want to have a dropdown (combo box) on your sheet, and when a button is clicked you want to run a macro based on the selection. The following does that - see if it helps you.
First - create a combobox, and a range for the inputs (names in the combobox) and output (value selected). For example, you could call the input selectionIn and the result selectionOut.
Exact steps:
Wrote values of combobox selections in E1:E4 . Selected the four cells, then typed selectionIn in the name box (to the left of the formula bar). That creates a named range (there are other ways to create named ranges, but this is my preferred method).
Called cell F1 selectionOut
Created a combobox, and referenced these two ranges for its input and output:
Created a button, gave it the label "Go" and linked it to the action runIt.
Finally, I created the following code in a workbook module:
Sub runIt()
Dim whatToDo, makeName As Boolean
' look up the name of the combo based on the value:
whatToDo = Range("selectionIn").Cells([selectionOut].Value, 1)
MsgBox "have to do '" & whatToDo & "'"
makeName = False
Select Case whatToDo
Case "one"
' example of putting the code you need right in the select:
MsgBox "doing the first thing"
Case "two"
' example of calling a specific routine:
Call caseTwo
Case "three"
Application.Run "case" & whatToDo ' making the name of the function on the fly
Case "four"
makeName = True
End Select
If makeName Then
Dim nameToRun
nameToRun = "case" & whatToDo
Application.Run nameToRun
End If
End Sub
Sub caseTwo()
MsgBox "called the code for case two"
End Sub
Sub caseThree()
MsgBox "doing case three here"
End Sub
Sub caseFour()
MsgBox "even four can be done"
End Sub
This shows a few different ways to handle different cases depending on what was selected. Of course you can have a macro run every time the combobox selection is changed - but it sounds from your description like that is not what you want.
Let me know how you get on with this code example - I tried to keep it simple but show some options at the same time.
One alternative (which might be simpler) would be to have an array with the names of the functions that you want to call:
Sub otherMethod()
Dim functionList()
functionList = Array("caseOne", "caseTwo", "caseThree", "caseFour")
Application.Run functionList([selectionOut].Value - 1)
End Sub
That's certainly the most compact way I can think of to do this... you need the offset of -1 because the array index is base 0 (by default anyway) and the combobox returns 1 for the first selection. You could make your code more robust by writing
functionIndex = [selectionOut].Value + LBound(functionList) - 1
Application.Run functionList(functionIndex)
This ensures that if you change the base index of the functionList array to another value, it will all still work correctly.

Find cell location based on value then do something- User Forms VBA Excel

i have experience in programing, however, I am new to VBA. I have a user form that i am working on. This form has a Combo Box that has a list initialized to it. What i am trying to do is:
*Get the ID Number value inputted by the user from the ComboBox
*Take the value inputted by the user and find its match using a range of values from a worksheet (i.e. Worksheet.Range("ID_Number_List"))
*Once it obtains it's match get the location of the cell that it matches
* Off set the location of the cell by one column to get the Name that relates to the ID Number(Same Row) to set it to textBoxName.Value
*Off set it two columns to get the telefone number that relates to the ID Number and set it to textboxTele.value
I want this to happen as soon as a value is selected from the Combobox, so my question is does my code go in the combo box or does it go to the next text box? so as soon as the person tabs over to the next text box the code is automatically execute. i would like the code to fully execute without tabing over to the next box.
This code is not complete but here is what i have (i didnt add the off set part i just did a test execution):
Dim ORIValue As String
'get value from combo_box Set
ORIValue = COMBO_ORILIST.Value
Dim cLoc As Range
Dim cORIVal As Range
'worksheet with the ID information Dim ORISheetList As Worksheet
Set ORISheetList = Worksheets("ORI_LIST")
'
For Each cLoc In ORISheetList.Range("ORI_LIST")
'compare the input string from list- considering using Match function for this
If StrComp(cLoc, ORIValue, vbTextCompare) Then TextBAgencyName.Value = "test"
Else: Next cLoc
End If
Let me know what you think. If i have to rewrite everything i will.
Your code doesn't compile.
If you have a userform with a single combobox called ComboBox1, you need to put your cell-finding code in the form code as follows:
Private Sub ComboBox1_Change()
MsgBox "yep, this is where the code should go"
End Sub
I suspect using the rowsource property of the combobox in combination with the index of the selected value you probably don't need to actually perform a search for the selected value. Something like this might work:
Private Sub ComboBox1_Change()
MsgBox Range(ComboBox1.RowSource).Cells(ComboBox1.ListIndex + 1)
End Sub
Hope that helps.