Clear Text boxes within a Multipage Control on Userform - vba

I am working on a school project while learning vba for the first time. The project is built around a wedding planning worksheet. I plan to lockdown the worksheet so that formulas and formatting don't get broken by the user (my fiance would find a way). In order to do this, I am building a userform that collects the data via text boxes on different pages of a multipage control.
This example only has one page, but it will show others like "Apparel" later:
I currently have the following code on _Click for the "Clear" button.
Dim C As Control
For Each C In frmExpenses.Controls
If TypeName(C) = "TextBox" Then
C.Value = ""
End If
Next C
This effectively clears the data from the text boxes. However, I want to be able to clear the data on ONLY the active page on the multipage. For example if there is later a tab called "Flowers" and it's the active tab, I want to leave the data on "Apparel" and clear the data from "Flowers."
I tried being as thorough as possible above. Let me know, if you need clarification on something.

Try this
For a particular Page (Say 1)
Dim ctl As Control
For Each ctl In Me.MultiPage1.Pages(1).Controls
If TypeName(ctl) = "TextBox" Then ctl.Value = ""
Next
From ActivePage
Dim ctl As Control
For Each ctl In Me.MultiPage1.Pages(Me.MultiPage1.Value).Controls
If TypeName(ctl) = "TextBox" Then ctl.Value = ""
Next

Related

Rename TextBoxes on Form after Copying it into a new multipage

I'm dealing with this issue. I have a userform that addapts after the user enters a value (for example, if he wants to add 3 members, the user form creates 3 different pages with the same boxes, after renaming them).
I have this right now:
After pressing "Lanzar", the userform will create more pages with "Datos Educando 2", "Datos Educando 3"... and so on, taking the value introduced on "Educandos a inscribir:"
The code is the following:
Private Sub lanzar_numero_educandos_Click()
Dim l As Double, r As Double
Dim ctl As Control
Me.MultiPage1.Pages(1).Visible = True
If Me.MultiPage1.Pages.Count > 2 Then
For a = Me.MultiPage1.Pages.Count - 1 To 2 Step -1
Me.MultiPage1.Pages.Remove a
Next a
End If
Me.MultiPage1.Pages(1).Visible = True
If educandos_a_inscribir.Value <> 1 Then
For a = 1 To educandos_a_inscribir.Value
MultiPage1.Pages.Add
MultiPage1.Pages(a).Controls.Copy
MultiPage1.Pages(a + 1).Paste
For Each ctl In MultiPage1.Pages(a).Controls
If TypeOf ctl Is MSForms.Frame Then
l = ctl.Left
r = ctl.Top
Exit For
End If
Next
For Each ctl In MultiPage1.Pages(a + 1).Controls
If TypeOf ctl Is MSForms.Frame Then
ctl.Left = l
ctl.Top = r
Exit For
End If
Next
Me.MultiPage1.Pages(a + 1).Caption = "Datos Educando " & a
Next a
Me.MultiPage1.Pages(1).Visible = False
End If
End Sub
Now, the problem I have is that the pages generated with this code have random names on each TextBox, so I'm not able to locate the information introduced from the user.
For example, this is the first page (the one that has the names I already know):
Here, the TextBox "Nombre Educando" is called "nombre_educando_1", so I can locate it easily on code:
The Textboxes created when copying the first page, have random names (like "TextBox 34", "TextBox 35"... and so on), so I'm not able to controll how are they called.
There is a way of generate the pages editing the TextBox names? Like, for example, for the second page generated, the TextBox in the example above should be "nombre_educando_2" and so on.
Thanks!
Each control on the first page has an attribute named Tag. You can value these with unique and meaningful values. When you paste the controls to the new page the Tag values will follow. Then as you loop through the controls on any page, use a Select Ctl.tag statement to identify what to do with the value of the control.

How do I efficiently pair Toggle Buttons and Textboxes in Access Form?

I know the title is a bit confusing so let me make myself as clear as possible.
In an Access form (2010), I have a set of text fields meant to contain dates. Those fields are all optional, the user can fill in any number of dates.
To make it more user-friendly, I want to associate each field to a toggle button. Then I want 2 things to happen :
On CURRENT event :
If a text field has a value, then it is visible and the toggle button
associated with it is pressed.
If a text field is empty, then it is not visible and the toggle button isn't pressed.
On CLICK of a toggle button :
If the text field associated with it has a value, then this field gets cleared (and invisible) and the toggle button gets de-pressed ;
If the text field associated with it is empty, then the focus is set on it and the toggle button gets pressed (and stay that way if a value is entered in the text field, otherwise everything gets back the way it was, invisible and unpressed).
So far I've achieved the first step by setting two collections of controls based on some examples I found online.
So, when the form is loaded, I call this :
Private mcolGroupTxToggle As New Collection
Private mcolGroupBuToggle As New Collection
Private Sub InitializeCollections()
Dim ctl As Control
If mcolGroupTxToggle.Count = 0 Then
For Each ctl In Me.Controls
If ctl.Tag = "txtoggle" Then
mcolGroupTxToggle.Add ctl, ctl.Name
End If
Next ctl
Set ctl = Nothing
End If
If mcolGroupBuToggle.Count = 0 Then
For Each ctl In Me.Controls
If ctl.Tag = "butoggle" Then
mcolGroupBuToggle.Add ctl, ctl.Name
End If
Next ctl
Set ctl = Nothing
End If
End Sub
And on Form_Current event, I call that :
Private Sub OnLoadToggles(mcol As Collection, pcol As Collection)
Dim ctl As Control
Dim btn As Control
Dim strBtn As String
For Each ctl In mcol
'Every button has the same name than the textbox + "b"
strBtn = ctl.Name & "b"
For Each btn In pcol
If btn.Name = strBtn Then
If IsNull(ctl) Then
ctl.Visible = False
btn.Value = False
Else
ctl.Visible = True
btn.Value = True
End If
End If
Next btn
Next ctl
Set ctl = Nothing
End Sub
Everything works well so far, but I'm not sure that's the best way to do it and I figured I would need to repeat some lines in step 2.
Making the distinction between text boxes and buttons in the procedure seems weird, I feel like it should be done prior so that I don't have to do it in every procedure. I also feel like it would be better to loop through each pair of controls (text + button) instead of each control in both collections.
Basically, I'm wondering if it would be (1) better and (2) possible to have something as simple as this :
Private Sub OnLoadToggles(Collection of pairs)
for each [pair of txt and btn]
if isnull(txt) Then
txt.visible = false
btn.value = false
else
...
end if
...
My guess is that I would need to make a public sub where I set a collection of pairs of buttons and text fields based on their tags (there are other controls in my form that need to be left alone) and names, but I'm not sure how, I'm a beginner in VBA.
Any suggestions please ?
-- Edit step 2 --
Thanks to Andre's answer the second part was easier than I thought. I've updated my sample database. So on click events I call this :
Private Sub ClickToggles()
Dim ctl As Control
Dim btn As Control
Dim strBtn As String
Dim strCtl As String
strBtn = Me.ActiveControl.Name
strCtl = Left(strBtn, Len(strBtn) - 1)
Set ctl = Me(strCtl)
Set btn = Me(strBtn)
If IsNull(ctl) Then
btn.Value = True
ctl.Visible = True
ctl.Enabled = True
ctl.SetFocus
Else
ctl.Value = ""
btn.Value = False
ctl.Visible = False
End If
End Sub
It's not perfect but it works. Probably not a good idea to clear the data at this point because misclicks may happen. It would be better to loop through the textboxes right before saving the form and clear values of invisible and/or disabled controls from the collection. I might to that later.
I had to add the .enabled property next to the .visible one because on lostfocus events I was getting an error saying the control was still active so it couldn't make it not visible.
Right now I'm more concerned about the amount of click and lost focus events. I'd rather have some public functions and event handlers dealing with it but it's getting too complicated for me. I'll get back to it when I know more about... everything.
Suggestions are still welcome anyway =) !
Since your control pairs are "paired" by their name anyway, you don't need any fancy constructs, or even the second collection. Just address the matching control directly by its name.
Instead of using If/Else for setting boolean properties, it is usually easier to assign a variable to the property.
Private Sub OnLoadToggles(mcol As Collection)
Dim ctl As Control
Dim btn As Control
Dim strBtn As String
Dim bShowIt As Boolean
For Each ctl In mcol
'Every button has the same name than the textbox + "b"
strBtn = ctl.Name & "b"
' If you have the control name, you can get the control directly:
Set btn = Me(strBtn)
' Using a variable you don't need If/Else
bShowIt = Not IsNull(ctl.Value)
ctl.Visible = bShowIt
btn.Value = bShowIt
Next ctl
' Note: this is not necessary for local variables - they go automatically out of scope
Set ctl = Nothing
End Sub

vba - Best Practice - Access Form Tab Control List Box Selected Items

What works ...
I have an Access I have a form, with a folder that has two pages or tabs. Each of these has it's own combobox related to the tabs topic. I wanted a fairly simply way to do this, by looking into the form, folder, tab I wanted, then pulling all selected values. I didn't know I was going to have to double for loop just to get this information.
Regardless, this is my good enough solution..
Private Sub getComboBoxInsideTabControl()
Dim selectedPage As Page
Dim pageIter As Page
Dim ctrl As Control
Dim varItm As Variant
Dim str As String
Set selectedPage = Me.folder1.Pages(1)
' GETS THE CONTROLS ON A PAGE
For Each ctrl In selectedPage.Controls
If ctrl.Name = "fields_lb" Then
MsgBox ("ok...")
' SEARCHES THROUGH A COMBOBOX CONTROLS SELECTED ITEMS
For Each varItm In ctrl.ItemsSelected
str = str & ctrl.ItemData(varItm) & ","
Next varItm
End If
Next ctrl
MsgBox (str)
End Sub
What I had hoped for ...
I really just want to know if there is a more simplistic way of doing it. For example, I kind of wanted something like this:
Dim results As String
Set results = Me.folder1.Pages(1).Controls("fields_lb").ItemsSelected
Is there a better way of doing this I am missing?

Save code-generated elements of form

VBA, Excel 2010.
Given:
MultiPage Userform
Script, which makes copies of a page (based on this question)
Process:
Open form (1 page in multipage, screenshot 1);
Copy a page by running script (2 pages in multipage, screenshot 2);
Close form;
Re-open form (again only 1 page, same as on Step 1);
Script code:
Private Sub CommandButton1_Click()
Dim l As Double, r As Double
Dim ctl As Control
Dim totalPageNum As Integer
'Get number of existing pages
totalPageNum = MultiPage1.Pages.Count
'Add new one
MultiPage1.Pages.Add
'Copy elements
MultiPage1.Pages(0).Controls.Copy
MultiPage1.Pages(totalPageNum).Paste
MultiPage1.Pages(totalPageNum).Caption = "Page" & MultiPage1.Pages.Count
'Copying frame coordinates
For Each ctl In MultiPage1.Pages(0).Controls
If TypeOf ctl Is MSForms.Frame Then
l = ctl.Left
r = ctl.Top
Exit For
End If
Next
For Each ctl In MultiPage1.Pages(totalPageNum).Controls
If TypeOf ctl Is MSForms.Frame Then
ctl.Left = l
ctl.Top = r
Exit For
End If
Next
End Sub
Question: How to make pages to be saved on re-open of form/file (so I could get 2 pages on Step 4)
P.S. Unfortunately, I can't post pictures yet to explain the question in a better way.
Thanks for help!
The only way to do this is to simply hide the UserForm instead of unloading it if it is within the same session of Excel. If you have to close Excel and reopen it then there is not a way to save.
I would suggest saving the info you need to create your pages on a VeryHidden Worksheet and dynamically create the UserForm each time.

VBA How do you copy and paste in a Userform using right-click?

I want to allow users to be able to paste values into TextBoxes in a userForm in VBA. You can use Ctrl-v just fine, but not everyone knows how to do that.
How do I enable copy and pasting using a right-click menu?
I realize this is an old post but I believe there is a more efficient method.
Userform Contextual Menu class code
http://www.andypope.info/vba/uf_contextualmenu.htm
There are even sample excel spreadsheets for the code examples.
The class module handles the construction of the contextual menu, the capture of right clicking in textboxes and the actual Cut. Copy and Paste actions. The class makes use of the userform's ActiveControl object. The code even handles controls within container controls such as Frames and Multipage.
The follow Initialization code, from the userform, shows how simple it is to define and use the class object. You only need declare a variable to the object and then set a reference for each textbox you want to have contextual menu capabilities. You can loop through all controls and automatically reference each textbox.
Private m_colContextMenus As Collection
Private Sub UserForm_Initialize()
Dim clsContextMenu As CTextBox_ContextMenu
Dim cTRL as Control
Set m_colContextMenus = New Collection
For Each cTRL In Me.Controls
Select Case TypeName(cTRL)
Case "TextBox"
'MsgBox cTRL.Name & ": " & Me.Controls(cTRL.Name).Value
Set clsContextMenu = New CTextBox_ContextMenu
With clsContextMenu
Set .TBox = Me.Controls(cTRL.Name)
Set .Parent = Me
End With
m_colContextMenus.Add clsContextMenu, CStr(m_colContextMenus.Count + 1)
Case Else
'MsgBox TypeName(cTRL) & ": " & cTRL.Name
End Select
Next
End Sub
Download example workbook which contains both .xls and .xlsm files
This may be of interest: http://word.mvps.org/faqs/userforms/AddRightClickMenu.htm