setting button enabled state - vb.net

I have a simple vb 2010 form that I want to be able to set the enabled stated of all buttons on.
I have made similar functions for checkboxes and numericalUpDown controls that function as required, but for buttons the function does not seem to operate correctly.
Private Sub setButtonsState(ByVal state As Boolean)
Dim cControl As Control
For Each cControl In Me.Controls
If (TypeOf cControl Is Button) Then
cControl.Enabled = state
End If
Next cControl
End Sub
Which is called like so: setButtonsState(True)
This doesnt seem to have any effect at all with buttons, though buttonName.Enabled = True works OK...
Im pretty much what you'd call a noob at VB, so anyone help me out?
Ta

Unless all of your buttons belong directly to the Form this is run in, then they won't be accessed because this doesn't cruise down through the control tree to get to them. A slightly different approach might be a more recursive method:
Private Sub setButtonsState(ByVal controls as System.Windows.Forms.Control.ControlCollection, ByVal state as Boolean)
For Each ctrl as Control in controls
If (ctrl.HasChildren) Then setButtonsState(ctrl.Controls, state)
If (TypeOf ctrl Is Button) Then ctrl.Enabled = state
Next
End Sub

It works on my form. Are you sure you are setting state to a true value? you many want to dim a variable called "state" inside the subroutine just to test it. Set state to true and disable all of your buttons.
Try to retrieve the count of controls returned. To make sure you are correctly referencing the controls.
Demonstrating set boolean to True for testing:
*Dim state As Boolean = True*
Dim cControl As Control
For Each cControl In Me.Controls
If (TypeOf cControl Is Button) Then
cControl.Enabled = state
End If
Next cControl
Check the count of controls:
For Each cControl In (Your Form Name Ex. FrmMain1).Controls
If (TypeOf cControl Is Button) Then
cControl.Enabled = state
*debug.writeline(cControl.Name)*
End If
Next cControl

I would suggest you avoid recursion, if possible. Below approach has a much better debug-ability.
First, Linearise ControlCollection tree into array of Control - generic extension method, no recursion, LINQ or GetNextControl.
Then you can write like this:
Private Sub setButtonsState(ByVal controls As ControlCollection, ByVal state As Boolean)
For Each ctrl As Control In controls.GetAllControlsOfType(Of Button)()
ctrl.Enabled = state
Next
End Sub

Related

Access VBA put a form element name as an argument

Let's see if anyone knows how to solve this problem:
I have a form with several elements: Some of them are textboxes called A1, A2, A3, A4...
Now, their AfterUpdate SubProcedure is extremely long but barely similar for each of them: A1_AfterUpdate, A2_AfterUpdate, A3_AfterUpdate...etc... are very similar but for the names of the textboxes they change.
My idea was to gather all that was equal in a subprocedure defined this way:
Private Sub Update(Box As String, Menu As Boolean)
If Menu=True{
Me!Box.Text = "This is the text that is going to change"
}
End Sub
So, the only thing I must do is to call it this way, for instance:
Update(A1, True)
But it doesn't seems to work. Any idea on how to reach this objective?
Add a class module - I've called it clsTextBoxEvents.
Add this code to the class:
Public WithEvents txt As Access.TextBox
Private Sub txt_AfterUpdate()
MsgBox txt.Name & " has been updated."
End Sub
In your form module add this code:
Public MyTextBoxes As New Collection
Private Sub Form_Open(Cancel As Integer)
Dim ctl As Control
Dim txtBoxEvent As clsTextBoxEvents
For Each ctl In Me.Controls
If TypeName(ctl) = "TextBox" Then
Set txtBoxEvent = New clsTextBoxEvents
Set txtBoxEvent.txt = ctl
txtBoxEvent.txt.AfterUpdate = "[Event Procedure]"
MyTextBoxes.Add txtBoxEvent
End If
Next ctl
End Sub
The MyTextBoxes declaration must be at the very top of the module.
This just adds the AfterUpdate event to all textboxes on the form. You'll probably want to refine that a bit to textboxes with specific text in the name, or controls that are in a specific frame on the form.
If you use a function instead of a sub:
Private Function UpdateCtl(Menu As Boolean)
If Menu Then
activecontrol = "This is the text that is going to change"
End If
End Sub
then you can call it directly from the control's AfterUpdate property: =UpdateCtl(True).
Simple and fast

VBA-excel: How to check if any of controls were changed

Im new at VBA and wonder if there any way to check if any of UserForm controls were changed? Maybe there is some global event handler for all of controls?
For example I have a UserForm1 with some data and Controls on it. Also there is some kind of global Boolean B_bool which is False by default.
If User changes any text or click any of radio buttons, or check any of checkboxes B_bool becomes True.
I tried to create some sort of event handler and a Classmodule for each type of controls but only textbox and optionbuttons classes work fine. Other classes (checkboxes, comboboxes) swears at OnChange event (Object or class doesn't support the set of events)
Following code mostly same for every type of control, so i see no reason to flood a question
Private WithEvents MyTextBox As MSForms.TextBox
Public Property Set Control(tb As MSForms.TextBox)
Set MyTextBox = tb
End Property
Private Sub MyTextBox_Change()
B_bool = True
End Sub
and then UserForm code
Public tbCollection As Collection
Private Sub Userform_Initialize()
Set tbCollection = New Collection
For Each ctrl In Me.Controls
If TypeOf ctrl Is MSForms.TextBox Then
Set obj_tb = New clsTextBox
Set obj_tb.Control = ctrl
tbCollection.Add obj_tb
End If
Next ctrl
End Sub
You can detect if a workbook has unsaved changes with:
ActiveWorkbook.Saved
An example of how you could use this:
'Here is the code where your userform is prepared for the user...
'maybe you set default values or something like that. Once you're
'finished the changes YOU (or your VBA) are making to the workbook,
'SAVE it. This will mark a "starting point" to watch for changes...
ActiveWorkbook.Save
'And here would be your code (if any) that runs when the user is doing
'he does. blah blah blah
'When it's time to check if the user made any changes, find out with:
If ActiveWorkbook.Saved then
'no changes have been made
Else
'changes have been made
'do whatever you need to do to save your data.
End If
See the links below to learn how AutoSave may or may not affect this functionality.
More Information:
MSDN : Workbook.Saved Property (Excel/VBA)
MSDN : Workbook.Save Method (Excel)
MSDN : Workbook.AutoSaveOn Property (Excel)
MSDN : How AutoSave impacts add-ins and macros

VBA: how to use class module to change value of checkbox in userform

I have a userform with a lot of emailaddresses. I want the user to be able to select who to send an email to. I do so with checkboxes which are created on run time. To make it easier to use, I have also added a checkbox which allows the user to select of deselect all checkboxes.
This works perfectly as I want it to, but there is one problem I'm breaking my head over. If all checkboxes are checked and one gets unchecked, I want the "Select all" checkbox to be unchecked as well - and vice versa, if not all checkboxes were checked and the final checkbox is being checked by the user I want the "Select all" checkbox to be checked as well.
I try to do this using a class module. My overall knowledge of vba is pretty okay, but class modules are new territory for me, so excuse me if my language gets a bit fussy now.
In the initialize event of the userform I create a new collection and I assign clicks to these specific checkboxes. That works perfectly, as it doesn't give any errors in the initialize event of the userform and an event is triggered once I click one of these checkboxes. The problem I'm having is that I can't get a grip on the "Select all" checkbox (chkSelAll) in the userform. I've tried creating a public object for this checkbox in the userform (Public objSelAll As MSForms.CheckBox), but still it gives me the "Variable not defined" error once I click one of the checkboxes.
Here's the code for the class module (cls_RIRI):
Private WithEvents chkBox As MSForms.CheckBox
Public Sub AssignClicks(ctrl As Control)
Set chkBox = ctrl
End Sub
Private Sub chkBox_Click()
If chkBox.Value = False Then objSelAll.Value = False
'^This is where the error occurs: variable not defined
End Sub
And here's the relevant part of the Userform_Initialize event:
Private colTickBoxes As Collection
Public objSelAll As MSForms.CheckBox
Private Sub UserForm_Initialize()
Dim ChkBoxes As cls_RIRI
Dim ctrl As Control
Set objSelAll = Me.Controls.Item("chkSelAll")
Set colTickBoxes = New Collection
For Each ctrl In Me.Controls
If TypeName(ctrl) = "CheckBox" And Left(ctrl.Name, 1) = "M" Then
Set ChkBoxes = New cls_RIRI
ChkBoxes.AssignClicks ctrl
colTickBoxes.Add ChkBoxes
End If
Next ctrl
Set ChkBoxes = Nothing
Set ctrl = Nothing
End Sub
As you can see I didn't get to the point yet where I let the code check if all checkboxes are checked so that the select all checkbox can be checked as well. I'm not really looking for this code, I'll probably manage it once I get grip on the select all checkbox from the class module, so please don't worry about this part! :)
Private WithEvents chkBox As MSForms.CheckBox
private strParentFormName as string
Public Sub AssignClicks(ctrl As Control,strFormName as string)
strParentFormName=strFormName
.....
end sub
Private Sub chkBox_Click()
dim f as userform
set f=userforms(0) <--- or loop the userforms to get form name
If chkBox.Value = False Then f.controls("objSelAll").Value = False
'^This is where the error occurs: variable not defined
End Sub
and something like this
Public Function GET_USERFORM(strUserform As String) As UserForm
Dim i As Integer
For i = 0 To UserForms.Count - 1
If UserForms(i).Name = strUserform Then
Set GET_USERFORM = UserForms(i)
Exit For
End If
Next i
End Function
You'll need to pass in the form also, as the variable doesnt exist in the class. Add a property for the formname or if you'll only have 1 form open, then use the open form or reference the form if multiples are open. Your class exists on it's own as a check box. I am not sure, but you may be able to get the parent object from the checkbox. Hope this helps.
private strFormName as string
Public Property Let ParentForm(value as string)
strFormname=value
End Property
then...
userforms(strFormname).controls("objSelectAll").value=true

Excel VBA Error 13 type mismatch in Me.ActiveControl

I'm creating a commmon validation subroutine for a form with multiple text boxes.
For each of the textbox I have an Exit event that triggers the following:
Private Sub formatoNumerico(Optional ByVal Cancel As MSForms.ReturnBoolean)
Dim tb As MSForms.TextBox
Set tb = Me.ActiveControl
' Do something
This is generating an Error 13 Type Mismatch on the 3rd line of the code, why?
Thanks in advance for helping!
The tab host control is a container so it takes precedence over its constituents.
The simplest thing is to pass the textbox to formatoNumerico otherwise you will need to identify the textbox by asking the current tab for its ActiveControl:
Private Sub formatoNumerico(Optional ByVal Cancel As MSForms.ReturnBoolean)
Dim tb As MSForms.TextBox
If Not (Me.ActiveControl Is Nothing) Then
If TypeOf Me.ActiveControl Is MultiPage Then
Set tb = Me.ActiveControl.Pages(Me.ActiveControl.Value).ActiveControl
Else
Set tb = Me.ActiveControl
End If
Debug.Print tb.Name
End If
End Sub
Also note that switching between controls on different tabs wont raise _Exit.
When you exit, the Textbox is no longer the active control, hence, when you try to set a textbox type variable to the current control (which may or may not be the textbox), this error will result.
You will need to modify your code to explicitly refer to the TextBox control you are interested in modifying. You may, perhaps, refer to it using some global variable at the time of initializing your forms and then use that reference in your code.

How to change multiple comboboxes with little code

Here's my problem.
I have a userform with 10 comboBoxes.
Instead of Select Case al those comboboxes one by one is
there a smart way to change multiple combobox properties such as backcolor or fontcolor?
So for example:
Sub ChangeMultipleComboBoxes()
Dim comboB as control
For Each comboB In Me.Controls
If TypeName(comboB) = "ComboBox" Then
comboB.BackColor = vbRed
End If
Next comboB
End Sub
The problem is that for comboB I can't seem to find any properties for changing it's backcolor or whatsoever.
Can someone help me please?
As Zaider says, your code works. You just don't get the IntelliSense for the ComboBox-specific properties when it's declared as a Control, even though you can use the properties as you've done in your code. (Note that properties common to all controls, e.g., Caption are available.)
To get the Intellisense for all ComboBox properties, re-declare the Control as a ComboBox once you've determined that's what it is:
Private Sub UserForm_Click()
Dim ctl As MSForms.Control
Dim comboB As MSForms.ComboBox
For Each ctl In Me.Controls
If TypeName(ctl) = "ComboBox" Then
're-declare it as a ComboBox
Set comboB = ctl
'Now you get IntelliSens
comboB.BackColor = vbRed
End If
Next ctl
End Sub