Pouvoir masquer des lignes selon la valeur d'une liste

Hello à tous,

J'avais une petite question (qui n'entraîne pas forcément une petite réponse ) sur un code que j'ai produit.

Je vous explique ma problématique. Je souhaiterais masquer les lignes d'un fichier excel selon les valeurs d'une liste déroulante.

J'essaye d'appliquer ça, à un fichier avec plus de données, c'est pourquoi ma demande est un peu complexe.

(J'ai cherché sur le forum avant, et j'ai trouvé des brides d'explications que j'ai tenté d'assembler sans succès ).

Je suis parti dans l'idée de faire une boucle qui tester toutes les valeurs de la colonne, et si les valeurs sont différentes alors la ligne se masque.

La valeur vient de ma cellule d4:

Voici le code :

Private Sub W_Change(ByVal Target As Range)
Dim FL1 As Worksheet, NoCol As Integer
Dim NoLig As Long, Var As Variant

      Set FL1 = Worksheets("Feuil1")
    NoCol = 4
For NoLig = 5 To 60
       Var = FL1.Cells(NoLig, 4)

Application.ScreenUpdating = 0
Rows("1:50").EntireRow.Hidden = False
If Var <> Range("d4") Then
Rows("NoLig").EntireRow.Hidden = True
Next
Application.ScreenUpdating = -1
End Sub

Je vous joints mon fichier de test.

Ps: C'est mes débuts en VBA , je suis preneur de quelques explications si ce n'est pas trop demander.

16test-macro.xlsm (38.72 Ko)

Est ce que ça correspond à ce que tu veux ?

PS:

l'erreur était au niveau de la variable

Rows("NoLig").EntireRow.Hidden = True

il faut l'écrire ainsi

Rows(NoLig).EntireRow.Hidden = True
21test-macro.xlsm (15.17 Ko)

Bonjour,

En vrac :

1) Indenter correctement une procédure permet de la rendre plus lisible sans sauter de lignes...

2) Ta procédure n'est pas une évènementielle (déclaration non conforme), elle ne se lancera donc pas lors d'une modification dans la feuille...

3) Le besoin d'utiliser une évènementielle n'est pas par ailleurs établi.

4) Le critère sur lequel tu veux masquer des lignes est inclus dans ton tableau : il est plutôt souhaitable qu'il soit extérieur si tu veux éviter des surprises...

5) Un tableau de données ne devrait pas comporter de lignes vides.

6) False au lieu de 0 et True au lieu de -1 est plus parlant... En outre VBA rétablit automatiquement ScreenUpdating à True en fin de procédure.

7) La saisie de sept-16 ou oct-16 est interprétée par Excel comme saisie de date et il convertit donc automatiquement la valeur saisie en date. Ce n'est pas le cas de Dec-16, chaîne texte, cela aurait été le cas de Déc-16 ! L'interprétation de ce qui est date ou non dépend des paramètres régionaux du système. Il convient d'ajuster la saisie au résultat souhaité.

8) Le résultat souhaité : masquer les lignes ne correspondant pas à un critère, serait plus facilement obtenu par filtrage...

With Worksheets("Feuil1")
    .Range("B3:F3").AutoFilter 3, .Range(Critère)
End With

Critère à remplacer par l'adresse de la cellule qui le contient.

9) Dans une évènementielle réagissant au changement de valeur du critère, la ligne de code deviendrait :

Me.Range("B3:F3").AutoFilter 3, Target

10) Les autres remarques possibles sont secondaires. Il convient d'arranger le tableau, de mettre le critère hors tableau et sur une ligne non masquable, de cadrer la procédure en vérifiant que Target (cellule modifiée) est bien la cellule critère pour appliquer le filtrage.

Cordialement.

Bonjour Skrut, bonjour le forum

Top d'incohérences dans ton code !...

1 - La macro événementielle Change d'un onglet ne se renomme pas ! Quel que soit le nom que tu ais donné à cet onglet ce sera toujours, dans le composant de l'onglet concerné, Private Sub Worksheet_Change(ByVal Target As Range). En renommant, comme tu l'as fait : Private Sub W_Change(ByVal Target As Range), la procédure Change n'est simplement pas lancée.

2 - Le code doit se lancer uniquement lorsque la cellule D4 est modifiée. Pas tout le temps ! Il doit commencer par : If Target.Address <> "$D$4" Then Exit Sub

2 - Il est inutile de spécifier l'onglet puisque de toute manière c'est de lui qu'il s'agit. Sauf, évidement, si le "Change" de cet onglet doit modifier dans un autre onglet. Dans ce cas il faudra même toujours spécifier l'autre onglet, même si on l'a sélectionnée. Mais ce n'est pas le cas dans ton exemple. Donc les Dim FL1 As Worksheet et Set FL1 = Worksheets("Feuil1") sont inutiles.

3 - Tu traites les lignes de 5 à 60 et systématiquement, à chaque boucle, tu affiches les lignes 1 à 50 : Rows("1:50").EntireRow.Hidden = False ! C'est à se la prendre, se la couper, se la poser sur l'oreille pour la fumer plus tard !...

4 - Il manque un End If à ton code !

5 - Si tu utilises le nom d'une variable dans le code il ne faut pas le mettre entre guillemets ! Si la macro événementielle Change avait correctement fonctionné, Rows("NoLig") aurait généré un plantage... Il faut écrire Rows(NoLig).

6 - Tu déclares une variable NoCol, tu la définis : NoCol = 4, mais tu ne l'utilises pas dans le code. Quel intérêt ?

7 - C'est bien d'utiliser les variables mais ce n'est pas obligatoire d'en faire un élevage !...

8 - Pour supprimer des lignes il est préférable de faire une boucle inversée en partant de la dernière vers la première. Ce n'est pas nécessaire pour masquer mais j'aurais quand même coder comme ça :

Private Sub Worksheet_Change(ByVal Target As Range)
Dim LI As Integer

If Target.Address <> "$D$4" Then Exit Sub
Application.ScreenUpdating = False
Rows("5:60").Hidden = False
For LI = 60 To 5 Step -1
    If Cells(LI, 4).Value = Range("D4").Value Then Rows(LI).Hidden = True
Next LI
Application.ScreenUpdating = True
End Sub

Bref Skrut, il te faut mieux scruter tes codes si tu veux qu'ils fonctionnent. Bon Ok ! Celle-là elle est naze de chez naze mais moi je l'aime...

[Édition]

Le temps que je fasse mon laïus (et surtout que je corrige les fautes... Mais sûr qu'il en reste...), deux personnes dont l'éminent Môssieur FERRAND sont venus mettre leur grain de sel !... Pfff ! même pas mal...

Merci à tous pour vos réponses rapides.

Je suis en train d'étudier tous vos commentaires.

Je suis quand même content que pour ma première macro en VBA qu'il y'ait un rendu, à une faute de syntaxe près, même si le code n'est pas très rigoureux .

Je vais me renseigner sur les subtilités et le mode de fonctionnement de macro événementielle, je n'avais pas prévu ça.

Je vais essayer d'être plus rigoureux et cohérent pour le deuxième code.

@ThauThème : Sur le point 1, je n'ai pas saisi le passage "dans le composant de l'onglet concerné". Une macro événementielle , on peut pas changer de nom une fois écrite? Je pense que cette incompréhension vient aussi avec le fait que je ne saisis pas la notion d'événementielle . Je cours me documenter.

Merci encore à vous tous . Bon week end

Bonsoir le fil bonsoir le forum,

Les macro événementielles sont tout simplement des macros qui réagissent à un événement. Pas besoin d'un CommandButton ou de la lancer à partir de la boîte de dialogue Macro ([Alt]+[F8]), elles se lancent automatiquement.

Seuls les composants onglets Feuil(Feuil1) par exemple, et le composant ThisWorkbook ont des macros événementielles qui leur sont propres.

Pour connaître leur liste exhaustive il te suffit :

• D'ouvrir VBE (Visual Basic Editor) avec le raccourci [Alt]+[F11]

• Dans le cadre en haut à gauche, double-clique dans un composant Feuil1(Feuil1) par exemple ou dans le composant ThisWorkbook

• Dans le grand cadre à gauche tu as deux champs portant par défaut l'indication (Général) pour le premier et (Déclaration) pour le second.

• Si tu es dans un composant onglet clique dans (Général) et choisis l'option Worksheet

Le second champ (Déclarations) affiche désormais la liste de tous les événements disponibles pour cet onglet (et tous les onglets en général)

• Si tu es dans le composant ThisWorkbook clique dans (Général) et choisis l'option Workbook

Le second champ (Déclarations) affiche désormais la liste exhaustive de tous les événements disponibles pour le classeur

Pour revenir à ton exemple, le code que je t'ai proposé va agir chaque fois que l'onglet concerné ( = l'onglet dans lequel tu auras choisi l'événement) va changer. "Changer" signifiant tant ,éditer une nouvelle valeur dans une cellule vierge que modifier une valeur déjà existante ou qu'effacer le contenu d'une cellule (ou plage de cellules évidement). Ces macros peuvent être très pratiques mais elles fonctionnent en permanence et risquent d'engendrer des boucles sans fin. Si par hasard je code pour qu'au changement dans A1, ça écrive "Coucou" dans A2, l'événement Change va être relancée par ce nouveau changement dans A2. C'est pour cela que je t'ai dit qu'il fallait en limiter son rayon d'action. Pour un seule cellule on s'en sort avec un code comme je t'ai proposé :

If Target.Address <> "$A$1" Then Exit Sub

Si tu veux limiter l'action à une ligne ou une colonne ça donne :

If Target.Row <> 1 Then Exit Sub 'l'événement Change est limité à la ligne 1
If Target.Column<>2 Then Exit Sub 'l'événement Change est limité à la Colonne  2 (=B)

si tu veux limiter l'action à une plage ça donne :

If Application.Intersect(Target, Range("A1:D50")) Is Nothing Then Exit sub 'l'événement Change est limité à la plage A1:D50

Tu connais maintenant la liste de tous les événements que tu peux utiliser soit dans un onglet soit dans le classeur. Certaines actions n'engendre aucune événementielle comme par exemple mettre de la couleur ou changer de format en général...

Tu es gâté ! ThauThème a judicieusement complété quelques points que j'avais négligé, et même 2 que je n'avais pas vu ! et il s'avère qu'ils sont tout de même important pour qu'un code fonctionne comme on le souhaite.

Et en plus un condensé de cours sur les évènements !

Bon courage pour pousuivre !

Rechercher des sujets similaires à "pouvoir masquer lignes valeur liste"