6
votes

VBA (Excel) ActiveX Listbox Changer le comportement récursif d'événement

Je ne suis pas un programmeur VBA, donc je m'excuse à l'avance si une partie de ma terminologie dans cette question est incorrecte. Un collègue de mien souhaitait effacer la sélection d'une zone de liste dès sa sélection. Après une google, nous avons trouvé une façon de le faire était via l'événement de changement. Au départ, nous avons essayé: xxx

Cependant, il semblait que définir la propriété sélectionnée sur false déclenche un événement Changement sur la zone de liste et ceci devient efficacement une boucle infinie et provoque l'accident d'Excel (2007). Étant donné que nous savions qu'il y avait deux entrées, nous avons également essayé: xxx

et cela fonctionne! Bien que nous nous attendions au même comportement - pour le réglage de la propriété sélectionnée pour que l'événement de changement se déclenche à nouveau et à obtenir une boucle infinie.

Cependant, il semble qu'une fois par ex. LISTBOX1.Selected (0) = FALSE L'événement de changement est re-déclenché mais dans cette itération, il ne se rétrécit pas sur cette ligne - je suppose parce qu'il sait que ce sélectionné la propriété a déjà été définie sur false pour cet article, de sorte que rien ne change.

mais si tel est le cas, nous nous attendions également à ce comportement dans la Première solution .. Donc, il semble qu'il y a une différence de dire ListBox1.Selected (i) = FALSE VERSUS Spécification de l'index d'élément réel directement (plutôt que via la variable i < /STSTRONG >).

> Quiconque connaissez la raison de ce comportement? J'espère que la question a du sens que j'ai essayé de l'expliquer le mieux que je peux.

merci Amit


5 commentaires

Pour arrêter les événements de re-déclenchement, lisez Ce .


Merci beaucoup de bleu - En fait, nous avons résolu le problème de la boucle en utilisant quelque chose de similaire à ce qui est discuté dans le lien que vous avez posté .. Mais ma question ci-dessus (probablement très claire!) Est d'essayer de comprendre pourquoi le comportement diffère dans les deux cas ( Le premier donne une boucle infinie la seconde ne le fait pas)


Y a-t-il littéralement seulement 2 articles disponibles pour sélectionner dans la liste de liste? Ou voulez-vous dire que seuls 2 éléments ont été sélectionnés?


Dans le but de l'exemple, il y avait deux éléments dans la zone de liste, mais pour le cas d'utilisation réelle, il y en a 5


Je ne peux pas reproduire aucune différence entre les deux versions (Excel 2007). L'événement de changement est soulevé uniquement pour l'élément sélectionné [sélectionné (item_index) est égal à true], mais lorsque le gestionnaire d'événements de changement est ré-entré, cet élément est désélectionné [sélectionné (item_index) est égal à False] qui est correct et changement d'événement n'est pas ré-entré à nouveau. Cela fonctionne donc comme prévu et est pour les deux versions les mêmes.


6 Réponses :


0
votes

Attachez votre boucle à l'événement de clic au lieu de l'événement de changement pour arrêter les boucles infinies: xxx

Je ne crois pas que "pourquoi" de cette question a une réponse facile. Généralement, le mot est très linéaire et ne peut traiter que 1 chose à la fois. Les processeurs modernes optimisent toutefois le code et exécutent des choses en tandem. Le mot est simplement confus dans des moyens suffisamment prévisibles de fournir des solutions de contournement relativement cohérentes pour la confusion. L'astuce que vous avez mentionnée ci-dessus (le faisant deux fois) est un moyen populaire de gérer ce problème (j'ai vu de nombreuses recommandations lorsque j'avais le même problème avec les cases de liste).

Je préfère améliorer la logique plutôt que tenter un travail bâclé autour. Comme ci-dessus, désactivez plutôt les événements ou utilisez le double truc, j'ai simplement compris que l'événement de changement n'était pas le bon événement à utiliser.


1 commentaires

Je crois que nous avons essayé avec ListBox Click, mais je pense que cela déclenché avant que la sélection soit "physiquement" sélectionnée dans la zone de liste, modifier ainsi la propriété sélectionnée n'avait aucun effet



0
votes

Je devrais faire plus de recherches à ce sujet, mais je sais que pendant un pour ... Suivant boucle, une fois que le code frappe le Suivant ligne ajoute 1 à la variable (en supposant que vous n'avez pas défini de étape ), puis exécute un test logique pour déterminer si la variable est toujours entre votre inclusifs pour bla Conditions. Étant donné que chacune d'entre elles fonctionne indépendamment, il permet au code de vérifier votre événement _change () . Quelques excellentes sollaires pour empêcher une boucle infinie: change () Événement des boucles infinies

Edit: Voici quelques informations supplémentaires sur les causes de la trigger listbox.changer Documentation . Il mentionne que

En outre, un changement programmatique de listebox.listindex déclenche également l'événement de changement.

qui pourrait être ce qui est vérifié entre les boucles.


0 commentaires

0
votes

Vous avez raison à propos de l'utilisation de l'événement de changement, mais c'est un peu délicat dans les cases de liste. Vous avez évidemment déclencher l'événement de changement chaque fois que vous désélectionnez un élément, car vous êtes changer em> la liste de code de code.

La réponse de guitarthore em> va dans la bonne direction , mais je ne pense pas que Application.Enablevents code> ferait le travail dans ce cas car il n'a aucun effet sur les objets ActiveX. P>

Alors, j'essaierais ce deux Alternatives qui essaient d'émuler le travail de Application.Enablevents code> par la programmation simple: p>

  • Alternative 1: solution générale pour l'événement de changement. Cependant, il est un peu risqué si la variable code> noexecute code> n'est pas réinitialisée par aucune raison (fonction de sortie due à une erreur). P>

    Private Sub ListBox1_Change()
        For i = 0 To ListBox1.ListCount - 1
            If ListBox1.Selected(i) Then
                ListBox1.Selected(i) = False
            End If
        Next
    End Sub        
    
  • alternative 2: meilleure solution dans ce cas, bien que pas aussi jolie que la précédente. P>

    Private NoExecute As Boolean
    
    Private Sub ListBox1_Change()
    
        If NoExecute Then Exit Sub
    
        NoExecute = True
    
        For i = 0 To ListBox1.ListCount - 1
            ListBox1.Selected(i) = False
        Next
    
        NoExecute = False
    
    End Sub
    


1 commentaires

Merci pour l'info - En fait, nous avons mis en œuvre la première solution en tant que travail autour, ma question était plus pourquoi y a-t-il une différence de comportement pour les deux cas que j'ai décrites



0
votes

Arrêter la folie infinie, vous pouvez le faire (une question difficile encore meilleure est, pourquoi voudriez-vous faire cela quand même, car après cette valeur ne peut être sélectionnée ou peut être réellement modifiée en faux) - < PRE> XXX

Maintenant, la raison de la boucle infinie n'est pas visible et que l'on ne peut que deviner, mais permet d'abord de corriger l'hypothèse que le bloc de code sans la prochaine boucle ne causerait pas le même problème. Il fait la même chose que la première chose que le premier et est coincé dans une boucle infinie, si vous modifiez la valeur de la liste de liste1.Selected (1) ou ultérieure.

Pourquoi cela se produit est que l'événement changera Être déclenché juste après la modification de la première valeur et que la première cellule est modifiée, l'événement de modification est déclenché et que l'exécution de code est arrêtée pour cette instance et commence à nouveau. Maintenant, les deux codes fonctionnent sans causer de boucle si seul le premier élément est changé et pourquoi cela se produit est probablement que le compilateur frappe avec son automatie. Je ne peux pas vous dire la vraie raison derrière les événements, mais ce qui se passe probablement, c'est que le compilateur prédit lorsque seule la première valeur est modifiée et optimise le code pour ne faire que le seul changement et rien d'autre et quand les autres valeurs changent, il tente de Réécrivez chaque valeur et la première valeur à chaque fois et encore la boucle infinie est déclenchée.

C'est à quoi il s'agit, de bien comprendre ce qui se passe sous la hotte, vous feriez mieux de contacter Mme. < / p>


0 commentaires

0
votes

juste pour référence future: Si vous voulez juste Désactiver la sélection forte> dans une liste CODE> ListBox CODE> UTILISEZ UTILISER

ListBox.Locked = True


0 commentaires

1
votes

Je suis une année de retard à la fête mais j'espère que cela aidera les autres. J'avais un problème avec listbox1_click () forte> boucle infinie plutôt que change () strong>. Cependant, je pense que cela peut être une solution viable aux deux.

Chaque fois que j'ai appelé listbox1.Selected (i) = true fort>, il le déclencherait comme un clic () strong> ou un change () strong> . Dans ma routine clic () forte>, il existe certains index qui entraîneront la repeuplement de la liste complète de se repoduler avec une nouvelle liste et resélect fort> lui-même. Cela provoque la boucle infinie quand elle se résolvait. Il m'a fallu une journée pour résoudre le problème, mais à la fin de la solution, n'utilisez pas l'événement Click () Strong>; Au lieu de cela, j'ai utilisé MouseDown () Strong> événement avec un petit calcul. Cela élimine l'utilisation de click () fort>. J'ai noté que j'utilise cela dans une seule liste de liste Sélectionner et non une liste de liste de sélection multiple. Vous pouvez utiliser une déclaration si forte> avec un booléen pour l'appliquer à Multiselect. Goodluck! P>

Private Sub ListBox1_MouseDown(ByVal Button As Integer, ByVal Shift As 

Integer, ByVal x As Single, ByVal Y As Single)

    On Error Resume Next  'You can comment this out for trouble shooting
    If Button = 1 And UBound(ListBox1.List) <> -1 Then
        ListBox1.Selected(((Y / 9.75) - 0.5) + ListBox1.TopIndex) = True
        MsgBox "left Click"
        'You can use Button = 2 for right click
        'Do some other stuff including listbox1.select(1234)

    End If
End Sub


1 commentaires

Merci. Je croyais que cela n'ajouterait pas de valeur, mais il peut être utilisé car la sélection est déjà enregistrée avant le tir à l'événement. Par conséquent, vous pouvez détecter une modification d'un élément de liste spécifique dans certains cas. Par exemple, je voulais un élément de liste (0) de «réinitialiser les filtres» ci-dessous, cela peut fonctionner dans ce cas parce que je l'efface toujours. Si c'est sélectionné, alors je sais que l'utilisateur a juste fait et je peux suivre de la poursuite.