Reputation: 390
This is a follow-up to the following question: Can't set Userform.KeyPreview to true
To recap: the goal is to build a form with some command buttons and a frame containing check boxes. The check boxes are dynamically populated at userform_initialize
in the frame so the user can scroll through them. My problem was with keyboard shortcuts. It wasn't possible to brute force write KeyDown handlers for each of the checkboxes because I don't know which ones will exist. Unfortunately, Excel doesn't support KeyPreview
so I had to mock up my own version. Thank you to @UGP for giving me promising avenues that seem to work, but not quite...
First, this is my class module called clsReasonPickKP
. I create a new instance for each checkbox to listen for KeyDown
events:
Option Explicit
Dim WithEvents vChkBx As MSForms.CheckBox
Friend Sub initializeListener(cControl As control)
Set vChkBx = cControl
End Sub
Private Sub vChkBx_KeyDown(ByVal keyCode As MSForms.ReturnInteger, ByVal shift As Integer)
frm2.keyChooser keyCode
End Sub
The line frm2.keyChooser keyCode
launches a quick sub located in the userform code module. Code below:
Public Sub keyChooser(ByVal keyCode As MSForms.ReturnInteger)
Select Case keyCode
Case vbKeyEscape: cancelBtn_Click
Case vbKeyReturn: completeDecision_Click
Case vbKeyN: customizeNote_Click
Case vbKeyS: resetDecisionNote_Click
Case vbKeyR: chkRefGrnds_Click
End Select
End Sub
I've copied the relevant part of the UserForm_Initialize
sub below. The loop creates the checkboxes and an event listener for each.
Sub UserForm_Initialize()
Dim x As Long, maxWidth as Long
Dim cControl As control
Dim keyPreviewCollection As New Collection
Dim keyPreviewer As clsReasonPickKP
For x = 1 To dTbl.Rows.Count - 1
Set cControl = chkBoxFrame.Controls.Add("Forms.CheckBox.1", "chkBox" & x, True)
With cControl
.AutoSize = True
.WordWrap = False
.Left = 10
.Top = 16 * x - 12
.Caption = dTbl(x, 1).Value
If .Width > maxWidth Then maxWidth = .Width
End With
Set keyPreviewer = New clsReasonPickKP
keyPreviewer.initializeListener cControl
keyPreviewCollection.Add keyPreviewer
Next x
'Additional initialization code here
End Sub
The odd thing is that unless I break code some time after keyPreviewCollection.Add keyPreviewer
, the listener doesn't seem to handle the event. For example, if I set a break point at Next x
or for x > 1
and then complete initialization, then when the form is finished initializing and appears the listener calls keyChooser
and all is well; if I don't break code like that, it doesn't trap the event or call the sub, etc.
To trouble-shoot, I've tried not adding keyPreviewer
to the collection, and then the listener also doesn't work, no matter if or when I break. It seems adding the object to the collection, and being in code break mode after adding it to the collection, somehow makes the listener trap the event.
Also interesting, if I put a breakpoint in the vChkBx_KeyDown
module, it breaks when the event is raised (assuming an appropriate break as described above). After I then run the code, however, it stops handling the KeyDown
event when its raised.
In case it helps, I'm currently working in Excel 2010.
Does anybody have any idea what's going on? Any idea how to solve this, even with a different code approach?
Thank you as always for everybody's help.
Upvotes: 0
Views: 434
Reputation: 143
DoEvents might be the ticket. See the article below:
https://www.automateexcel.com/vba/doevents/
Upvotes: 0
Reputation: 390
It turns out that the problem was so simple and right in front of my eyes. I just had to make the keyPreviewer
and keyPreviewCollection
variables public in my userform code module.
That still doesn't answer why breaking code execution after adding the object to the collection made VBA treat it as public, but just happy that it all works.
Upvotes: 1