I am working on a userform trying to loop through the controls in a multipage.
The user form has 2 Multipages (MultiPage1 and MultiPage2).
Multipage2 is contained within the Multipage1.
When only MultiPage1 exists I could ran the following code:
For Each pPage In frmValidationTest.MultiPage1.Pages
But after creating this nested system, and I trying to run it again, displays the following error:
"Type Mismatch" (in the For Each pPage line)
The variable pPages is declared as follows:
Dim pPage as Page
I've ran Debug.Print Mode to check misspelling issues but everything is OK ("frmValidationTest.MultiPage1.Pages.Name" does actually print out an output)
When I take a look at the pPages, it declares that the variable is Nothing.
I just realized that when declaring the variable, I have 2 classes with the same name "Page".
Not sure what's going on, is that normal? I don't think I should have 2 different classes for the same superclass. (-F2- Ref Lib only shows 1).
After closing, restarting, etc. The issue still there.
Hopefully is just a minor thing!
Many thanks in advance.
There is a Page class in both the Excel and MSForms libraries. So you will be better off using the library names in your declarations. For example, if your form looks like this:
Then this code should work:
Option Explicit
Private Sub CommandButton1_Click()
' declare variables using specific libraries
Dim mpgItem1 As MSForms.MultiPage
Dim mpgItem2 As MSForms.MultiPage
Dim pagItem1 As MSForms.Page
Dim pagItem2 As MSForms.Page
' other variables
Dim ctlItem As Control
Dim intCounter1 As Integer
Dim intCounter2 As Integer
Dim intPageCount1 As Integer
Dim intPageCount2 As Integer
Set mpgItem1 = UserForm1.MultiPage1
' get page count of first multi page
intPageCount1 = mpgItem1.Pages.Count
' not using for..each loop ...
For intCounter1 = 0 To intPageCount1 - 1
Set pagItem1 = mpgItem1.Pages(intCounter1)
MsgBox pagItem1.Name
For Each ctlItem In pagItem1.Controls
' looking for nested multi page
If TypeName(ctlItem) = "MultiPage" Then
' same code as for first multipage
Set mpgItem2 = ctlItem
intPageCount2 = mpgItem2.Pages.Count
For intCounter2 = 0 To intPageCount2 - 1
Set pagItem2 = mpgItem2.Pages(intCounter2)
MsgBox pagItem2.Name
Next intCounter2
End If
Next ctlItem
Next intCounter1
End Sub
Related
Excel now has the possibility to store personal filtering views to help collaboration in simultaniously used documents.
I could only find Microsoft documentation for an add-in, but the function is available in my Excel version of MS Excel for Microsoft 365 MSO (16.0.13127.20266) 32bit.
https://learn.microsoft.com/en-us/javascript/api/excel/excel.namedsheetview?view=excel-js-preview
I am trying to store the currently applied NamedSheetView name property (for later restoring option) but
this code fails:
Dim sh1 As Worksheet
Dim xViewName As String
Set sh1 = ThisWorkbook.Sheets(Sheet6.Name)
xViewName = sh1.NamedSheetView.Name
However this code works (with previously created "Test" view):
sh1.NamedSheetViews.GetItem("Test").Activate
If this NamedSheetViews is a collection, I should be able to get the item property, but these codes also fail:
strName = sh1.NamedSheetViews.GetItem(1).Name
strName = sh1.NamedSheetViews.Item(1).Name
Anyone has ever succeeded in getting the current NamedSheetView of a Worksheet?
Here is how I probe unknown Object properties:
I start with a reference to the Object. If I don't know what the Object is I use TypeName() to return it's class name (data type). I then declare a variable of that data type. Wash, rinse and repeat as I drill down the structure. Once the variable is declared, selecting the variable and pressing F1 with open the Microsoft Help document for that data type.
Module Code
Sub WhatIsThat()
Const TestName As String = "TestName"
Dim View As NamedSheetViewCollection
Set View = Sheet6.NamedSheetViews
On Error Resume Next
View.GetItem(TestName).Delete
On Error GoTo 0
View.Add TestName
Dim SheetView As NamedSheetView
Dim n As Long
For n = 0 To View.Count - 1
Debug.Print View.GetItemAt(n).Name
Set SheetView = View.GetItemAt(n)
Debug.Print SheetView.Name
Next
Stop
End Sub
Immediate Window Tests
?TypeName(Sheet6.NamedSheetViews)
?View.GetItemAt(0).Name
?TypeName( View.GetItemAt(0))
SOLUTION:
(Thanks for the great help from TinMan)
Dim SheetView As NamedSheetView
Dim sh1 As Worksheet
Dim ActiveSheetView as string
Set sh1 = ThisWorkbook.Sheets(Sheet6.Name)
Set SheetView = sh1.NamedSheetViews.GetActive
ActiveSheetView = SheetView.Name
Application:
sh1.NamedSheetViews.GetItem(ActiveSheetView).Activate
I have an array loaded with cell addresses that are passsed into a sub that handles tab order on a sheet. I want to be able to put a control name, i.e. "MyListBox" in that array and have my function handle it. However, I cannot get it to resolve in the .activate method. If I implicitly name the control it will work but I need it to "macro expand / resolve" to the actual control name so I can say Array(x).Activate.
Here is the code I'm fumbling with to no avail. I've tried it with and without the MSFORMs declaration. I've tried concatenating the command "activesheet." & arr(x) and many other things. I'm pretty sure I'm probably missing something simple but can't seem to find it.
Sub TabIntercept()
Dim arr, a, x, nxt, sel
Dim cMyListBox As MSForms.ListBox
If TypeName(Selection) <> "Range" Then Exit Sub 'Exit if (eg) a shape is selected
Set sel = Selection.Cells(1) 'if multiple cells selected use the first...
arr = GetTabOrder(ActiveSheet.Name) 'this function loads the tab order from a table
If UBound(arr) = -1 Then
Application.OnKey "{TAB}"
Exit Sub
End If
For x = LBound(arr) To UBound(arr)
If Left(arr(x), 3) = "lst" Or Left(arr(x), 3) = "cmb" Then 'Look for a control - they all start with lst/cmb
Set cMyListBox = Sheets("Resources & Process").arr(x) 'HERE IS THE ISSUE
arr(x).Activate
End If
If sel.Address() = sel.Parent.Range(arr(x)).Address() Then
'loops back to start if at end...
nxt = IIf(x = UBound(arr), LBound(arr), x + 1)
sel.Parent.Range(arr(nxt)).Select
Exit For
End If
Next x
End Sub
Set cMyListBox = Sheets("Resources & Process").arr(x) 'HERE IS THE ISSUE
First, declare a Worksheet variable for that sheet; the Workbook.Sheets property returns an Object, so all these member calls are implicitly late-bound, and you're coding blindfolded without compiler assistance.
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Worksheets("Resources & Process")
Note the ActiveWorkbook qualifier: if you have a specific Workbook object to use instead, use that. But consider always qualifying Workbook member calls, otherwise you're implicitly referring to whatever the ActiveWorkbook is, and eventually that will not be the workbook you're expecting.
Now, sheet.arr(x) isn't going to work, as IntelliSense is now showing you when you type that . dot operator: a Worksheet object would have to expose an indexed property named arr for that to work.
What you want to do, is get the OLEObject that is named whatever the value of arr(x) is.
You get OLE objects from the Worksheet.OLEObjects property:
Dim oleControl As OLEObject
Set oleControl = sheet.OLEObjects(arr(x))
If that succeeds, you've found your MSForms control - but it's wrapped in an OLE object and we now just need to unwrap it:
Set cMyListBox = oleControl.Object
If that fails, then the MSForms control isn't compatible with the declared type of cMyListBox. But now you get IntelliSense and compile-time validation for member calls against it: if you type cMyListBox. and there's an Activate member, then the call should be valid at run-time.
I want to embed an explorer-window into my excel worksheet, to display some folder contents that are related to my workbook.
I use the following code, which works quiet well:
Sub AddOleBrowser()
Dim OleBrowser As OleObject
Dim Browser As Object
Set OleBrowser = ActiveSheet.OLEObjects.Add(ClassType:="Shell.Explorer.1", Link:=False, DisplayAsIcon:=False)
Set Browser = OleBrowser.Object
Browser.Navigate "X:\" 'Actually some network-path related to my workbook-path
OleBrowser.Activate
End Sub
My problem is, that the OleBrowser keeps getting replaced by a low-res image, displaying the contents of the folder instead, whenever I click somewhere into my worksheet. When I double-click it, it returns to the normal browser view until it loses focus again. I want to add multiple browser windows to my worksheet, so they all should stay "activated".
I also tried to add a frame instead, which then holds a browserobject:
Sub AddOleFrameWithBrowser()
Dim OleFrame As OleObject
Dim CtrlBrowser As Control
Dim Browser As Object
Set OleFrame = ActiveSheet.OLEObjects.Add("Forms.Frame.1", Link:=False, DisplayAsIcon:=False)
Set CtrlBrowser = OleFrame.Object.Controls.Add("Shell.Explorer.2", "Browser") 'Frame1 is an MSForms.Frame-object that I placed there before.
CtrlBrowser.Left = 0
CtrlBrowser.Top = 0
CtrlBrowser.Width = OleFrame.InsideWidth
CtrlBrowser.Height = OleFrame.InsideHeight
Set Browser = CtrlBrowser.Object
Browser.Navigate "X:\" 'Actually some network-path related to my workbook-path
OleFrame.Activate
End Sub
The second option works somewhat OK but when I switch to another worksheet and return, my frame is empty and I can't get a valid reference to my "Browser" control.
Sub CheckFrame()
'
Dim CheckBrowser As Object
Set CheckBrowser = ActiveSheet.OleObjects(1).Object.Controls("Browser").Object
Stop
'CheckBrowser now actually contains the correct WebBrowser-object,
'but when I run this sub (after I return to my Worksheet
'with the Frame-OleObject) all it's properties either
'contain falsified data or may not be accessed by the debugger...
'Everything is fine, when I run this sub right after
'my AddOleFrameWithBrowser()-Sub.
ActiveSheet.OleObjects(1).Activate '<- Does not help
End Sub
Additionally whenever I try to do something with the folder-items inside my embedded explorer, it displays some security warning because the path is not on my local machine. This warning does not appear when I add the Shell.Explorer-OleObject directly with AddOleBrowser().
Could someone please give me some advice?
I was following some examples online in which im trying to pass a value from one sub into a another sub in VBA but get the error:
Compile Error:
Procedure declaration does not match description of event or procedure having the same name.
Sub next_sat_click()
Dim iweekday As Integer
Dim nextsat As String
Dim index As Integer
Dim str_game_date As String
iweekday = weekday(Now(), vbSunday)
nextsat = Format((Now + 7 - iweekday), "mm-dd-yy")
Call set_button_Click(nextsat)
End Sub
Sub set_button_Click(ByRef nextsat As String)
......
End Sub
Change the sub name in something else like SetButtonOnClick.
The _Click keyword is reserved by excel for the Click event on buttons if you have a button called with the same name.
You can't change the parameters for an event handler (except for the parameter name). That also means you can't add any parameters if none are expected. Not even Optional ByRef nextsat As String will work.
There are three ways to pass a value between event handlers in a UserForm:
Using a global variable (not recommended, ever);
Via the UserForm.tag property (recommended for simple values such as strings). Obviously cannot be used if it already has a permanent use;
Via one or more hidden controls (recommended for multiple or complex values as well as simple ones).
I've used the second method:
Sub next_sat_click()
Dim iweekday As Integer
Dim nextsat As String
Dim index As Integer
Dim str_game_date As String
iweekday = Weekday(Now(), vbSunday)
nextsat = Format((Now + 7 - iweekday), "mm-dd-yy")
Me.Tag = nextsat
End Sub
Sub set_button_Click()
Dim nextsat As String
nextsat = Me.Tag
......
End Sub
A better solution in your case might be to have a visible TextBox in which you store the calculated date when the user clicks next_sat, so that the user can see it. Then in your set_button handler, grab it from TextBox.Text.
I have a button in Access (2003) that transfers data to Excel (also 2003). It opens the Excel workbook, then cycles through the Access subforms and transfers data.
To give more information on how this works, Excel has a range called "Tables" which contains the names of the Access subforms ("Main", "Demographics", "History", etc). Excel also has a range for each of the names in that first range. For example, the range "Demographics" contains a series of field names ("FirstName", "LastName", etc). So the first loop moves through the subforms, and the nested loop moves through the field names. Each field then passes the value in it over to excel. Excel also has ranges for "Demographics_Anchor" and "History_Anchor" etc, which is the first value in the column next to each range (ie the range Demographics has firstname, lastname, and to the right is where the data would go. So the first item in the range is FirstName, to the right "Demographics_Anchor" is where firstname will go. Then LastName goes to Demographics_Anchor offset by 1 - or 1 cell down from the anchor).
Dim ThisForm As Form
Dim CForm As Object
Dim CTab As TabControl
Dim CControl As Control
Dim CurrentTab As Variant
Dim CControlName As Variant
Dim CControlValue As String
Dim Code As Control
Dim counter1 As Integer
Dim appExcel As Object
Dim Anchor As Object
Dim PageRange As Object
Dim ControlNameRange As Object
strpath = "C:\blah\blah\filename.xlsm"
Set appExcel = CreateObject("Excel.Application")
appExcel.Workbooks.Open Filename:=strpath, UpdateLinks:=1, ReadOnly:=True
Set wbk = appExcel.ActiveWorkbook
Set PageRange = appExcel.Range("Tables")
'set Access environment
Set ThisForm = Forms("frmHome")
Set CTab = ThisForm.Controls("Subforms")
'export the data from Access Forms to Excel
For Each CurrentTab In PageRange
If CurrentTab = "Main" Then
Set CForm = ThisForm
Else
CTab.Pages(CurrentTab).SetFocus
Set CForm = ThisForm.Controls(CurrentTab & " Subform").Form
End If
Set ControlNameRange = appExcel.Range(CurrentTab)
Set Anchor = appExcel.Range(CurrentTab & "_Anchor")
counter1 = 0
For Each CControlName In ControlNameRange
Set CControl = CForm.Controls(CControlName)
CControl.SetFocus
Anchor.Offset(RowOffset:=counter1).Value = CControl.Value
counter1 = counter1 + 1
Next CControlName
Next CurrentTab
I hope this explains what is going on in the code. I just can't figure out why this keeps bombing out with type mistmatch (error 13).
The data DOES transfer. It goes through the entire code and every piece of data correctly gets transferred over. It bombs out at the end as if it goes through the code 1 last time when it shouldn't. I did confirm that every range is correct and doesn't contain any null values. The code bombs out on this line: Set CControl = CForm.Controls(CControlName) which is towards the bottom of the second loop.
Please help! I've spent weeks working with this code and had no luck. This exact code works in every other database I've worked with.
You are getting the name of the control CControlName from your Excel Range, but then setting the value of this control to the control on the Access form Set CControl = CForm.Controls(CControlName). From this, the most likely explanation is probably that the CControlName isn't actually on the Access form (perhaps a typo?).
In the VBA IDE, go under the Tools Menu, select Options and then select the General tab. Under the Error Trapping section, select the "Break on All Errors" option and click "OK" to set the preference. Run your code again; when an error is encountered VBA will stop processing on the line that caused the error. Check the value of CControlName and make sure it actually exists on the Access form.