How to cycle between tabs on a tab? - vba

My Access form "frmLoad" has five tabbed pages. One of those pages has a subform "frmClients" with a few dozen tabbed pages.
I need to cycle through each tabbed page on frmClients, Debug.Print the tab name, modify certain labels, and go on to the next.
(I don't have to access any other tabs on frmLoad; I only mention it in case we have to fully qualify everything.)
The documentation I've been reading is confusing. I'm not sure of the difference between a Page and a Tab, for one thing.

You can reference the Tab Pages from the frmClients' Controls collection.
Run this in a standard Module and it will Debug.Print the needed references.
Sub PrintLabelsReferences()
Dim ctrl As Object, pageCtrl As Object
For Each ctrl In Forms("frmLoad").Controls("frmClients").Controls
If TypeName(ctrl) = "Page" Then
For Each pageCtrl In ctrl.Controls
If TypeName(pageCtrl) = "Label" Then
Debug.Print "Me.Controls(""frmClients"").Controls("""; pageCtrl.Name; """).Caption ="""; pageCtrl.Caption; """"
Debug.Print "Forms(""frmLoad"").Controls(""frmClients"").Controls("""; pageCtrl.Name; """).Caption ="""; pageCtrl.Caption; """"
End If
Next
End If
Next
End Sub
Uses the Forms() reference if you want to modify the Label.Caption from outside of the form or use Me if you want to reference the Label.Caption from within the Form's code module.

Related

How does Tab Index work if the control's enabled property is false

If I'm viewing a form and I set the enabled property of the control with tab index = 0, does the cursor then move to the next tab index? Do I need to, and is there a way, to force the tab to set to the first control with Enabled = True?
So in order to achieve this (assuming there are no panels on your form), this is how you could iterate through the controls in tab order. The first control which you encounter and which is enabled, you set the focus on it and leave the Sub. The myFirstControl variable is initialized by you with the first control in the tab order list of the form.
Private Sub IterateControls()
Dim ctrl As Control = myFirstControl
While ctrl IsNot Nothing
If ctrl.Enabled = True Then
Me.ActiveControl = ctrl
Exit Sub
End If
ctrl = Me.GetNextControl(ctrl, True)
End While
End Sub
If you have panels also, you should build a dictionary of panels (with the panel as key, its first control as value) and take them one by one using a For loop. The For loop should be placed to include the whole method's code, but this time you initiate the ctrl variable with the first control from the panel (i.e. the value of the current dictionary entry), instead of the first control of the Form, and also you would call myPanel.GetNextControl(...) instead of Me.GetNextControl(...). The other code lines should remain the same. If this is not helpful enough, add a comment and I will edit my answer.

Access Navigation Subform, recordsource

I am working with MS Access and I am currently trying out the navigation sub-forms. However I am finding it difficult to understand how to simply change the recordsource of a sub form. One of the tabs within my "NavigationSubform" is called "nbCustomerList", which has the target navigation name "CustomerList". Within the CustomerList form, there is a button which when clicked opens a popup which allows you to filter the query on CustomerList. How do I achieve a change to recordsource from an event like this?
Private Sub btnSearch_Click()
On Error GoTo HandleError
If CurrentProject.AllForms("MainMenu").IsLoaded Then
[Forms]![CustomerList].RecordSource = CustomerListFilter()
[Forms]![MainMenu]![NavigationSubform].Requery
End If
''ErrorHandling'''''''''''''''''''''''''''''''''''''''''''''''''''''''
HandleExit:
Exit Sub
HandleError:
MsgBox (Err.Number & ": " & Err.Description)
Resume HandleExit
End Sub
The following test worked for me:
Forms![Navigation Form].NavigationSubform.Form.RecordSource = "SELECT * FROM Rates WHERE ID=2"
Assuming your form design has the default names of [Navigation Form] and NavigationSubform assigned by Access, in your db try:
[Forms]![Navigation Form].NavigationSubform.Form.RecordSource = CustomerListFilter()
Requery command was not necessary.
I don't use Navigation Form design. Keep in mind that no matter how many tabs are set up, only one subform is available at any time. Nature of Navigation Form is that it loads and unloads subforms as called by click on tabs.

Sub to add controls works when called from one sub but the other

I am getting an error that I just can't figure out. I wrote a sub that opens a form in Design view, deletes all of the dynamic controls, then adds the requested number.
The sub gets called in two different ways. The user opening the form (via a Main Menu form) to fill out a new form (so the dynamic controls are deleted then recreated) OR after the form is created, the user can click a button on the form to add more rows of controls. Both the Main Menu and button form call the same sub, BUT when the button is clicked the code gets stuck and error 29054 'Microsoft Access can't add, rename, or delete the control(s) you requested.' is thrown. The button to debug is deactivated so I can't see what line is actually getting stuck, but when I step through the code this is the last line before the error pops up (the last indent block in the context below):
With Application.CreateControl("BOM5", acComboBox, acDetail, frm.Controls("Tabs").Pages(PageNum).Name, , ChangeTypeLeft, LastControlTop, ChangeTypeWidth, ControlHeight)
The rest of the code is as follows.
DoCmd.OpenForm "BOM5", acDesign
Set frm = Application.Forms("BOM5")
' Cycle through controls and set LastControlTop based on the last dynamic control, if any
For i = 0 To frm.Controls.Count - 1
Set ctl = frm.Controls(i)
Debug.Print ctl.Name
If ctl.Tag Like DYNAMIC_TAG & "*" Then
If ctl.ControlType = acComboBox Or ctl.ControlType = acTextBox Then
LastControlTop = ctl.Top + ControlHeight + ControlPadding
FormRowCount = FormRowCount + 1
End If
Else
FormRowCount = (FormRowCount / 6) + 1 ' Convert number of fields to number of rows then add one to start new batch of controls
Exit For
End If
Next
PageNum = frm.Controls("Tabs").Pages.Count - 1 ' .Pages has an index of 0. Getting PageNum to follow suit with the -1
' Add controls for inputting parts
For FormRowCount = FormRowCount To NewControlCount
With Application.CreateControl("BOM5", acComboBox, acDetail, frm.Controls("Tabs").Pages(PageNum).Name, , ChangeTypeLeft, LastControlTop, ChangeTypeWidth, ControlHeight)
.Name = "ChangeType" & FormRowCount
.Tag = DYNAMIC_TAG
.RowSourceType = "Table/Query"
.RowSource = "ChangeType"
End With
The last for loop has 5 other With Application.CreatControl statements, but I just showed the first one. The other 5 are similar except text boxes instead of combo.
I've had this error before, but I think I resolved it by moving the DoCmd.OpenForm statement to a different part of the code (like out of an if statement or for loop or somewhere that wasn't letting it get called) but I don't think that will resolve it. Besides, the first for loop iterates correctly since I see it grabbing the control height of the last dynamic control.
You can't do this. A form or report can only hold a certain amount of controls, deleted or not, so - eventually - it will not accept more controls. At that point, you must recreate the form from scratch.
So, don't delete the controls. Create those you may need and, at any time, hide those not needed and rename the rest if necessary.

Word VBA: Sharing variables between documents

I feel like this should be obvious, I'm just not finding the answer anywhere.
I have a Word document with several Public variables declared and defined in a variety of procedures. One procedure opens another Word document, which has a form that loads on open. For the life of me I cannot get that form in the second document to use values from the original document's variables. Am I misunderstanding the nature of Public variables? Everything I've found seems to indicate that those values should be visible to the newly opened document.
So to open the second document, I'm using the code below (some of it is declared and set elsewhere, but I think this is the relevant stuff:
Public iMarker as boolean
Sub OpenDoc()
If check_ExA.Value = True Then 'a checkbox on a userform
docName = docsPath & "/" & "seconddocumentpath.docm"
iMarker = True
formAddDocs.Hide
Set addDoc = Documents.Open(docName)
End Sub
from there, the new document has a form that shows on Open, and in the initialization, I want it to be able to see if the iMarker variable is true, among some other strings, etc.
Private Sub UserForm_Initialize()
If iMarker = True Then
'do some other stuff
End If
End Sub
I tried changing that Initialize sub to public and that did nothing. It won't see that iMarker is true when the second document opens. Any suggestions?
To make a public variable of doc01 ("source doc") available to doc02 ("target doc") document, go like follows:
open the "source doc"
open the "target doc"
click Tools-> References
from Available References listbox of the References dialog box click the "Project" of the "source doc"
You can recognize it from the path appearing near the dialog box bottom
Otherwise
close Reference dialog box
go to "source doc" and rename its project (Tools->project properties, edit "project name" textbox and click "OK") with a meaningful name (say "MainProject")
go back to "target doc" project
open References dialog box and now from Available References listbox click the "MainProject" reference
Save and close target doc

Userform MultiPage Navigation

I have a Userform I built in Excel that has roughly ten tabs utilizing the MultiPage setup. Problem is I am running out of space for additional tabs and would really like to replace the tabs with a friendlier Navigation Menu or Toolbar. I've looked into the Microsoft ToolBar Control, which is close to what I'm looking for but I can't change the height and the dropdown has to have the arrow clicked and nto the text, which is not that intuitive in my opinion.
So my question is, are any of you familiar with a better multipage navigation setup, perhaps using a form of ActiveX?
I would reccommend seperating your User Form into seperate forms or Child forms based on category.
You can have one form launch another one if they are both Modeless, and both can be on screen at the same time. This way, you can work with both consecutively.
To launch a form as modeless, when you do Form1.Show change it to Form1.Show vbModeless
What I ended up doing was making a Listbox with all my different pages that is apart of my Multipage then placed this listbox on the left hand side of my Userform then used this code
Populate the listbox
i = 0
With Main_Window.form_navigation_list
.AddItem "Domestic"
.List(i, 0) = "Page 1"
.List(i, 1) = 0
i = i + 1
.AddItem
.List(i, 0) = "Page 2"
.List(i, 1) = 1
i = i + 1
End With
Then I have this for the on click
Private Sub form_navigation_list_Click()
Dim i As Integer
Dim SelectedRow As Integer
For SelectedRow = 0 To Main_Window.form_navigation_list.ListCount - 1
If Main_Window.form_navigation_list.Selected(SelectedRow) Then
nav_page = Main_Window.form_navigation_list.List(SelectedRow, 1)
With Main_Window
.MultiPage1.Value = nav_page
.Show
End With
End If
Next
End Sub
I started off using a flexgrid but kept getting a memory leak issue and program would crash, so I swapped to the listbox and it's working fine now. Now I can customize this listbox to look a bit more like the navigation I want.