Let me preface by saying I am a self taught novice at VBA or coding for that matter.
I have a combobox "cmbStyle" not in a userform but diretly on a worksheet named "Cost". I need to run code on the change event of "cmbStyle". The problem I have is that when the user changes the combobox the event fires and the code runs but at the end of the code the combobox event fires again and so on and so on.
I know that Application.EnableEvents = False will have not effect on ActiveX controls so this is not a solution.
I have found descriptions on how to use a boolean variable to stop the looping in the change event for listboxes but I can't seem to get it to work in my instance.
My code will end the subroutine after the Cange Event fires the second time. However, the next time the user selects another value from the Combobox the CodeDoneRun variable is still TRUE so the subroutines won't run again when I need it to.
I feel I am missing something very basic here....
My code is as follows:
Public CodeDoneRun as Boolean
Private Sub cmbStyle_Change()
If CodeDoneRun = True Then Exit Sub
CodeDoneRun = True
Call other Subroutines
End Sub
Enclose your function call in the if statement and let the code run through.
Public CodeDoneRun as Boolean
Private Sub cmbStyle_Change()
If Not CodeDoneRun Then
Call other Subroutines
End If
CodeDoneRun = Not CodeDoneRun
End Sub
Related
I am trying to create a button in an excel spreadsheet that activates every other button in the workbook in a particular order. These buttons are located in 4 different sheets. I attempted to simply create a button in one sheet, and call the other buttons from this button as below:
Public Sub CommandButton1_Click()
Button2_Click
Button3_Click
Button4_Click
Button5_Click
Button6_Click
End Sub
This did not work. I was thinking that maybe I need some sort of way to reference the sheet that each button is in?
Event handlers are Private for a reason. Making them Public will work, but isn't what you should be doing.
Move the code out of these handlers and into their own public procedures; then invoke these procedures from the respective handlers - and invoke the same procedures in the appropriate order from this commandbutton handler.
For example you take this:
Private Sub Button2_Click()
'do stuff
End Sub
Turn it into this:
Private Sub Button2_Click()
DoStuff
End Sub
Public Sub DoStuff()
'do stuff
End Sub
Then you can invoke DoStuff from wherever you need to.
Event handlers should never be invoked directly, and never need to be.
Even Private event handlers within sheet modules can be started by following way.
Assuming you have a worksheet named "ActiveXButtons" (its caption) with Button2 on it and following button event code within that worksheet:
Private Sub Button2_Click()
' ...
End Sub
Then you can trigger above button's event by addressing the worksheet's codename indirectly:
Application.Run Worksheets("ActiveXButtons").CodeName & ".Button2_Click"
or shortened:
Run “Sheet2.Button2_Click“
Dear Stackoverflow users,
For a small project, i have a few modules and a User form.
In the module, i have a loop statement that calls the User form.
The Userform gives the user four options to choose from.
When selection an option a public variable (string) will be defined.
The loop will fill the string in the column.
But now the loop will not stop before everything is answered.
I would like to create an exit button because if the list is large this is quite annoying).
So I thought of creating a command button "exit" which can be clicked (in the user form) to cancel the loop.
But because this button is in the user form, this will not stop the loop, it will just shut down the current user from, but the next will be displayed after.
Do you know the best way to stop the loop from-out the user form?
I know the techniques like Goto, but should only be used for error handling and won't work because the Goto needs to be in the user form sub and I want to cancel the total loop in another module.
I'm quite stuck at this, I hope you guys can help me out.
I think it would be something simple.
Regards,
Dubblej
I suggest not to use global variables as well as go to statement. In your form add a function to show the form and return the user choice whether they want to continue or not. Something like this:
Option Explicit
Private continue As Boolean
Public Function ShowDialog() As Boolean
Me.Show 1
ShowDialog = continue
End Function
Private Sub btnCancel_Click()
continue = False
Me.Hide
End Sub
Private Sub btnOK_Click()
continue = True
Me.Hide
End Sub
And in your module call ShowDialog function and if its return value is false quit the loop:
Option Explicit
Public Sub Sub1()
Dim form As New UserForm1
Do
If Not form.ShowDialog Then
Exit Do
End If
Loop
End Sub
I have an excel workbook.
In one of the worksheets I make use of the Worksheet_Calculate event. This works fine. However when the workbook is first opened I do not want MyFunction to be called. What is the best away to do this?
My only idea so far is the following (I don't like this though). On the workbook open method put a time stamp in one of the worksheets and then have an if statement in my worksheet_calculate and if the current time is 1 minute past the time stamp (that was created on the workbook_open event) run the code otherwise don't.
Thinking there must be a better way though?
Private Sub Worksheet_Calculate()
MyFunction()
End Sub
Update
The reason I do not want my code to execute when the workbook opens is because there are some Bloomberg formulas that take a little time to execute so initially some of the cell values are #NA.
This causes a type mismatch error - any errors that happen are logged and an e-mail is automatically sent. So every time the workbook is opened there is an 'error' as the bloomberg formulas have not updated straight away
The code below should work for you.
The first time calculate is called it sets the flag to allow future calls to process. This means the first call to calculate does not process your code.
ThisWorkbook Code:
Private Sub Workbook_Open()
bFunctionFlag = False
End Sub
Sheet Code:
Public bFunctionFlag As Boolean
Private Sub Worksheet_Calculate()
If bFunctionFlag = True Then Call MyFunction
bFunctionFlag = True
End Sub
Private Function MyFunction()
MsgBox "Calculate"
End Function
In the workbook open event you can have
Private Sub Workbook_Open()
Application.EnableEvents = False
'Run Workbook Open code
Application.EnableEvents = True
End Sub
or if you need events to run from external services then do something similar with a public variable. Eg Dim wbOpenEventEnded as Boolean
I'm looking for a bit of advice here.
I have a spreadsheet with various modules and procedures that can be called from a Worksheet_Change event. This causes problems when I need to issue a sheet from the workbook for other users to complete.
Whenever the user tries to update the sheet, the on change event gets triggered, causing a compile error as the procedure being called does not exist, and this cannot be trapped (as far as I'm aware). I've tried using Application.EnableEvents = False, but this is in the worksheet event and the code breaks as soon as the event is triggered.
Is there anyway to call a procedure through late binding where I can trap the error?
I'm trying something like this at the moment.
Dim mdl as object
' Test for module in workbook, if error, then exit routine
Set mdl = Application.ActiveWorkbook.VBProject.VBComponents("mdlSharedFunctions")
'If no error, then call procedure here
call mdl.UpdateData(Target)
'Or
Application.Run mdl.UpdateData(Target)
Neither of these call methods will work and I'm hoping someone out there will be able to point me in the right direction.
Cheers
Pete
You can use a global variable as a flag - bit dirty but it works fine. Then add an If flag = true then statement to the change event sub.
Public globalflag as Boolean
Sub test1()
If globalflag = True Then
BrokenSub 'This sub has an invalid sub/function referenced, but will be ignored if the flag is set to false
Else
'Don't run the code
Exit Sub
End If
End Sub
Sub BrokenSub()
invalidfunction ("asb")
End Sub
EDIT
To put it in a worksheet, just see if the variable exists:
Declare this in a module in your master spreadsheet:
Public globalflag as Boolean
Then in your worksheet code
If not IsEmpty(globalflag) Then
BrokenSub 'Put your master spreadsheet code here - it'll run if globalflag exists and be ignored if it doesn't
End If
Sub BrokenSub()
invalidfunction ("asb")
End Sub
this one may be impossible to solve in VBA but I'd like to see what you experts have to say about it.
I have a textbox on a userform that triggers a macro within a TextBox1_Change() type of sub.
If the user types "ABC" in the textbox, the macro gets triggered 3 times: once for "A", once for "AB" and once for "ABC". This macro is actually kind of heavy, so I would like it to run only when the user is actually done typing, and not inbetween single key strokes.
I know I can make the user "press enter" or whatever and only then run the macro, but this is not what I'm looking for. I want him to type freely and see the results of his typing dynamically show up, with no other type of interaction required.
So, I came up with the idea of making the change event wait and see if another change event gets triggered within, say, 1 second from the first. If that happens, the first change event aborts.
Now this would work, and I think I would know how to code it, except that I don't know how to give the user the power to keep typing even when the first change event is running.
What I mean is that when the first macro runs, it "freezes" everything. Waiting to see if another change event triggers will therefore not work, as nothing is going to trigger until the first macro is done running.
Do you guys see my problem here? How would you go about this? Any chance I can achieve the results I'd like?
Any help is greatly appreciated, thanks guys!
I tested the following, and it works (assuming I correctly understand what you're trying to do).
In a code module, write this:
Public aRunIsScheduled As Boolean
Public nextRunTime As Variant
Sub MyMacro()
'Flag macro as having been run, no longer scheduled.
aRunIsScheduled = False
'Place your macro code here.
'I'll just use some dummy code:
MsgBox "MyMacro is running!"
End Sub
In your sheet module:
Private Sub CommandButton1_Click()
If aRunIsScheduled Then
' Cancel the previously scheduled run.
Application.OnTime EarliestTime:=nextRunTime, _
Procedure:="MyMacro", Schedule:=False
aRunIsScheduled = False
End If
' Schedule a new run 3 seconds from now:
nextRunTime = Now + TimeValue("00:00:03")
Application.OnTime EarliestTime:=nextRunTime, _
Procedure:="MyMacro", Schedule:=True
aRunIsScheduled = True
End Sub
I put a Commandbutton in my sheet and here I'm using its change event, but you can put this code in your TextBox1_Change() event instead, in exactly the same way.
reference: http://www.cpearson.com/excel/SuppressChangeInForms.htm
To suppress events in a form, you can create a variable at the form's module level called "EnableEvents" and set that to False before changing a property that will cause an event to be raised.
Public EnableEvents As Boolean
Private Sub UserForm_Initialize()
Me.EnableEvents = True
End Sub
Sub Something()
Me.EnableEvents = False
' some code that would cause an event to run
Me.EnableEvents = True
End Sub
Then, all of the controls on form should have a test if that variable as their order of business in any event code. For example,
Private Sub ListBox1_Change()
If Me.EnableEvents = False Then
Exit Sub
End If
MsgBox "List Box Change"
End Sub
You can declare the EnableEvents as Private if only procedures with that form need to suppress events. However, if you have forms that are programmatically linked together, such UserForm2 adding an item to a ListBox on UserForm1, you should declare the variable as Public and set it for another form with code like the following:
UserForm1.EnableEvents = False
'
' change something on UserForm1
'
UserForm1.EnableEvents = True
The primary difference between the EnableEvents property and code shown above and the Application.EnableEvents property is that with a UserForm EnableEvents, all control on the form must have code to exit if EnableEvents is True. In other words, all the form's controls must cooperate and respect the setting of EnableEvents.