I want to fire the BeforeDoubleClick-event BEFORE the SelectionChange-event for an EXCEL work-sheet.
The order is normally the other way round: SelectionChange-event first, and later BeforeDoubleClick-event.
My goal is to either run MyDoubleClickCode, if there a double-click, or if NOT, run MyChangeSelectionCode.
The problem relies in the order of event-triggering!
My best solution comes here:
' This Event is **MAYBE** fired secondly and runs the MyDoubleClickCode
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
dblFlag = true
...
MyDoubleClickCode
...
End Sub
' This event is always fired AND runs first
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
dblFlag = false
alertTime = Now + TimeValue("00:00:01")
Application.OnTime alertTime, "MyChangeSelectionSub"
End Sub
' Userdefined subroutine which will run one second after an event ( doubleclick or not).
public sub MyChangeSelectionSub()
If NOT dblFlag then
...
MyChangeSelectionCode
...
End if
End Sub
I use OnTime in my SelectionChange-event to call the MyChangeSelectionSub one second after a selection-change is triggered. This gives times to handle an BeforeDoubleClick-event and do the MyDoubleClickCode - if the cell was also double-clicked. My wanted logic is reached , BUT...
... it is of course very clumpsy and not satisfying: I have to wait one second before the MyChangeSelectionSub starts, instead of just after the BeforeDoubleClick-event has been dealed with.
Maybee there is a kind of logic to make this happend? Any idea?
EDIT: I've edited the code-exampel to be more clear about my problem! And I know now that I can't change the order of events, but how to not use the onTime solution??
This "works" for me, but it doesn't seem stable. Probably the timing of the OnTime method causes an "uncomfortable pause" in execution that we might need to accept. (or improve upon.)
'worksheet (Name) is "Sheet17" in the VBA Properties window
'worksheet Name is "Sheet1" as shown in the worksheet tab in the application Excel
Private double_click_detected As Boolean
Private SelectionChange_target As Range
' This Event is **MAYBE** fired secondly and runs the MyDoubleClickCode
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
double_click_detected = True
'...
MsgBox "MyDoubleClickCode"
'...
End Sub
' This event is always fired AND runs first
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Set SelectionChange_target = Target
alertTime = Now + TimeValue("00:00:01")
Application.OnTime alertTime, "Sheet17.MyChangeSelectionSub"
End Sub
' Userdefined subroutine which will run one second after an event ( doubleclick or not).
Public Sub MyChangeSelectionSub()
If Not double_click_detected Then
'...
MsgBox "MyChangeSelectionCode"
'...
End If
End Sub
I found a solution for a similar issue, to avoid Worksheet_SelectionChange before the event Worksheet_BeforeRightClick on https://www.herber.de/forum/archiv/1548to1552/1550413_Worksheet_BeforeRightClick.html (in german) and used it for my test sub.
The whole list of virtual key codes you find on https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)'just for sleep
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
Const VK_LBUTTON = &H1 'Left mouse button
Const VK_RBUTTON = &H2 'Right mouse button
Const VK_SHIFT = &H10'Shiftkey just for fun to exit the sub
Sub TestGetAsyncKeyState()
Dim RMouseClick As Long, LMouseClick As Long
Dim RMouseClickpr As Long, LMouseClickpr As Long
Dim lShift As Long, iC As Integer
iC = 0
Do
DoEvents
lShift = GetAsyncKeyState(VK_SHIFT)
RMouseClickpr = RMouseClick
LMouseClickpr = LMouseClick
RMouseClick = GetAsyncKeyState(VK_RBUTTON)
LMouseClick = GetAsyncKeyState(VK_LBUTTON)
If RMouseClick <> RMouseClickpr Or LMouseClick <> LMouseClickpr Then Debug.Print vbLf; CStr(iC); ":"
If RMouseClick <> RMouseClickpr Then Debug.Print "Right: "; RMouseClick; "Previous: "; RMouseClickpr
If LMouseClick <> LMouseClickpr Then Debug.Print "Left : "; LMouseClick; "Previous: "; LMouseClickpr
' If RMouseClick <> RMouseClickpr Or LMouseClick <> LMouseClickpr Then Stop
Sleep (1000)
iC = iC + 1
If iC > 120 Then Stop '2
Loop While GetAsyncKeyState(VK_SHIFT) = 0 'End Loop by pressing any of the Shift-Keys
End Sub
It works for mouseclick (1), shortly held mousebutton (-32767) and longer held mousebutton (-32768). Unfortunately not for doubleclick.
Attention: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate says that it detects the physical mousebuttons. If someone changed the setting it will not detect the correct button. MS says you can correct that with GetSystemMetrics(SM_SWAPBUTTON).
Hope it helps.
Related
The Workbook.BeforeClose event triggers when the workbook is about to close but before the saving message prompt which allows cancelling it.
How can I detect when the workbook is already closing past the point where it can be cancelled without removing nor replacing the saving message with a custom one?
One workaround I have found online is to use the event together with the Workbook.Deactivate event which looks like this:
Code in the workbook:
Private Sub Workbook_BeforeClose(ByRef Cancel As Boolean)
closing_event = True
check_time = VBA.Now + VBA.TimeSerial(Hour:=0, Minute:=0, Second:=1)
Excel.Application.OnTime EarliestTime:=check_time, Procedure:="disable_closing_event"
End Sub
Private Sub Workbook_Deactivate()
If closing_event Then
VBA.MsgBox Prompt:="Closing event."
Excel.Application.OnTime EarliestTime:=check_time, Procedure:="disable_closing_event", Schedule:=False
End If
End Sub
Code in a module:
Public closing_event As Boolean
Public check_time As Date
Public Sub disable_closing_event()
closing_event = False
End Sub
One very specific edge case where it triggers incorrectly is if you click to close the workbook and in less than one second close the saving message (press Esc to do it fast enough) and change to another workbook (Alt + Tab) it triggers the Deactivate event with the closing_event condition variable still set to True because disable_closing_event has still not set it to False (scheduled by Application.OnTime for when one second goes by).
I would like to find a solution that isn't so much of a workaround and that works correctly against that edge case.
Edit:
The accepted answer has the best solution in my opinion out of all the current answers. I have modified it for my needs and preference to the following code in the workbook:
Private WorkbookClosing As Boolean
Private Sub Workbook_BeforeClose(Cancel As Boolean)
WorkbookClosing = True
End Sub
Private Sub Workbook_Deactivate()
If WorkbookClosing And ThisWorkbook.Name = ActiveWindow.Caption Then
Workbook_Closing
Else
WorkbookClosing = False
End If
End Sub
Private Sub Workbook_Closing()
MsgBox "Workbook_Closing event."
End Sub
This is an evolution of my 1st Answer - it detects the edge case problem by comparing the ActiveWindow.Caption against ThisWorkbook.Name so it can detect that issue and deal with it. It's not the most elegant solution but I believe it works.
All Code in the Workbook most of it in DeActivate
Public ByeBye As String
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ByeBye = "B4C"
End Sub
Private Sub Workbook_Deactivate()
If ByeBye = "B4C" Then
If ActiveWindow.Caption = ThisWorkbook.Name Then
If ThisWorkbook.Saved Then
MsgBox "No problem - Closing after Saving"
Else
MsgBox "No problem - Closing without Saving"
End If
Else
If ThisWorkbook.Saved Then
MsgBox "No problem - New Workbook Activation"
Else
MsgBox "Oops Try Again You Cannot Activate '" & ActiveWindow.Caption & "' until '" & ThisWorkbook.Name & "' has completed processing & IT HAS NOW COMPLETED", vbOKOnly, "Hiding"
ThisWorkbook.Activate
End If
End If
Else
MsgBox "No problem - Just Hiding"
End If
ByeBye = "Done"
End Sub
Private Sub Workbook_Open()
ByeBye = "OPENED"
End Sub
In response to comment about saving I tested this for 7 possible combinations as follows
1) Closing without Edits - No Saving Involved ... MsgBox Prompted with ... No problem - Closing after Saving
2) Not closing - Just Switch Workbook - Whether Edited or Not ... MsgBox Prompted with ... No problem - Just Hiding
3) Not closing - Switch Workbook - After Edit & Cancel ... MsgBox Prompted with ... Oops Try Again …
4) Closing and saving ... MsgBox Prompted with ... No problem - Closing after Saving
5) Closing and Saving after a prior Cancel ... MsgBox Prompted with ... No problem - Closing after Saving
6) Closing but Not Saving ... MsgBox Prompted with ... No problem - Closing without Saving
7) Closing but not Saving after a prior Cancel ... MsgBox Prompted with ... No problem - Closing without Saving
I think trying to cancel the close event is the wrong approach for what you are trying to do. A better approach would be to have a function that is only called when the workbook is actually closing.
Thank you for the comments regarding OnTime not being called while the dialog is open as that pointed me in the right direction. What we need to test is the time between the workbook deactivation and the closing of either the workbook itself or the save dialog. Using the Excel.Application.OnTime function to set this close time means this is possible as it can be delayed until the save dialogue has closed.
Once we have this time, a simple comparison to the deactivation time allows us to decide whether to call the exit function or not.
I initially ran into issues with the workbook reopening to run the .OnTime procedure, so an artificial delay needs to be added into the Deactivation function so the workbook hasn't closed until the close time has been set. Using the code from here - Delay Macro to allow events to finish we can accomplish this.
In ThisWorkbook
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Excel.Application.OnTime EarliestTime:=Now, Procedure:="SetCloseTime"
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Timer < CloseTime + 0.2 Then Call CloseProcedure
End Sub
Private Sub Workbook_Deactivate()
Delay (0.3)
If Timer < CloseTime + 0.4 Then Call CloseProcedure
End Sub
In a module
Option Explicit
Public CloseTime As Single
Function SetCloseTime()
CloseTime = Timer
End Function
Function Delay(Seconds As Single)
Dim StopTime As Single: StopTime = Timer + Seconds
Do While Timer < StopTime
DoEvents
Loop
End Function
Function CloseProcedure()
MsgBox "Excel is closing"
End Function
The .OnTime seems to run within one second cycles which dictates the length of the delay and the time difference test has a little leeway added with an additional 1/10th of a second (which I found necessary). These timings could potentially need slight tweaking but have so far worked for me with the different scenarios when closing the workbook.
In order to get around your edge case, you need to handle the case where the workbook is deactivated within 1 second of closing it, but only when the save prompt was displayed.
To check if less than 1 second has elapsed, use a high resolution timer to store the time in the Workbook_BeforeClose event, and then compare against it in the Workbook_Deactivate event. Assuming that clsTimer is a suitable high res timer, your code should now be:
Private MyTimer As clsTimer
Private StartTime As Currency
Private Sub Workbook_BeforeClose(ByRef Cancel As Boolean)
closing_event = True
Set MyTimer = New clsTimer
StartTime = MyTimer.MicroTimer
check_time = VBA.Now + VBA.TimeSerial(Hour:=0, Minute:=0, Second:=1)
Excel.Application.OnTime EarliestTime:=check_time, Procedure:="disable_closing_event"
End Sub
Private Sub Workbook_Deactivate()
If closing_event Then
If Not ThisWorkbook.Saved Then
'The Save prompt must have been displayed, and the user clicked No or Cancel or pressed Escape
If MyTimer.MicroTimer - StartTime < 1 Then
'The user must have pressed Escape and Alt-Tabbed
closing_event = False
Else
'Your Windows API calls here
End If
Else
'The workbook was saved before the close event, so the Save prompt was not displayed
'Your Windows API calls here
End If
Excel.Application.OnTime EarliestTime:=check_time, Procedure:="disable_closing_event", Schedule:=False
End If
Set MyTimer = Nothing
End Sub
The class module for clsTimer looks like this:
Private Declare PtrSafe Function getFrequency Lib "kernel32" _
Alias "QueryPerformanceFrequency" (cyFrequency As Currency) As Long
Private Declare PtrSafe Function getTickCount Lib "kernel32" _
Alias "QueryPerformanceCounter" (cyTickCount As Currency) As Long
Public Function MicroTimer() As Currency
' Returns seconds.
Dim cyTicks1 As Currency
Static cyFrequency As Currency
MicroTimer = 0
' Get frequency.
If cyFrequency = 0 Then getFrequency cyFrequency
' Get ticks.
getTickCount cyTicks1
' Seconds
If cyFrequency Then MicroTimer = cyTicks1 / cyFrequency
End Function
This post could be helpful https://www.dummies.com/software/microsoft-office/excel/an-excel-macro-to-save-a-workbook-before-closing/
I found code below from the book Excel 2016 Power Programming with VBA, by Michael Alexander
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim msg As String, ans as integer
If Me.Saved = False Then
msg = "Do you want to save?"
ans = MsgBox(msg, vbquestion+vbyesnocancel)
Select Case ans
Case vbYes: Me.Save
Case vbCancel: Cancel = True
End Select
End If
Call mySub
Me.Saved = True
End Sub
I think deactivate is the best way to capture this.
Beforeclose might occur earlier than Save event if the document was not saved. So Excel might prompt to save before closure.
But Deactivate is the final event before closure (after save). So this can be used.
had a similar problem and tried to run some macro before closing but it is dependad whether user wants to save workbook or not.
My solution was the code below, though there is a problem, that window of excel always stays open.
Public ClosedByProgram As Boolean
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Not ClosedByProgram Then
Cancel = True
Dim Ans As String
Ans = MsgBox("Want to save your changes to '" & ThisWorkbook.Name & "'?", vbYesNoCancel, "Microsoft Excel")
If Ans = vbNo Then
ClosedByProgram = True
ThisWorkbook.Close
ElseIf Ans = vbYes Then
Dim STR As String: STR = "'" & ThisWorkbook.Name & "'!" & "mod16_Versioning.IsSuitableForSaving"
Dim isForSaving As Boolean: isForSaving = Application.Run(STR, SaveAsUI)
If isForSaving Then
Dim STRToRun As String
STRToRun = "'" & ThisWorkbook.Name & "'!" & "mod02_Events.BeforeSave"
Application.Run STRToRun, SaveAsUI
Dim STRVersions As String: STRVersions = "'" & ThisWorkbook.Name & "'!" & "mod16_Versioning.MakeVersion"
Dim blankCheck As Boolean: blankCheck = Application.Run(STRVersions, SaveAsUI)
ClosedByProgram = True
ThisWorkbook.Close
End If
End If
Else
ThisWorkbook.Saved = True
Application.Quit
End If
End Sub
This seems to work
Code in the WorkBook
Public ByeBye As String
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ByeBye = "BB # " & Now()
End Sub
Private Sub Workbook_Deactivate()
If Left(ByeBye, 2) = "BB" Then
ByeBye="Done"
MsgBox "Closing"
Else
ByeBye="Done"
MsgBox "DeActivating BUT NOT Closing"
End If
End Sub
Private Sub Workbook_Open()
ByeBye = "OP # " & Now()
End Sub
Just uses a public variable ByeBye
You must initialise it in WorkBook.Open
You must Set it in WorkBook.BeforeClose
and can test it in WorkBook.DeActivate
In case it is needed for this to work even after a VBA crash - and loss of ByeBye value I'm resetting it in the Workbook_SheetChange and in WorkBook_SheetSelectionChange
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
ByeBye = "SC # " & Now()
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
ByeBye = "SSC # " & Now()
End Sub
The above addendum is really only needed if you were going to use the string default of "" for the tested value - but I'm using "BB # " & Now() so this is not really needed
I am developing a VBA code that will run on a range of cells in a worksheet. Every time a cell within that rnage is selected, I want the code to execute. I am doing this using:
Sub Worksheet_SelectionChange(ByVal Target As Range)
However, the code is quite slow and there are times I would like to navigate within that range using the arrow keys. To do so, I thought to use the Timer function that will only run the code if I am on a cell for more than 0.5 seconds.
The code I have tried is as follows:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'set timer
Dim PauseTime, Start, Finish, TotalTime
PauseTime = 0.6 ' Set duration.
Start = Timer ' Set start time.
Do While Timer < Start + PauseTime
DoEvents ' Yield to other processes.
Loop
Finish = Timer ' Set end time.
TotalTime = Finish - Start ' Calculate total time.
If Abs(TotalTime) < 0.1 Then GoTo ws_exit
'continuation of code......
ws_exit:
Application.EnableEvents = True
End Sub
The Main issue I am having with the code is that it is recursive and returns to the first timer that was set on the first cell I pressed. I wanted to know if there is a way to delay the SelectionChange code from running until the user is set on a cell for X amount of time.
Thanks,
Yon
A class module solves this. Add a class module, call it cTimer. Paste this code:
Option Explicit
Public Target As Range
Private StartTime As Double
Public WaitTime As Double
Public Sub HandlePrevious()
If Timer - StartTime > WaitTime Then
'Handle things now using Target
Debug.Print Target.Address, "Taking action"
Else
Debug.Print Target.Address, "Moving on"
End If
End Sub
Private Sub Class_Initialize()
StartTime = Timer
End Sub
Use this in your worksheet module:
Option Explicit
Dim mcTimer As cTimer
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not mcTimer Is Nothing Then
mcTimer.HandlePrevious
End If
Set mcTimer = Nothing
Set mcTimer = New cTimer
mcTimer.WaitTime = 0.5
Set mcTimer.Target = Target
End Sub
What I am trying to achieve here is I have three different dashboards running in all the three sheet which I was to switch every 1 Min. I am stuck with the below code. Any help would be appreciated.
I have three sheets to switch between
1. First_sheet, 2. Second_Sheet, 3. Third_Sheet
Sub Swap_Sheets()
Dim Sheets As Workbook
Dim dTime As Date
dTime = Now + TimeValue("00:00:60")
Application.OnTime dTime, "Swap_Sheets"
If ActiveSheet.Name = "First_Sheet" Then
Sheets("Second_Sheet").Activate
Else
Sheets("Third_Sheet").Activate
Else
Sheets("First_Sheet").Activate
End If
If Sheets("Second_sheet").CheckBox1.Value = False Then
Application.OnTime dTime, "Swap_Sheets", , False
End If
End Sub
This is a good way to do it, avoiding multiple if-s,select case and recursion:
Option Explicit
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Sub SwapSheets()
Dim dTime As Date
Dim i As Long: i = 1
While i <= ThisWorkbook.Worksheets.Count
If ActiveSheet.Name = Worksheets(Worksheets.Count).Name Then
Worksheets(1).Activate
Else
Worksheets(ActiveSheet.index + 1).Activate
End If
i = i + 1
Sleep (10000) '10 seconds
Wend
End Sub
The idea is that every sheet has an index, and you simply have to increment the index of the active one. If the last sheet is the activeone, start from the beginning. Sleep takes milliseconds as a parameter, for 60 seconds it is 60.000.
Plus - in your code you have Dim Sheets As Workbook and here you probably mean Worksheet (I am only guessing).
If you only want to activate 3 worksheets, this is probably the easiest way to do it:
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Sub SwapSheets()
Dim sheetNames() As Variant
Dim i As Long
sheetNames = Array("Sheet1Name", "Sheet2Name", "Sheet3Name")
For i = LBound(sheetNames) To UBound(sheetNames)
Sheets(sheetNames(i)).Activate
Sleep (10000) '10 seconds
Next i
End Sub
I'm working on a project where the requirement is not to let the users use mouse to move from one cell to another, they can only move through the Tab button.
So, I have no idea how can I disable the mouse click on particular excel sheet and allow the users to use only the Tab key.
Thanks in Advance!
In this answer I suppose that your goal is not to lock the cells from editing,
but only to disable selecting the cells using the mouse. That is, user is still allowed to edit a cell, but she needs to first select it using Tab or Arrow buttons, and then she can edit it by pressing F2 or typing.
Add the following code to your Worksheet's code module:
Option Explicit
Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
' The keyword PtrSafe is needed only if you are working on a Win64 platform
' Remove it if you are using Win32
Private lastSelection As Range
Private Sub Worksheet_Activate()
On Error Resume Next
Set lastSelection = Selection.Cells(1)
If Err.Number <> 0 Then Set lastSelection = Cells(1, 1)
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim e As Variant
For Each e In Array(vbKeyUp, vbKeyDown, vbKeyLeft, vbKeyRight, vbKeyTab, vbKeyReturn, vbKeyHome, vbKeyEnd, vbKeyPageDown, vbKeyPageUp)
If CBool(GetAsyncKeyState(e) And &H8000) Then 'You got here without using the mouse
Set lastSelection = Target
' do other stuff if needed
Exit Sub
End If
Next
' Selection was changed via mouse. Rollback
If lastSelection Is Nothing Then Set lastSelection = Cells(1, 1)
lastSelection.Activate
End Sub
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True
End Sub
A couple of options
.
1. Without protecting the sheet - forces all clicks back to cell A1 (in sheet's module)
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
With Target
If .Column <> 1 Or .Row <> 1 Or .CountLarge > 1 Then Application.Undo
End With
Application.EnableEvents = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.EnableEvents = False
With Target
If .Column <> 1 Or .Row <> 1 Or .CountLarge > 1 Then Cells(1, 1).Select
End With
Application.EnableEvents = True
End Sub
2. Protecting the sheet - doesn't allow cell navigation
Private Sub Worksheet_Activate()
Me.Protect
Me.EnableSelection = xlNoSelection
End Sub
I'm working in Excel on a Userform. Essentially, I want a "Photoshop-esque" toolbar that floats over my spreadsheet while I work, allowing me to select and use various tools.
I've got a series of toggle buttons set up so that when one is clicked, any other toggle buttons go back to unclicked. It's a little more complicated because I have sub-buttons, if that makes sense, meaning that once I have a button clicked, I can click one of four other buttons to make my actual selection, and these four buttons are mutually exclusive from each other as well.
The weird thing: I haven't been able to get these buttons to work. Except. For some reason, when I right-click only, the buttons work like a charm. Left-click: nothing. Help please?
Sample button code:
Private Sub tMouse_MouseUp(ByVal button As Integer, _
ByVal shift As Integer, ByVal X As Single, ByVal Y As Single)
tMouse.Value = True
tActual.Value = False
tSched.Value = False
tX.Value = False
tDiam.Value = False
tCirc.Value = False
tTri.Value = False
tTrash.Value = False
tText.Value = False
End Sub
EDIT:
I tried what was suggested about printing the value of the toggle button. And my computer blew up with messageboxes. I had changed all the actions to Click() events. Apparently I was sending the computer through an infinite loop. Maybe the act of changing a button from true to false or vice versa acts like a click and triggers all the other click events?
You have events that are triggering other events. What you'll need to do is set a Boolean AllowEventsToRun variable (either at the module or public level) and set that to false at the start of your code. Run whatever you need to do, and then set it to true at the end.
The trick is to do an if statement to make sure that AllowEventsToRun is set to true before any other code is running. Be sure to initialize the Boolean to true when you load your userform (since the default value of a boolean is false. So something like this:
Option Explicit
Private AllowEventsToRun As Boolean
Private Sub ToggleButton1_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If AllowEventsToRun Then
AllowEventsToRun = False
'whatever you're doing that's causing the events to chain fire
AllowEventsToRun = True
End If
End Sub
Private Sub ToggleButton2_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If AllowEventsToRun Then
AllowEventsToRun = False
'whatever you're doing that's causing the events to chain fire
AllowEventsToRun = True
End If
End Sub
Private Sub UserForm_Initialize()
AllowEventsToRun = True
End Sub
source: http://www.cpearson.com/excel/SuppressChangeInForms.htm
I would recommend using an "Option" Control instead of a "Toggle" Control.
If you stick 4 options in 1 frame then only 1 of those 4 options will allow itself to be true at a time automatically. You should use the "ToggleButton" control only if you want multiple instances of it to be true at the same time.
However if you refuse to do so and just really want to use ToggleButtons. Then you could write a procedure that is executed once pressing the button that sends it's name (or something else that identifies it uniquely) as a parameter to a procedure that sets all other togglebuttons false except it.
Cheers!
Private Sub ToggleButton1_Click()
Dim s As String
s = "ToggleButton1"
Evaluate_Options s
End Sub
Private Sub ToggleButton2_Click()
Dim s As String
s = "ToggleButton2"
Evaluate_Options s
End Sub
Private Sub ToggleButton3_Click()
Dim s As String
s = "ToggleButton3"
Evaluate_Options s
End Sub
Private Sub ToggleButton4_Click()
Dim s As String
s = "ToggleButton4"
Evaluate_Options s
End Sub
Private Sub ToggleButton5_Click()
Dim s As String
s = "ToggleButton5"
Evaluate_Options s
End Sub
Private Sub ToggleButton6_Click()
Dim s As String
s = "ToggleButton6"
Evaluate_Options s
End Sub
Private Sub ToggleButton7_Click()
Dim s As String
s = "ToggleButton7"
Evaluate_Options s
End Sub
Private Sub ToggleButton8_Click()
Dim s As String
s = "ToggleButton8"
Evaluate_Options s
End Sub
Private Sub Evaluate_Options(s As String)
Dim tgl As Control
For Each tgl In UserForm1.Frame1.Controls
If InStr(tgl.Name, s) Then Set_Toggles_1 tgl
Next
For Each tgl In UserForm1.Frame2.Controls
If InStr(tgl.Name, s) Then Set_Toggles_2 tgl
Next
End Sub
Private Sub Set_Toggles_1(tglTrue As Control)
Dim tglFalse As Control
For Each tglFalse In UserForm1.Frame1.Controls
If tglFalse.Name = tglTrue.Name Then tglFalse = True Else tglFalse = False
Next
End Sub
Private Sub Set_Toggles_2(tglTrue As Control)
Dim tglFalse As Control
For Each tglFalse In UserForm1.Frame2.Controls
If tglFalse.Name = tglTrue.Name Then tglFalse = True Else tglFalse = False
Next
End Sub
Try these basic mouse event capture subs and modify to suit your needs (tMouse = toggle button name):
Private Sub tMouse_Click()
'MsgBox "tb value = " & tMouse.Value
End Sub
Note: upper sub will not work, if lower sub called
Private Sub tMouse_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If Button = 1 Then MsgBox "Left"
If Button = 2 Then MsgBox "Right"
End Sub