I have a form in an xlam. I would like the form to be usable in an xlsm.
With the help of ThunderFrame's link, I think I am close, but have no idea where to go from here.
I followed the steps in https://stackoverflow.com/questions/45231935/userform-in-excel-sheet-can-it-be-made-an-add-in, but get error "Compiler error: Method or data member not found" when I add code to a toggle button. I tried adding the GetUserForm function in the xlam's form code, which failed, then in an xlsm's module, which failed. Here is my code:
Public Function GetUserForm() As frmQuickQuote
Set GetUserForm = New frmQuickQuote
End Function
Here is my toggle button code:
Private Sub tglQQ_Click()
Dim frm As PRI_Comp_Life.frmQuickQuote
If tglQQ Then
tglQQ.BackColor = lngPressed
Set frm = PRI_Comp_Life.GetUserForm()
frm.Show
Else
tglQQ.BackColor = lngUnPressed
Unload frmQuickQuote
End If
End Sub
I was expecting the form to load when I pressed the toggle button tglQQ, and unload when I pressed it again. Thanks.
EDIT: form now showing, but getting an error "Method 'Range' of object '_Global' failed" when the form loads. Form code:
Private Sub cmdReset_Click()
Dim MyLoop As Integer
'Set defaults
Me.cboRepLevel = Range("rngDefaultContract") 'errors here
With Me.cboAge
For MyLoop = 18 To 70
.AddItem MyLoop
Next MyLoop
End With
End Sub
This works for me.
In the ThisWorkbook module of the add-in
Public Function GetForm() As Object
Dim frm As frmTest
Set frm = New frmTest 'a form in the add-in
Set GetForm = frm
End Function
Button code:
Private Sub ToggleButton1_Click()
Dim addin As Object
Static frm As Object
If ToggleButton1.Value Then
Set addin = Workbooks("test.xlam")
Set frm = addin.getform()
frm.Show vbModeless
Else
Unload frm
End If
End Sub
Note it's all very late-bound.
Related
I have created a multipage user form which dynamically populates with a set of identical frames and each of them has 2 option buttons based on previous user selections. I am trying to check if at least one of the option buttons is selected within each frame but don't seem to access the option buttons in code even through I know what their names will be. I will then be transferring the selection to a worksheet so need to be able to see what they have selected. Any help would be appreciated, I use VBA for excel infrequently so its always a struggle to be honest.
I'm getting closer, I've used this code of another post and changed it slightly while I trial what I am doing. Getting there slowly. :)
I'm not sure what some of the Class modules part is doing but its working.
Forms: Userform1
Option Explicit
Friend Sub OptionButtonSngClick(o As MSForms.OptionButton)
Dim cControlCheck As MSForms.Control
Dim cControlCheck1 As MSForms.Control
Dim cControlFrame As MSForms.Control
Dim strName As String
If Left(o.Name, 2) = "qN" Then
o.BackColor = RGB(256, 0, 0)
ElseIf Left(o.Name, 2) = "qY" Then
o.BackColor = RGB(0, 256, 0)
End If
For Each cControlCheck In UserForm1.Controls
If TypeName(cControlCheck) = "Frame" Then
For Each cControlCheck1 In Me.Controls(cControlCheck.Name).Controls
If TypeName(cControlCheck1) = "OptionButton" Then
If cControlCheck1 = False Then
cControlCheck1.BackColor = RGB(240, 240, 240)
End If
End If
Next
End If
Next
End Sub
Friend Sub cmdCheck_Click()
Dim cControlCheck2 As MSForms.Control
Dim cControlCheck3 As MSForms.Control
Dim cCollection As Collection
Set cCollection = New Collection
For Each cControlCheck2 In UserForm1.Controls
If TypeName(cControlCheck2) = "Frame" Then
For Each cControlCheck3 In Me.Controls(cControlCheck2.Name).Controls
If TypeName(cControlCheck3) = "OptionButton" Then
cCollection.Add cControlCheck3
End If
Next
End If
Next
If cCollection(1).Value = False And cCollection(2).Value = False Then
MsgBox ("Make a selection")
End If
End Sub
Class Module: OPtionButtonEvents
Option Explicit
Private WithEvents ob As MSForms.OptionButton
Private CallBackParent As UserForm1
Private CallBackParent1 As UserForm1
Private Sub ob_Change()
End Sub
Private Sub ob_Click()
Call CallBackParent.OptionButtonSngClick(ob)
End Sub
Private Sub ob_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Call CallBackParent.OptionButtonDblClick(ob)
End Sub
Friend Sub WatchControl(oControl As MSForms.OptionButton, oParent As UserForm1)
Set ob = oControl
Set CallBackParent = oParent
End Sub
I have the following code which is supposed to load a userform, and then execute some code if the cancel button on the form isn't clicked.
Sub test()
Dim frm As Userform1
Set frm = New Userform1
frm.Show
If Not frm Is Nothing Then
Debug.Print "test"
End If
End Sub
The code for the cancel button is simply
Private Sub cmdCancel_Click()
Unload Me
End Sub
I was expecting the frm object in the first code snippet to be set back to nothing when the userform was unloaded, but apparently that's not the case as "test" is printed to the immediate window whether I click cancel or not. Is there any simple way to check if the frm-object points to a loaded userform or not?
I'd suggest to create for debugging purposes the following class clsExample
Option Explicit
Dim mObject As Variant
Property Get obj() As Object
Set obj = mObject
End Property
Function Cancel()
Set mObject = Nothing
End Function
Property Get version()
version = mObject.version
End Property
Private Sub Class_Initialize()
Set mObject = Application
End Sub
And then use the debugger to go stepwise through the following code
Sub TestClass()
Dim my As New ClsExample
Set my = New ClsExample
Debug.Print my.version
my.Cancel
If Not my Is Nothing Then
Debug.Print "Test"
End If
Debug.Print my.version
End Sub
currently i am programming a excel macro. The macro shows a Userform.
In the Userform the User can Select something. After the User has selected something i call Userform.Hide to Hide the Userform and to read the Selection from the Form. After the selection was read i call Unload Userform. Now the Code interacts with the selection. I want to do this in a loop but when the Code trys to show the Userform the second time. I get a exception that the Form is already displayed. I cant understand it, because i called Unload Userform. When i do it in debug mode everthing works as it should.
Userform Code
Private Sub Image1_Click()
SelectCard 1
End Sub
Private Sub Image2_Click()
SelectCard 2
End Sub
Private Sub SelectCard(number As Integer)
SelectedNumber = number
Me.Hide
End Sub
Public Sub CardSelector_Activate(Cards As Cards)
Dim c As card
For Each Key In Cards.CardDictionary.Keys
Set c = Cards.CardDictionary.Items(Key - 1)
If c.value = 1 And c.played Then
Image1.Enabled = False
End If
If c.value = 2 And c.played Then
Image2.Enabled = False
End If
Next Key
number = SelectedNumber
CardSelector.Show
End Sub
Code in the ClassModule i call this in a loop
Sub Costum(Spalte As Integer, Zeile As Integer, SpalteBeginn As Integer, Cards As Cards, CardsOpponent As Cards)
CardSelector.CardSelector_Activate Cards
Dim c As card
Dim number As Integer
number = CardSelector.SelectedNumber
Set c = Cards.CardDictionary.Items(CardSelector.SelectedNumber - 1)
SetCardAsPlaced c, Zeile, Spalte, SpalteBeginn
Unload CardSelector
End Sub
Can someone help me here ?
I am not sure if I fully understand your issue, but this is how I invoke a form using VBA. This is assuming you have a Cancel and OK button:
In the form:
Option Explicit
Private m_ResultCode As VbMsgBoxResult
Private Sub btnCancel_Click()
Call CloseWithResult(vbCancel)
End Sub
Private Sub btnOK_Click()
' Store form control values to member variables here. Then ...
Call CloseWithResult(vbOK)
End Sub
Private Sub CloseWithResult(Value As VbMsgBoxResult)
m_ResultCode = Value
Me.Hide
End Sub
Public Function ShowMe(Optional bNewLayerOptions As Boolean = True) As VbMsgBoxResult
' Set Default to Cancel
m_ResultCode = vbCancel
' Execution will pause here until the form is Closed or Unloaded
Call Me.Show(vbModal)
' Return Result
ShowMe = m_ResultCode
End Function
Then, to call it (please note that frmLayers is my own VBA form object - you would use yours):
Dim dlgLayers As New frmLayers
If (dlgLayers.ShowMe(False) = vbOK) Then
' Proceeed
End If
Does this help you with your issue? I am sorry if I have misunderstood, and I will remove my answer if needed.
Things like xxxxx_Activate etc. are event handlers called by the framework. So, for example, there is an event for activate and an event for initialize. You don't normally have to directly call these yourself if you set your code up correctly. See https://support.microsoft.com/en-us/kb/138819.
I've made a couple of macros that run through right click menu button based on the cell value. Typically, if I right click on cell with value 'XYZ', the menu button shows as 'Run macro for XYZ' and then does a bunch of operations: show a couple of user forms, run an SQL query, show and format result data.
On the original .xlsm file, on 'Thisworkbook' I have the following code:
Public WithEvents mxlApp As Application
Public WithEvents mxlSh As Worksheet
Private Sub mxlApp_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Range, Cancel As
Boolean)
... (do stuff here) ...
End Sub
...
Private Sub Workbook_Open()
Call AutoExec
End Sub
...
On a separate module, I have the following function used to set my event handler
Public Sub AutoExec()
Set mxlApp = Application
Set ColectionOfMxlEventHandlers = New Collection
ColectionOfMxlEventHandlers.Add mxlApp
Debug.Print ThisWorkbook.Name & " Initialized"
End Sub
The problem: on the original .xlsm file, the code works fine: every time I right-click on a cell which meets certain criteria, I get the 'Run macro for XYZ' and all is fine.
Once I save the file as .xlam and load it as addin, the code won't work.
I have been looking everywhere on the internet and here and couldn't figure out how to resolve this issue.
EDIT:
After modifying the code as kindly suggested by creamyegg, this is what I have:
In class module clsAppEvents:
Private WithEvents mxlApp As Excel.Application
Private Sub Class_Initialize()
Set mxlApp = Excel.Application
End Sub
Private Sub mxlApp_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
Dim cBut As CommandBarButton
On Error Resume Next
Call CleanMenu
If Len(Target.Value) = 8 Then
MyId = Target.Value
With Application
Set cBut = .CommandBars("Cell").Controls.Add(Temporary:=True)
End With
With cBut
.Caption = "Run SQL Query for " & MyId
.Style = msoButtonCaption
.FaceId = 2554
.OnAction = "CallGenericQuery"
End With
End If
With Application
Set cBut = .CommandBars("Cell").Controls.Add(Temporary:=True)
End With
With cBut
.Caption = "Columns_Select"
.Style = msoButtonCaption
.FaceId = 255
.OnAction = "CallShowHide"
End With
On Error GoTo 0
End Sub
in Thisworkbook class I have
Public m_objMe As clsAppEvents
Private Sub Workbook_Open()
Set m_objMe = New clsAppEvents
Debug.Print ThisWorkbook.Name & " Initialized"
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next
Call CleanMenu
On Error GoTo 0
Set m_objMe = Nothing
End Sub
Private Sub Workbook_Deactivate()
Call CleanMenu
End Sub
MyId is defined as a public string in the main module containing the CallShowHide and callGenericQuery subs
The issue sounds like your WithEvents is still in your ThisWorkbook Class? What you need to do is create a new class and then instantiate an instance of this on the Workbook_Open() event of your add-in. For example:
New Class (clsAppEvents):
Private WithEvents mxlApp As Excel.Application
Private Sub Class_Initialize()
Set mxlApp = Excel.Application
End Sub
Private Sub mxlApp_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
...
End Sub
Add-in ThisWorkbook Class:
Private m_objMe As clsAppEvents
Private Sub Workbook_Open()
Set m_objMe = New clsAppEvents
End Sub
Private Sub WorkbookBeforeClose(Cancel As Boolean)
Set m_objMe = Nothing
End Sub
I have created a userform that contains two checkboxes. I would like to be able to do different things depending on whether each box is checked or unchecked. However, it seems like no matter what I do, it will always tell me the original value of the checkboxes (false and false). Here is the code attached to clicking CommandButton1:
Private Sub CommandButton1_Click()
ReadData
End Sub
And here ReadData:
Sub ReadData()
Dim myForm As UserForm
Set myForm = UserForms.Add("ComplaintEntryForm")
Debug.Print (myForm!CheckBox1.Name)
Debug.Print (myForm!CheckBox1.Value)
Debug.Print (myForm!CheckBox2.Name)
Debug.Print (myForm!CheckBox2.Value)
End Sub
No matter how the boxes are checked, the immediate window always shows this:
VBA.UserForms.Add("ComplaintEntryForm").Show
CheckBox1
False
CheckBox2
False
I have a screenshot of the whole operation but it won't let me upload it because I'm a new user.
Try this method to load and show the form (this goes in a normal module):
Sub main()
Dim myForm As ComplaintEntryForm
Set myForm = New ComplaintEntryForm
myForm.Show
Set myForm = Nothing
End Sub
In the UserForm's own module, add the following:
Private Sub CheckBox1_Change()
readData
End Sub
Private Sub CheckBox2_Change()
readData
End Sub
Private Sub UserForm_Initialize()
Me.CheckBox1.Value = True
Me.CheckBox2.Value = False
End Sub
Private Sub readData()
Debug.Print Me.CheckBox1.Name
Debug.Print Me.CheckBox1.Value
Debug.Print Me.CheckBox2.Name
Debug.Print Me.CheckBox2.Value
End Sub
I've initialized the two checkboxes to specific values in the Initialize event. This means we are certain about the state the form will start in