Excel VBA Object Helper Function - vba

I have a UserForm where one of my ComboBox's can have different values depending on other variables that the user has selected. Rather than update the contents of a single ComboBox every time the user makes a change, I have created two ComboBox's and simply set the appropriate one as visible. These two ComboBox's have the names "width1_cb" and "width2_cb" respectively.
I have created a helper function to return the currently active ComboBox so that other pieces of my code can use it. Here is the helper function:
Function myGetActive(ByVal control As String) As ComboBox
If control = "width" Then
If width1_cb.Visible = True Then
Set myGetActive = Me.width1_cb
ElseIf width2_cb.Visible = True Then
Set myGetActive = Me.width2_cb
Else
Set myGetActive = Nothing
End If
End If
End Function
Unfortunately, this function is not functioning as expected. I have another line of code:
Set currentWidth = myGetActive("width")
currentWidth.Value = 5
which fails on the second line. I cannot figure out what I am doing incorrectly here - my best guess is that I am somehow not returning the actual combobox instance in my helper function but instead some sort of copy, but in my research I have not been able to figure out the correct way to accomplish this. Does any one know how I can make this function work as expected?
Update: Debugging efforts I have taken including stepping through the code line-by-line and putting a "watch" within the "myGetActive" function on both the width1_cb and the myGetActive variables. What I find is that the myGetActive variable gets set to type "ComboBox/Combobox" while the width1_cb is "Object/Combobox". What's more, the context for width1_cb is "Input_Window.UserForm_Initialize" while the context for the myGetActive is "Input_Window.myGetActive". The function does exit without any errors though.

Initially I just wanted to make a comment about 2 distinct ways for declaring variables:
Private currentWidth As ComboBox
or
Private currentWidth As MSForms.ComboBox
but I can't duplicate the issue you're having. Here is the code I tested with
Option Explicit
Private currentWidth As ComboBox
'Private currentWidth As MSForms.ComboBox
Private Sub UserForm_Click()
testCombos
End Sub
Private Sub UserForm_Initialize()
With Me.width1_cb
.AddItem "test1"
.AddItem "test2"
.AddItem "test3"
End With
With Me.width2_cb
.AddItem "test1"
.AddItem "test2"
.AddItem "test3"
End With
End Sub
Private Sub testCombos()
Set currentWidth = myGetActive("width")
currentWidth.Value = 5
Set currentWidth = myGetActive(vbNullString)
currentWidth.Value = 7
End Sub
Function myGetActive(ByVal control As String) As ComboBox
If control = "width" Then
If width1_cb.Visible = True Then
Set myGetActive = Me.width1_cb
ElseIf width2_cb.Visible = True Then
Set myGetActive = Me.width2_cb
Else
Set myGetActive = Nothing
End If
Else
If width2_cb.Visible = True Then
Set myGetActive = Me.width2_cb
ElseIf width1_cb.Visible = True Then
Set myGetActive = Me.width1_cb
Else
Set myGetActive = Nothing
End If
End If
End Function
.

Related

vba Checkbox if else condition in Subform, access

I have a main form with several tab controls with subforms in them. On the first tab or subform I have a "checkbox 1", which shall be:
checked if "textbox 1" is not empty
unchecked if "textbox 1" is empty
The code is directly put into the Class Object of "subform 1", that's why I thought I could use Me.
Here is my code, but I always get error messages :(
Private Sub Ctltextbox_1_AfterUpdate()
If Len(Ctltextbox_1.Value) = 0 Then
Me.checkbox_1.Value = 0
Else
Me.checkbox_1.Value = -1
End If
End Sub
That way I am getting the
Run-time error '2448': You can't assign a value to this object.
On the line that attempts to assign -1 to Me.checkbox_1.Value.
Try this. It is working for me. I moved it to the Ctltextbox_1_Change action. This will call the function whenever it is changed and will catch when you have nothing in the box as well. I also changed your values to True and False.
Please try this and let me know.
Private Sub Ctltextbox_1_Change()
If Len(frmSub.Ctltextbox_1.Value) = 0 Then
frmSub.CheckBox_1.Value = False
Else
frmSub.CheckBox_1.Value = True
End If
End Sub
you can also solve this in one line as mentioned below.
Private Sub Ctltextbox_1_Change()
frmSub.CheckBox_1.Value = IIf((Len(frmSub.Ctltextbox_1.Value) = 0), False, True)
End Sub
Ok, the simple answer is: you can not use the expression Len()= 0 for a not numeric field! So my working code for the subform is now:
Private Sub Textbox1_AfterUpdate()
If IsNull(Textbox1.Value) = False Then
Me.checkbox1.Value = True
Else
Me.checkbox1.Value = False
End If
End Sub
Thank you all for your help! :)

Excel VBA combobox doesn't allow to select specific items from list

I have a combobox in my worksheet with a dynamic search, the dynamic search is done by searching the typed letters in a list that is on another worksheet. The search is done by excel formulas. The list is a defined range and then the combobox listfillrange is set to the named range.
When I type the dropdown list opens, for certain items the combobox allows me to select from the list and for others the selection disappear as I select. I tried figure why do these items disappear. The list is long (10,000 items) so it kind of works slow, but I am not sure if this is the problem.
How can I fix such a problem? Is there a way to define a variable for the mouseclick selection from dropdown list?
Thanks in advance,
Tali
This is my code:
Private Sub ComboBox1_Change()
Sheets("PS").EnableCalculation = True
ComboBox1.ListFillRange = "DropDownList"
ComboBox1.DropDown
End Sub
Private Sub CommandButton21_Click()
Dim PS As Worksheet
Application.ScreenUpdating = False
Application.ErrorCheckingOptions.BackgroundChecking = False
Sheets("PharmaSoft").Select
Set PS = Sheets("PS")
SelectionA = PS.Range("J2").Value
If ComboBox1.Value = SelectionA Then
Range("J19") = "Pharmacy purchase price"
Range("N19") = PS.Range("K2")
Range("O19") = "ILS"
Range("J21") = "Pharmacy selling price Incl.VAT"
Range("N21") = PS.Range("L2")
Range("O21") = "ILS"
Range("J23") = "Package size"
Range("N23") = PS.Range("M2")
Range("J19:O23").Select
With Selection.Font
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
End With
Selection.Font.Bold = True
Application.ScreenUpdating = True
Range("N19").Errors.Item(1).Ignore = True
Range("N21").Errors.Item(1).Ignore = True
Range("N23").Errors.Item(1).Ignore = True
Else
MsgBox "Please select a product", vbCritical, "Error"
End If
Sheets("PS").EnableCalculation = False
End Sub
Private Sub CommandButton22_Click()
Application.ScreenUpdating = False
Sheets("PharmaSoft").Select
ComboBox1.Value = Null
Range("J19:O23").Value = Null
Application.ScreenUpdating = True
End Sub
Also the code for the workbook:
Private Sub Workbook_Open()
Sheets("PharmaSoft").Select
Application.ScreenUpdating = False
Sheets("PharmaSoft").ComboBox1.Value = Null
Range("J19:O23").Value = Null
Application.ScreenUpdating = True
End Sub
Although I can't comment on what you're doing given that your search is done as you mention with excel formulas. I do know that using data validation via a combo box can be pretty quick. The method I use is as per this page and is extremely fast. It's pretty much instantaneous on a validation range that is about 15k rows long. The best part about it is that it provides auto completion. So when you type in the combo box and that value isn't in the list, the entry that matched one character ago disappears. It's a good visual cue whether you're selection is valid or not. And of course, you can still use the drop down box in the usual way. The only down side is that, as coded at the link provided, you have to double-click to enter the auto-completion mode.

Userform controlled variables within a macro

Morning Guys,
I have ran into a small roadblock with my project. I'm new to VBA and am trying my best to 'learn by doing' but I cannot seem to get my head around macro/userform interactions.
I have a userform with one textbox and 9 checkboxes. This is supposed to show the userform, allow the user to dictate a sheet name, and (from a list of 9 users) select which is active or not (true or false).
In my main sub, I just have a
Allocator.show
command, as you may have guessed, allocator is my userform name.
Then I've sort of just been trying things so I don't know how right the rest of the userform code is;
Private Sub cbGo_Click()
Unload Allocator
End Sub
Private Sub cboxAlison_Click()
If Me.cboxAlison.Value = True Then
AlisonYN = True
Else
AlisonYN = False
End If
End Sub
Private Sub cboxBeverly_Click()
If Me.cboxBeverly.Value = True Then
BevelyYN = True
Else
BevelyYN = False
End If
End Sub
Private Sub cboxCallum_Click()
If Me.cboxCallum.Value = True Then
CallumYN = True
Else
CallumYN = False
End If
End Sub
Private Sub cboxEllen_Click()
If Me.cboxEllen.Value = True Then
EllenYN = True
Else
EllenYN = False
End If
End Sub
Private Sub cboxGeoff_Click()
If Me.cboxGeoff.Value = True Then
GeoffYN = True
Else
GeoffYN = False
End If
End Sub
Private Sub cboxJames_Click()
If Me.cboxJames.Value = True Then
JamesYN = True
Else
JamesYN = False
End If
End Sub
Private Sub cboxLouise_Click()
If Me.cboxLouise.Value = True Then
LouiseYN = True
Else
LouiseYN = False
End If
End Sub
Private Sub cboxMick_Click()
If Me.cboxMick.Value = True Then
MickYN = True
Else
MickYN = False
End If
End Sub
Private Sub cboxTammy_Click()
If Me.cboxTammy.Value = True Then
TammyYN = True
Else
TammyYN = False
End If
End Sub
Private Sub tbRPName_Change()
End Sub
Private Sub UserForm_Initialize()
Dim GeoffYN, TammyYN, CallumYN, JamesYN, MickYN, AlisonYN, BeverlyYN, LouiseYN, EllenYN As Boolean
Dim RP_Name As String
Me.cboxGeoff.Value = True
Me.cboxTammy.Value = True
Me.cboxCallum.Value = True
Me.cboxJames.Value = True
Me.cboxMick.Value = False
Me.cboxAlison.Value = False
Me.cboxBeverly.Value = False
Me.cboxLouise.Value = False
Me.cboxEllen.Value = False
Me.tbRPName = ""
End Sub
All of the named user variables (xxxxYN) are public in my main module.
These are the variables I want to pull back into my main macro as true or false following the user checking the desired boxes, along with the name as a string, and then continue running the original macro.
Any help would be greatly appreciated, I seem to be taking myself round in circles at the moment!
PS if it helps, my userform looks like this;
UserForm
Cheers,
Callum
You wrote "All of the named user variables (xxxxYN) are public in my main module." But we see them declared in userform's Sub UserForm_Initialize, too:
Private Sub UserForm_Initialize()
Dim GeoffYN, TammyYN, CallumYN, JamesYN, MickYN, AlisonYN, BeverlyYN, LouiseYN, EllenYN As Boolean
Dim RP_Name As Stringn
...
even if you declared the same variables as Public in any module, the Userform variables hide their Public namsakes so any Userform setting is not "seen" in other modules
so you'd better remove the Userform dimming statement of the "namesakes" and leave only the Public one
moreover in such a declaration statement as you used, every single variable not explicitly associated with a specific type is implicitly associated to a Variant type
so in the main module you should use a "dimming" statement like follows:
Public GeoffYN As Boolean, TammyYN As Boolean, CallumYN As Boolean, JamesYN As Boolean, MickYN As Boolean, AlisonYN As Boolean, BeverlyYN As Boolean, LouiseYN As Boolean, EllenYN As Boolean
But should all what above get you going, nevertheless I'd recommend you to switch to a "class" approach together with the use of Dictionary object, like follows
in the Allocator code pane place the following code
Option Explicit
Dim chkBoxes() As ChkBx_Class 'array of type "ChkBx_Class" which you define in a Class Module
Private Sub UserForm_Initialize()
Dim nControls As Integer, i As Integer
Dim namesArray As Variant, cbIniValues As Variant
UFInit = True
namesArray = Array("Geoff", "Tammy", "Callum", "James", "Mick", "Alison", "Beverly", "Louise", "Ellen") '<== set here the names to be associated to every CheckBox
cbIniValues = Array(True, True, True, True, False, False, False, False, False) '<== set here the initial values of checkboxes
nControls = UBound(namesArray) + 1 '<== retrieve the number of CheckBoxes you're going to consider in the Form
ReDim chkBoxes(1 To nControls) As ChkBx_Class 'redim the "ChkBx_Class" array
For i = 1 To nControls
Set chkBoxes(i) = New ChkBx_Class 'initialize a new instance of 'ChkBoxClass' class and store it in the array i-th position
With chkBoxes(i)
Set .ChkBox = Me.Controls("CheckBox" & i) 'assign the correct CheckBox control to its "ChkBox" property
.Name = namesArray(i - 1) ' assign the Name property of the Checkbox
.ChkBox.Value = cbIniValues(i - 1) 'set the checkbox correct initial value
Me.Controls("Label" & i) = .Name ' set the corresponding label caption
dealersDict.Add .Name, .ChkBox.Value ' fill the dictionary initial pair of Dealer-name/checkbox-value
End With
Next i
Me.tbRPName.Text = ""
UFInit = False
End Sub
Private Sub cbGo_Click()
Me.Hide
End Sub
add a "Class Module" to your project
either clicking Insert-> Class Module in the VBA IDE main Ribbon menu
or right-clicking anywhere in the VBA IDE Project Window and selecting Insert -> Class Module in subsequent sub-menus
expand the "Class Module" node in the Project Window
if you don't see the Project Window you can open it by clicking View-> Project Window in the main ribbon menu, or press "Ctrl+R"
select the new Class you added (it should be some "Class1" or the likes) and change its name to "ChkBx_Class" in the Property Window "Name" textbox
if you don't see the Property Window you can open it by clicking View-> Property Window in the main ribbon menu or press "F4"
in the Class Module code pane place the following
Option Explicit
'declare class properties: they will be associated in every instance of this class.
Public WithEvents ChkBox As MSForms.CheckBox ' "ChkBox" is now a property of the class of type CheckBox. it's associated to events
Public Name As String
' events associated to ChkBox class property
Sub ChkBox_Click()
If Not UFInit Then dealersDict.Item(Me.Name) = Me.ChkBox.Value ' set the dictionary pair of Dealer-name/checkbox-value
End Sub
edit your main sub module as follows
Option Explicit
Public dealersDict As New Scripting.Dictionary
Public UFInit As Boolean
Sub main()
myval = "io"
Dim myKey As Variant
Allocator.Show
Unload Allocator
For Each myKey In dealersDict
MsgBox myKey & ": " & dealersDict(myKey)
Next myKey
End Sub
create a reference to Microsoft Scripting Runtime Library to use Dictionaries.
this is done by choosing Tools➜References command in the Visual Basic Editor (VBE) which pops up a dialog box in whose listbox you are to find "Microsoft Scripting Runtime" to put a check mark next and press OK.
run the main sub
whenever you need to retrieve the boolean value associated to a given name you just have to use
myBool = dealersDict(name)
where name can be:
a string literal with the wanted name ("Alison", "Mick" , ..)
a string variable whose value stores the wanted name, so that somewhere in your code you may have typed:
Dim name as string
name = "Mick"
such an approach gives you a lot of flexibility, since you only have to:
set the names and their initial boolean values in those two arrays (namesArray and cbIniValues) in UserForm_Initialize
make sure you have checkboxes named after "CheckBox1", "CheckBox2", and so on as well as have labels named after "label1", "Label2", and so on
make sure that "CheckBoxX" is aligned with "LabelX"
make sure namesArray and cbIniValues have the same items number as labels and checkboxes
IDK what the actual issue is, but I tried to recreate your issue and just decided to show you what I have. See if any of this helps you at all.
All of this code is in the userform code, not at the module level. When I change the check box values, the values are stored (outside of the main sub, which is validated in the "check" sub click event).
To make you code a little shorter, you can directly assign the value of a checkbox to a variable
Dim test as Boolean
test = me.CheckBox1.Value
You can insert this into the code of your go button

Reading Userform Object Values

I created a Userform (manually in the VBA Projectbrowser). I have written VBA code, which fills this Userform with different Objects in runtime (Labels, Optionbuttons etc.). So far everything worked fine
The Userform is filled with data read from my Excel sheets and correctly displayed. However I'm not able to read the inputs from the objects on it (for example Optionbutton - TRUE or FALSE). These objects do not appear anywhere (except on the userform) so that I can link them and use them in another Module.
I guess they are only displayed and not really read into the memory or whatever (initialized !?).
There are two ways to go about it.
WAY 1
Declare your option button object as Public.
Module Code
Public theOpBut As Object
Sub Fill()
If theOpBut.Value = True Then
ActiveSheet.Cells(1, 5) = 1
Else
ActiveSheet.Cells(1, 5) = "NO"
End If
End Sub
Userform Code
Private Sub UserForm_Initialize()
Set theOpBut = UserForm1.Controls.Add("Forms.optionbutton.1", "OptionButton", True)
With theOpBut
.Caption = "Test Button"
'.GroupName = OpButGroupCounter
.Top = 10
.Left = 20
.Height = 16
.Width = 50
.Font.Size = 12
.Font.Name = "Ariel"
End With
End Sub
Private Sub CommandButton1_Click()
Call Fill
End Sub
WAY 2
Declare a Boolean Variable and create a click event of the Option button and then set the value of the Boolean Variable in that click event. To create the click event of the Option button at Run Time, see THIS EXAMPLE
You can then check the value of Boolean Variable in Sub Fill() and act accordingly.

Cycling through some checkboxes on my excel page

I am VERY new to VBA (and know of it only within excel).
I am trying to cycle through some (but not all) checkboxes. They are currently named CheckBox1 through CheckBox15. Howe do I cycle through say for instance CheckBox5 through CheckBox10?
I guess I am hoping there is a 'method' similar to 'CheckType' for controls that will allow me to check name?
Here is what I have tried. Causes a Compile Error - Sub or Function not defined, and highlights Worksheet.
Private Sub BoxCheck()
atLeastOneChecked = False
For i = 2 To 4
If Worksheets("ActiveX").Controls("Checkbox" & i).Value = True Then
atLeastOneChecked = True
End If
Next i
End Sub
While the above doesnt work, what is below does:
Private Sub BoxCheck()
atLeastOneChecked = False
For i = 1 To 2
If Sheet2.CheckBox2.Value = True Then
atLeastOneChecked = True
End If
Next i
End Sub
Of course, the loop has no affect on the outcome, but it compiles and atLeastOneChecked turns from False to True when Checkbox2 is True. Note that Sheet2 has been named ActiveX. I clearly don't understand how Worksheet and Controls work. Could someone help?
After fixing the error described below, this still won't work. I simplified to the following:
Private Sub BoxCheck()
Dim ole As OLEObject
atLeastOneChecked = False
Set ole = Sheets("ActiveX").OLEObjects("Checkbox2")
If ole.Value = True Then
atLeastOneChecked = True
End If
End Sub
This doesn't work. It fails at:
If ole.Value = True Then
The error states: Object Doesn't support this property or method
This is true for OLEObjects, but not for Checkboxes. When I look at the properties of ole, I see that its Object property is set to Object/Checkbox and that this Object has a value. I guess that is what I should be referencing in my if statement, but I don't know how.
I think I solved the problem.
The value of the Checkbox is accessed by Referencing the Object property within the OLEObject I set...Like this:
If ole.Object.Value = True Then
Thanks for all your help. If someone has a more elegant solution, I would still like to see it.
Use CheckBox.Name
Example:
For Each cb In ActiveSheet.CheckBoxes
If cb.Name = "CheckBox5"
' Do stuff
End If
Next cb
To expand on #Parker's answer:
Private Sub BoxCheck()
atleastonechecked = False
Dim oles As OLEObject
For i = 2 To 4
'If you're using Shapes Controls:
If ThisWorkbook.Worksheets("ActiveX").Shapes("Check Box " & i).Value = True Then
atleastonechecked = True
End If
' If you're using ActiveX Controls
Set oles = ThisWorkbook.Worksheets("ActiveX").OLEObjects("CheckBox" & i)
If oles.Value = True Then
atleastonechecked = True
End If
Next i
End Sub
Sorry, just put together the previous answer without testing - that always fails. Just use the If loop based on what type of control you're using.