I have a UserForm with two options Budget or Actual. If I select Actual the code works and Calls the Sub Routine Actual however if I select Budget I receive the error Invalid Use Of Property at the line Call Budget.
Option Explicit
Private Sub Budget_Click()
Call Budget
End Sub
Private Sub OptionButtonActual_Click()
Call Actual
End Sub
The Budget Sub Routine
Sub Budget()
Dim sys As Object
'Check to see if session is open
Set sys = CreateObject("BZWhll.WhllObj")
ResultCode = sys.Connect("B")
If (ResultCode) Then
MsgBox "UNABLE TO CONNECT TO SESSION!"
MsgBox "MACRO STOPPED!"
GoTo endM
End If
sys.Disconnect
X203BudgetExtract
endM:
End Sub
I changed the name of the option button to:-
OptionButtonBudget and now my code works!
Related
Inside a sub ("Sensitivities") I am calling another sub ("MVE_NIM_Subs.MVE_Main"), if this sub outputs a MsgBox I want to end the sub and to go to the "Jump" defined, instead of continuing executing the sub. ¿How can I do it?
Thanks
Public Sub Sensitivities()
Application.Run "MVE_NIM_Subs.MVE_Main"
........
Jump:
End Sub
You can trap your Msgbox with a public boolean variable. In the sub MVE_NIM_Subs.MVE_Main modify your code to set a public boolean variable to be true if the msgbox appears.
After this sub ends, execution will go back to executing code inside sub Sensitivities. Then just check the value of the public boolean variable. If it's true, then go to Jump.
Something like this:
Option Explicit
Public DidMsg As Boolean
Sub Sensitivities()
DidMsg = False
Application.Run "MVE_NIM_Subs.MVE_Main"
If DidMsg = True Then GoTo Jump
'rest of your code
'
'
'
'
Jump:
'rest of your code after point Jump
'
'
'
'
End Sub
Sub MVE_Main()
'your code whatever it is
'right after using the msgbox type:
DidMsg = True
End Sub
MsgBox is a modal element, so code execution is paused until the user deals with it. This leaves you with two options:
Don't display a MsgBox (if you only want to stop code when this happens I'm not sure what the point of it is anyway?)
Create a non-modal userform to emulate a MsgBox instead.
You have to options in my opinion:
Make MVE_NIM_Subs.MVE_Main a function that returns Bool. When you display message box in MVE_NIM_Subs.MVE_Main set return value to True. Then in calling sub you can write:
If returnValue Then GoTo Jump
Keep MVE_NIM_Subs.MVE_Main as sub and declare some global Bool variable, that can be used within two subs. In outer sub set it to False before calling MVE_NIM_Subs.MVE_Main and in MVE_NIM_Subs.MVE_Main set it to True whenever you show the message box. Then you can use it in outer sub to decide whether to jump or not, like in first option :)
I have two modules, Module1 and Module2.
In Module1:
Private Function myCheck() As Boolean
if [Operation] = [Something] then
myCheck = True
Else
myCheck = False
End if
End Sub
In Module2, I would like to run myCheck sub in Module 1 then do another operation:
Private Sub Execute()
[Operation 1]
If myCheck = True Then
[Operation 2]
Else
[Operation 3]
End If
End Sub
It does not work. If I place Private Function myCheck within the same module then it works. Is there a special method to call a sub or function from another module?
Use Option Private Module For Module1, then in Module 2:
for a Sub; qualify what you're calling with the Module it's in, like so:
Module1.myCheck()
for a Private Sub; use Application.Run and qualify what you're calling with the Module it's in, like so:
Application.Run ("Module1.myCheck")
Using Private Module hides it's contained sub/s in the Developer > Macros list.
Further Reading :-)
Read through the comments in the code below to see what does and doesn't work.
To confirm the behaviours yourself:
Create a new Excel, open Developer > Visual Basic, insert 3 Modules.
Copy the below code blocks into the relevant modules.
'In Module1
Option Explicit
Sub ScopeTrials()
'NOTES:
' Only NormalSubIn_NormalModule shows in Developer > Macros.
' As the default without a keyword is Public I have called
' these "Normal". I.e. you can use Public or Nothing wherever
' Normal is.
' A line commented out shows what doesn't work.
NormalSubIn_NormalModule
Call NormalSubIn_NormalModule
Application.Run ("NormalSubIn_NormalModule") 'Not recommended!
NormalSubIn_PrivateModule
Call NormalSubIn_PrivateModule
Application.Run ("NormalSubIn_PrivateModule") 'Not recommended!
'PrivateSubIn_NormalModule
'Call PrivateSubIn_NormalModule
'Module2.PrivateSubIn_NormalModule
'Call Module2.PrivateSubIn_NormalModule
Application.Run ("PrivateSubIn_NormalModule") 'Fails with duplicates! See Explanation
Application.Run ("Module2.PrivateSubIn_NormalModule")
'PrivateSubIn_PrivateModule
'Call PrivateSubIn_PrivateModule
'Module3.PrivateSubIn_PrivateModule
'Call Module3.PrivateSubIn_PrivateModule
Application.Run ("PrivateSubIn_PrivateModule") 'Fails with duplicates! See Explanation
Application.Run ("Module3.PrivateSubIn_PrivateModule")
'Explanation: if there is an identical sub in another Private Module, then this fails
'with Runtime Error 1004 (Macro not available or Macros Disabled), which is Misleading
'as the duplication and/or nonspecified module is the problem.
'I.e. always specify module!
'Also, this only fails when the line is actually run. I.e. Compile check doesn't find this
'when starting to Run the code.
End Sub
'In Module2
Option Explicit
Sub NormalSubIn_NormalModule() 'only THIS sub shows in Developer > Macros
MsgBox "NormalSubIn_NormalModule"
End Sub
Private Sub PrivateSubIn_NormalModule()
MsgBox "PrivateSubIn_NormalModule"
End Sub
'In Module3
Option Explicit
Option Private Module
Sub NormalSubIn_PrivateModule()
MsgBox "NormalSubIn_PrivateModule"
End Sub
Private Sub PrivateSubIn_PrivateModule()
MsgBox "PrivateSubIn_PrivateModule"
End Sub
You can use Application.Run to do this:
Application.Run "Module1.myCheck"
The macro will stay "invisible" for the users if they display the Macros Dialog Box (Alt+F8), since it's still private.
Edit #1
A second option is to introduce a dummy variable as an optional parameter in the Sub, like this:
Public Sub notVisible(Optional dummyVal As Byte)
MsgBox "Im not visible because I take a parameter, but I can be called normally."
End Sub
This too, will hide the macro in the Macros Dialog Box (Alt+F8), but it can now be invoked the usual way.
I'm trying to create a macro (in PERSONAL.XLSB) that every time a workbook is opened, it checks a condition and in if it's true (this means the workbook opened contains an specific Sub), it calls this Sub.
Option Explicit
Private WithEvents App As Application
Private Sub Workbook_Open()
Set App = Application
End Sub
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
If condition Then Call Specific_Sub
End Sub
It runs fine when I open a file that contains that Sub, however, if the Sub is not in the file, the compiler returns the error “Sub or Function not defined”, naturally.
I’m trying very hard to find a way to do this and deal with the error, but On error GoTo doesn’t work because the compiler error is before the run time, so it’s not executed.
I guess I have to do this in a different way but I can’t picture how to do it, any help or ideas?
Thanks a lot!
Thanks to the answers I've discovered that the best way is to use Application.Run. To keep the code as simple as possible, I just changed the last part to look like this:
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
On Error Resume Next
If condition Then
Application.Run ("'" & ActiveWorkbook.FullName & "'!" & "Specific_Sub")
End If
End Sub
Thank you all.
I cobbled this together from a few web sites. The key is that your sub routines name is in a variable and application. run uses the variable. This gets past the compiler error you are running into
Sub SubExists()
Dim ByModule As Object
Dim ByModuleName As String
Dim BySub As String
Dim ByLine As Long
'
'Module and sub names
ByModuleName = "Module1"
BySub = "Specific_Sub"
On Error Resume Next
Set ByModule = ActiveWorkbook.VBProject.vbComponents(ByModuleName).CodeModule
ByLine = ByModule.ProcStartLine(BySub, vbext_pk_Proc)
If Err.Number = 0 Then
Application.Run BySub
End If
End Sub
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
SubExists
End Sub
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
Txt_Prod_Loc_Date.Value = MonthView1.Value
Unload Me
End Sub
Private Sub FrmCalendar_Initialize()
Unload Me
End Sub
I also tried Txt_Prod_Loc_Date.Value= DateClicked. But I see a " runtime error 424, object required
Thanks
You can use both; MonthView1.Value or DateClicked. The problem is not because of that :)
BTW why do you have Unload Me in FrmCalendar_Initialize()? That would give you a Run Time Error 91. Object Variable or With block variable Not set
You are getting Runtime error 424, object required because it could not find the Txt_Prod_Loc_Date control on your userform.
If that control is in the worksheet then use it like this
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
Sheet1.TextBox1.Value = MonthView1.Value
End Sub
If that control is in some other form (say Userform1) then use it like this
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
UserForm1.Txt_Prod_Loc_Date.Value = MonthView1.Value
End Sub
In VBA for excel, I have a userform then I want this to show only for 1 instance. Even if the user re-open it, it won't open again. Is there any code for it? well, I'm also using this code for my login:
Private Sub UserForm_Initialize()
User.Caption = Environ("Username")
End Sub
I'm thinking if i can use this code in my problem. Hoping for a quick response. thanks guys, you're awesome!
Yes, it's possible.
You have to add new sheet. In a cell A1 type 0 (zero), then hide it. In a code which calls UserForm, use this:
Sub ShowMyForm()
If ThisWorkbook.Worksheets("HiddenSheet").Range("A1")=0 then MyUserForm.Show
End Sub
In a form:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
ThisWorkbook.Worksheets("HiddenSheet").Range("A1")=1
ThisWorkbook.Save()
DoEvents
End Sub
If you don't want to add an extra sheet just to store one bool, you can set a custom document property like this:
Private Sub Workbook_Open()
On Error Resume Next
Dim test As Boolean
test = Me.CustomDocumentProperties("UserFormShown").Value
If Err.Number = 0 Then Exit Sub
UserForm1.Show
Me.CustomDocumentProperties.Add "UserFormShown", False, msoPropertyTypeBoolean, True
End Sub
If the property hasn't been set yet it will throw an error, so trapping an error lets you know if you've set the property (and shown the form).