This seems to work ok, but it looks like a lot of code just to detect a mouse click. For instance, I thought it should be possible to create a Class that contains all the Form Controls, so I could detect a click on any of them in one go, without having to check on each kind of control separately. I couldn't make that work and I'm hoping somebody can improve on this.
Just to restate what this does: On a Userform, a large frame named mapFrame holds any number of other frames and labels, and all those contained frames can hold any number of other frames and labels, but that's as deep as the nesting goes. I want to start a loop, (in this case the loop blinks a control off and on, but it could be any other loop) and wait for the user to click on any of the contained Frames or Labels to signal an exit from the loop. I also want to get the name of the control that was clicked.
I took the suggestion by therealmarv and used the click to set a public Boolean which gets tested inside the loop.
In a new Class Module:
Option Explicit
Public WithEvents classLabels As msForms.Label
Private Sub classLabels_Click()
clickedControlName = "" '<== Public String
With classLabels
If .Parent.Name = "mapFrame" Or _
.Parent.Parent.Name = "mapFrame" Then
isClickDetected = True '<== Public Boolean
clickedControlName = .Name
End If
End With
End Sub
In another new Class Module:
Option Explicit
Public WithEvents classFrames As msForms.Frame
Private Sub classFrames_Click()
clickedControlName = "" '<== Public String
With classFrames
If .Name = "mapFrame" Or _
.Parent.Name = "mapFrame" Or _
.Parent.Parent.Name = "mapFrame" Then
isClickDetected = True '<== Public Boolean
clickedControlName = .Name
End If
End With
End Sub
In a Form Module:
Option Explicit
Dim frames() As New clsFrames
Dim labels() As New clsLabels
Private Sub createFrameListeners()
Dim ctl As msForms.Control
Dim frameCount as Long
For Each ctl In Me.Controls
' Debug.Print TypeName(ctl): Stop
If TypeName(ctl) = "Frame" Then
frameCount = frameCount + 1
ReDim Preserve frames(1 To frameCount)
'Create the Frame Listener objects
Set frames(frameCount).classFrames = ctl
End If
Next ctl
End Sub
Private Sub createLabelListeners()
Dim ctl As msForms.Control
Dim LabelCount as Long
For Each ctl In Me.Controls
' Debug.Print TypeName(ctl): Stop
If TypeName(ctl) = "Label" Then
LabelCount = LabelCount + 1
ReDim Preserve labels(1 To LabelCount)
'Create the Label Listener objects
Set labels(LabelCount).classLabels = ctl
End If
Next ctl
End Sub
Function blinkThisControl(ctrl As Control, ByVal blinkCount As Long)
isClickDetected = False
Dim i As Integer
For i = 1 To blinkCount
' <blink ctrl twice>
DoEvents
If isClickDetected Then Exit Function
'name of clicked control will be in clickedControlName
Next i
End Function
Private Sub userform_initialize()
Call createFrameListeners
Call createLabelListeners
' do other stuff
End Sub