I have a Userform with several pages, one of which is called FXForward1 and if a certain condition is met I want to create a new page in the userform called FXForward2 that has all the same controls as FXForward1. Does anyone know how I can go about doing this? The following is the relevant part of the code I currently have and it's giving me the following error:
Run-Time Error '-2147319767(80028029)':
Could not paste the control. Invalid forward reference, or reference to uncompiled type
Sub UpdateForm()
Dim vbObject As Object
Dim objControl As Control
Dim OptionNumber As Integer
Set vbObject = ThisWorkbook.VBProject.VBComponents("UserForm1")
Set objControl = vbObject.Designer.Controls("MultiPage1")
' Other code here
If OptionNumber > 1 Then
objControl.Pages.Add ("FXForward" & OptionNumber)
objControl.Pages(FXForward1).Controls.Copy
objControl.Pages("FXForward" & OptionNumber).Paste ' This line is where I get the error
End If
UserForm1.Show
End sub
Related
I have an array oNam of TextBox names, I want to call a sub and pass an index number pointing to the specific TextBox I am working on to the sub. In the sub I use the following code, Dim MyControl As Control, and Set MyControl = Me![oNam(n)]. I get the following
Run-time error 2147024809: Could not find the specified object.
However, if I replace oNam(n) with the actual TextBox name, Me![tbxBuyNowPrice], I don't get the error. I included a Debug.Print oNam(n) and it holds the correct name.
I've replaced the variable with the actual name and it works.
Dim oNam() As Variant
....Call TextBoxControl(34)
Sub TextBoxControl(n As Integer)
Debug.Print oNam(n) <====Shows correct name
Set MyControl = Me![oNam(n)] <====GET THE ERROR HERE
If DVAL(n) = "Yes" Then
Call TextBoxSettings(MyControl, "", vbYellow)
MyControl.SetFocus
GoTo EndOfTextBoxControl
Else
Call TextBoxSettings(MyControl, 0, vbCyan)
End If
EndOfTextBoxControl:
End Sub
I have a userform “myUserForm” with dozens of controls whose TypeName() is “CheckBox”. I just hate having dozens of _Click() routines named like “Private Sub Chk1_Click()”, so in order to manage the quantity of _Click() routines, I simplified and made them nearly identical:
Private Sub Chk1_Click()
ProcessClickFor ("Chk1")
End Sub
Private Sub Chk2_A_Click()
ProcessClickFor ("Chk2_A")
End Sub
Private Sub Chk3_Z_Click()
ProcessClickFor ("Chk3_Z")
End Sub
ProcessClickFor() does most of the work.
Sub ProcessClickFor(anyCheckBox As String)
Dim cbControl As Object
Set cbControl = ControlByName(anyCheckBox)
If cbControl.Value Then
cbControl.Value = True
End If
End Sub
Later, when I want to work with any control, I can get the Control object by name, like:
Dim aControl As Object
Set aControl = ControlByName(“Chk3”)
MsgBox “The control named “ & cbControl.Name & “ is “ & cbControl.Visible
Function ControlByName(sName) As Object
Dim objectified As Object
For Each objectified In myUserForm.Controls
If objectified.Name = sName Then
Set ControlByName = objectified
Exit Function
End If
Next objectified
End Function
This works fine, almost, but it FAILS on the same four controls on myUserForm every time.
The failure “mode” is that ControlByName() seems to return successfully, but the first use of the returned control (such as my MsgBox) gives the error:
"Run-time error '91': Object variable or With block variable not set".
I verified that the spelling of the defined control names matches the names in my _Click() routines. Dozens of similarly designed CheckBox controls work perfectly. Could it have to do with the length of the CheckBox names or the number of “_” characters in the CheckBox names? Could there be a corrupt character in a CheckBox name? Can you think of other things for me to try?
I am using Ms-Access and I created a userform which has a number of Textboxes on it. The boxes are named: Box1, Box2, Box3 ...
I need to loop through all boxes, but I don't know which is the last one. To avoid looping through all userform controls I thought of trying the following:
For i =1 To 20
If Me.Controls("Box" & i).value = MyCondition Then
'do stuff
End If
Next i
This errors at Box6, which is the first box not found. Is there a way to capture this error and exit the loop when it happens.
I know I could use On Error but I 'd rather capture this specific instance with code instead.
Thanks,
George
A Controls collection is a simplified collection of controls (obviously) and share a same order as a placement order of controls.
First of all, even a creatable collection object lacks methods such as Exists or Contains , hence you need a function with error handling to checking/pulling widget from a collection.
Public Function ExistsWidget(ByVal Name As String) As Boolean
On Error Resume Next
ExistsWidget = Not Me.Controls(Name) Is Nothing
On Error GoTo 0
End Function
If you really doesnt like "ask forgiveness not permission" option you can pull entire ordered collection of your textboxes (and/or check existance by name in another loop with similar logic).
Public Function PullBoxes() As Collection
Dim Control As MSForms.Control
Set PullBoxes = New Collection
For Each Control In Me.Controls
If TypeOf Control Is MSForms.TextBox And _
Left(Control.Name, 3) = "Box" Then
Call PullBoxes.Add(Control)
End If
Next
End Function
Since names of widgets are unique - you can return a Dictionary from that function with (Control.Name, Control) pairs inside and able to check existance of widget by name properly w/o an error suppression.
There's a good guide to Dictionary if it's a new information for you.
Anyway, no matter what object you choose, if user (or code) is unable to create more of thoose textboxes - you can convert this Function above to a Static Property Get or just to a Property Get with Static collection inside, so you iterate over all controls only once (e.g. on UserForm_Initialize event)!
Public Property Get Boxes() As Collection
Static PreservedBoxes As Collection
'There's no loop, but call to PullBoxes to reduce duplicate code in answer
If PreservedBoxes Is Nothing Then _
Set PreservedBoxes = PullBoxes
Set Boxes = PreservedBoxes
End Property
After all, the last created TextBox with name Box* will be:
Public Function LastCreatedBox() As MSForms.TextBox
Dim Boxes As Collection
Set Boxes = PullBoxes
With Boxes
If .Count <> 0 Then _
Set LastCreatedBox = Boxes(.Count)
End With
End Function
I think that now things are clearer to you! Cheers!
Note: All code are definitely a bunch of methods/properties of your form, hence all stuff should be placed inside of form module.
Long story short - you cannot do what you want with VBA.
However, there is a good way to go around it - make a boolean formula, that checks whether the object exists, using the On Error. Thus, your code will not be spoiled with it.
Function ControlExists(ControlName As String, FormCheck As Form) As Boolean
Dim strTest As String
On Error Resume Next
strTest = FormCheck(ControlName).Name
ControlExists = (Err.Number = 0)
End Function
Taken from here:http://www.tek-tips.com/viewthread.cfm?qid=1029435
To see the whole code working, check it like this:
Option Explicit
Sub TestMe()
Dim i As Long
For i = 1 To 20
If fnBlnExists("Label" & i, UserForm1) Then
Debug.Print UserForm1.Controls(CStr("Label" & i)).Name & " EXISTS"
Else
Debug.Print "Does Not exist!"
End If
Next i
End Sub
Public Function fnBlnExists(ControlName As String, ByRef FormCheck As UserForm) As Boolean
Dim strTest As String
On Error Resume Next
strTest = FormCheck(ControlName).Name
fnBlnExists = (Err.Number = 0)
End Function
I would suggest testing the existence in another procedure per below: -
Private Sub Command1_Click()
Dim i As Long
i = 1
Do Until Not BoxExists(i)
If Me.Conrtols("Box" & i).Value = MyCondition Then
'Do stuff
End If
i = i + 1
Next
End Sub
Private Function BoxExists(ByVal LngID As Long) As Boolean
Dim Ctrl As Control
On Error GoTo ErrorHandle
Set Ctrl = Me.Controls("BoX" & LngID)
Set Ctrl = Nothing
BoxExists = True
Exit Function
ErrorHandle:
Err.Clear
End Function
In the above, BoxExists only returns true if the box does exists.
You have taken an incorrect approach here.
If you want to limit the loop, you can loop only in the section your controls reside e.g. Detail. You can use the ControlType property to limit controls to TextBox.
Dim ctl As Control
For Each ctl In Me.Detail.Controls
If ctl.ControlType = acTextBox Then
If ctl.Value = MyCondition Then
'do stuff
End If
End If
Next ctl
I believe the loop will be faster than checking if the control name exists through a helper function and an On Error Resume Next.
But this only a personal opinion.
I have a two list boxes with one button when the user can click the button move all the list item from listbox1 to listbox2. when the listbox1 is becomes empty app is getting restarted IN EXCEL 2016.
My Code is
For i = 1 To ThisWorkbook.Sheets("MultiSheet").ListBoxes(strFromlb).listCount
ThisWorkbook.Sheets("MultiSheet").ListBoxes(strTolb).AddItem ThisWorkbook.Sheets("MultiSheet").ListBoxes(strFromlb).List(1)
ThisWorkbook.Sheets("MultiSheet").ListBoxes(strFromlb).RemoveItem (1)
Next i
Here strFromLb is clearing the values but when it clearing last value my VBA App is excel has been restarted.
Then I have tried code to clear the listbox
ThisWorkbook.Sheets("MultiSheet").ListBoxes(strFromlb).ControlFormat.RemoveAllItems
ThisWorkbook.Sheets("MultiSheet").ListBoxes(strFromlb).Items.Clear
The error is
"Object doesnt supported to property or method"
Then
ThisWorkbook.Sheets("MultiSheet").ListBoxes(strFromlb).Clear
This code I got the 400 error. so kindly help me.
Worksheets("MultiSheet").ListBoxes(strFromlb).ControlFormat.RemoveAllItems
Reference: The Complete Guide to Excel VBA Form Control ListBoxes
There are two type listbox controls for the worksheet Forms control and MsForms ActiveX control. getListBox will return get either one.
You code has a couple of syntax errors in it
Listbox.List returns a 0 based array
You don't use parentheses when using RemoveItem because it is a not a function
Dim lBoxFrom As Object, lBoxTo As Object
Set lBoxFrom = getListBox("MultiSheet", strFromlb)
Set lBoxTo = getListBox("MultiSheet", strTolb)
For i = 0 To lBoxFrom.ListCount - 1
lBoxTo.AddItem lBoxFrom.List(1)
lBoxFrom.RemoveItem 1
Next
or
lBoxTo.List = lBoxFrom.List
lBoxFrom.Clear
Sub Test()
Const WORKSHEET_NAME = "Sheet1"
Const strFromlb = "BoxFrom"
Const strTolb = "BoxTo"
Dim lBoxFrom As Object, lBoxTo As Object
Dim i As Integer
Set lBoxFrom = getListBox(WORKSHEET_NAME, strFromlb)
Set lBoxTo = getListBox(WORKSHEET_NAME, strTolb)
lBoxFrom.AddItem "A"
lBoxFrom.AddItem "B"
lBoxFrom.AddItem "C"
For i = 0 To lBoxFrom.ListCount - 1
lBoxTo.AddItem lBoxFrom.List(0)
lBoxFrom.RemoveItem 0
Next
End Sub
Function getListBox(WorkSheetName As String, ListBoxName As String) As Object
Dim lBox As Object
On Error Resume Next
Set lBox = Worksheets(WorkSheetName).ListBoxes(ListBoxName)
On Error GoTo 0
If lBox Is Nothing Then
On Error Resume Next
Set lBox = Worksheets(WorkSheetName).Shapes(ListBoxName).OLEFormat.Object.Object
On Error GoTo 0
End If
Set getListBox = lBox
End Function
I try to create a macro, placed in Workbook_Open() procedure, which adds items for combo boxes, named CBTask for each sheet in workbook, (which has combo box named CBTask in it).
Unfortunatelly following code generates Compile error: Method or data member not found"
I believe it is because not every sheet has CBTask in it (even on error resume next does not help).
Is there any way to check if sheet contains combo box, so I could do the checking before trying clear it, or adding new items?
Private Sub Workbook_Open()
Dim ws As Worksheet
Dim i As Integer
Dim strTaskName As String
On Error Resume Next
For Each ws In ThisWorkbook.Worksheets
ws.CBTask.Clear
strTaskName = taskName(1)
Do
ws.CBTask.AddItem strTaskName
strTaskName = taskName(i)
i = i + 1
Loop While taskName <> "LastOne"
Next ws
On Error GoTo 0
End Sub
(as you can see, this code also uses additional function "taskName(intSubtaskValue as integer)" to convert integer to string (e.g. taksName(1) = "Task01", taskName(2) = "Task02...)
The Worksheet class doesn't have a member named CBTask which is why that code fails. I suggest you use the OLEObjects property instead:
ws.OLEObjects("CBTask").Object.Clear
To expand on Rory's answer, in addition to fully qualifying your objects, you can check if an ActiveX-control of a given name exists on a worksheet by using this function:
Function obj_exists(obj_name As String, on_worksheet As Worksheet) As Boolean
On Error GoTo errHandler
Debug.Print on_worksheet.OLEObjects(obj_name).Name
obj_exists = True
On Error GoTo 0
Exit Function
errHandler:
obj_exists = False
On Error GoTo 0
End Function