2017-08-13 3 views
0

Ceci est un suivi à la question suivante: Can't set Userform.KeyPreview to trueclasse de traitement de l'événement ne se déclenche pas à moins que je casse l'initialisation formUtilisateur

Pour résumer: l'objectif est de construire un formulaire avec des boutons de commande et un cadre contenant cases à cocher. Les cases à cocher sont remplies dynamiquement à userform_initialize dans le cadre afin que l'utilisateur puisse les parcourir. Mon problème était avec les raccourcis clavier. Il n'était pas possible d'écrire en force brute des gestionnaires KeyDown pour chacune des cases à cocher car je ne sais pas lesquelles existeront. Malheureusement, Excel ne prend pas en charge KeyPreview, donc j'ai dû créer ma propre version. Merci à @UGP pour me donner des avenues prometteuses qui semblent fonctionner, mais pas tout à fait ...

D'abord, c'est mon module de classe appelé clsReasonPickKP. Je crée une nouvelle instance pour chaque case à cocher pour écouter les KeyDown événements:

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 

La ligne frm2.keyChooser keyCode lance un sous rapide situé dans le module de code formUtilisateur. Code ci-dessous:

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 

J'ai copié la partie pertinente des UserForm_Initialize sous ci-dessous. La boucle crée les cases à cocher et un écouteur d'événement pour chacun.

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 

La chose étrange est que si je casse le code quelque temps après keyPreviewCollection.Add keyPreviewer, l'auditeur ne semble pas gérer l'événement. Par exemple, si je définis un point d'arrêt à Next x ou pour x > 1 et puis terminer l'initialisation, puis lorsque le formulaire est terminé l'initialisation et apparaît l'appelant appelle keyChooser et tout va bien; si je ne casse pas le code comme ça, il ne piège pas l'événement ou n'appelle pas le sous-marin, etc.

Pour dépanner, j'ai essayé de ne pas ajouter keyPreviewer à la collection, puis l'auditeur n'a pas non plus ne fonctionne pas, peu importe si ou quand je casse. Il semble que l'ajout de l'objet à la collection, et le fait d'être en mode de rupture de code après l'avoir ajouté à la collection, font en sorte que l'écouteur piège l'événement.

Egalement intéressant, si je mets un point d'arrêt dans le module vChkBx_KeyDown, il se casse lorsque l'événement est déclenché (en supposant une pause appropriée comme décrit ci-dessus). Après avoir ensuite exécuté le code, cependant, il cesse de gérer l'événement KeyDown lorsqu'il est déclenché.

Dans le cas où il aide, je travaille actuellement dans Excel 2010.

Est-ce que quelqu'un a une idée de ce qui se passe? Une idée de comment résoudre cela, même avec une approche de code différente?

Merci comme toujours pour l'aide de tout le monde.

+0

La collection contenant la classe d'événements doit être au moins une variable large de l'utilisateur, si ce n'est pour le projet entier. Traduisez: ne déclarez pas la collection à l'intérieur d'un sous-marin, elle disparaîtra après la fin du sous-marin. –

+0

Merci @PatrickLepelletier, en regardant en arrière, je me sens même idiot! :) – PKB

Répondre

1

Il s'est avéré que le problème était si simple et juste devant mes yeux. Je devais juste rendre les variables keyPreviewer et keyPreviewCollection publiques dans mon module de code userform. Cela ne répond toujours pas pourquoi l'exécution de code de rupture après avoir ajouté l'objet à la collection VBA traité comme public, mais juste heureux que tout cela fonctionne.