Autres Filtre sur colonnes multiples

Michel1942

XLDnaute Nouveau
Bonjour à tous,



J’ai le problème suivant en VBA sous excel 2003.


Je voudrais filtre sur place un tableau sur deux colonnes non contigües si les cellules sont vides dans les deux colonnes simultanément.
Les colonnes ne sont pas fixes et doivent être sélectionnées avant de lancer la macro.
Le bouton de lancement existe déjà dans ma barre d’outils.
Je joint un exemple de fichier où filtrer les colonnes B et E mais pas forcément.

Je sais faire le filtre sur une colonne.

Merci d’avance pour vos propositions.
 

Pièces jointes

  • Test2.xls
    42.5 KB · Affichages: 9

soan

XLDnaute Barbatruc
Inactif
@Michel

Lis d'abord mon post #15 précédent.

* fais Ctrl f ; ça fait rien du tout ! :( c'est normal, car en A2 y'a 0 ; faut qu'y'ait 2, mais n'y touche pas !

* pour choisir la 1ère colonne, par exemple la colonne B, mets un "x" en B2 ➯ en A2 : 1

* pour choisir la 2ème colonne, par exemple la colonne E, mets un "x" en E2 ➯ en A2 : 2

"x" est la lettre X minuscule ; formule en A2 : =NB.SI(B2:E2;"x") ; maint'nant qu'tu as choisi tes 2 colonnes avec "x" : il y a 2 en A2 et tu peux faire Ctrl f ➯ filtre selon les 2 colonnes choisies. :)



code VBA (24 lignes) :

VB:
Option Explicit

Sub FiltrerBE()
  If ActiveSheet.Name <> "Feuil1" Then Exit Sub
  Dim dlg&: dlg = Cells(Rows.Count, 1).End(3).Row: If dlg < 3 Then Exit Sub
  Dim n As Byte: n = [A2]: If n <> 2 Then Exit Sub
  Dim plg As Range, col%(1 To 2), lig&, k%: k = 1: n = 0
  Do
    k = k + 1: If Cells(2, k) = "x" Then n = n + 1: col(n) = k
  Loop Until n = 2
  For lig = 3 To dlg
    If IsEmpty(Cells(lig, col(1))) And IsEmpty(Cells(lig, col(2))) Then
      If plg Is Nothing Then
        Set plg = Rows(lig)
      Else
        Set plg = Union(plg, Rows(lig))
      End If
    End If
  Next lig
  If plg Is Nothing Then Exit Sub
  Application.ScreenUpdating = 0
  plg.EntireRow.Hidden = -1
End Sub

soan
 

Pièces jointes

  • Test2.xls
    70 KB · Affichages: 3

TooFatBoy

XLDnaute Barbatruc
Je n'ai toujours pas compris l'intérêt d'une macro par rapport aux filtres activés manuellement, mais si on ne répondait qu'aux questions auxquelles on trouve un intérêt on ne répondrait pas souvent... ;)

Je te propose donc cette macro, affectée à un bouton :
VB:
Sub Filtrage()
'
Dim MonTableau As Range
Dim MonCritere As String
Dim i As Integer

    With ActiveSheet

        ' On détermine la plage du tableau de la feuille
        Set MonTableau = .Range("A2:E" & .Range("A" & .Rows.Count).End(xlUp).Row)

        ' On supprime les filtres de la feuille active
        .AutoFilterMode = False

        If Union(MonTableau.Resize(1), Selection).Address = MonTableau.Resize(1).Address Then

            Application.ScreenUpdating = False

            ' On défini le critère de filtrage
            MonCritere = "="

            ' On masque les flèches de filtrage
            For i = 1 To MonTableau.Columns.Count
                If Intersect(MonTableau.Resize(1).Cells(1, i), Selection) Is Nothing Then
                    MonTableau.AutoFilter field:=i, Visibledropdown:=False
                Else
                    MonTableau.AutoFilter field:=i, Criteria1:=MonCritere, Visibledropdown:=False
                End If
            Next i

'            For i = 2 To MonTableau.Rows.Count
'                MonTableau.Cells(i, 1).Rows.Hidden = Not MonTableau.Cells(i, 1).Rows.Hidden
'            Next i

            Application.ScreenUpdating = False

        End If

    End With

End Sub

Tu sélectionnes les cellules A, B, C, D, ou E que tu veux sur la ligne 2, puis tu cliques sur le bouton qui est associé à la macro pour filtrer les colonnes des cellules sélectionnées.
Si tu sélectionnes autre chose, quand tu cliques sur le bouton ça désactive le filtrage.


ps : tout comme le filtrage manuel proposé en #3, les filtres ne sont pas activés simultanément mais consécutivement, mais ça te conviendra peut-être mieux car le temps entre l'application des filtres est infime comparé à une action manuelle.

pps : si en fait c'est le filtrage inverse de celui que tu as demandé que tu veux réellement, alors "décommentarise" les trois lignes en fin de macro qui inversent le filtrage.
 
Dernière édition:

Michel1942

XLDnaute Nouveau
Mes recherches m’ont conduit à ceci.

Cà semble exaucer une partie de mes souhaits

Sub test()

Dim ref As Range

Set ref = Application.InputBox(prompt:="Sélectionner les colonnes", Type:=8)

MsgBox (ref.Address)

End Sub

L’exécution donne : $B:$B ; $E :$E

Comment extraire de ceci la lettre de la 1ère colonne (B dans l’exemple) et celle de la 2ème colonne mais ces lettres peuvent varier, pour les attribuer à ColActive1 et ColActive2.

Merci d'avance à qui me trouvera une solution, bonne journée à tous.
 

Michel1942

XLDnaute Nouveau
@Michel

Lis d'abord mon post #15 précédent.

* fais Ctrl f ; ça fait rien du tout ! :( c'est normal, car en A2 y'a 0 ; faut qu'y'ait 2, mais n'y touche pas !

* pour choisir la 1ère colonne, par exemple la colonne B, mets un "x" en B2 ➯ en A2 : 1

* pour choisir la 2ème colonne, par exemple la colonne E, mets un "x" en E2 ➯ en A2 : 2

"x" est la lettre X minuscule ; formule en A2 : =NB.SI(B2:E2;"x") ; maint'nant qu'tu as choisi tes 2 colonnes avec "x" : il y a 2 en A2 et tu peux faire Ctrl f ➯ filtre selon les 2 colonnes choisies. :)



code VBA (24 lignes) :

VB:
Option Explicit

Sub FiltrerBE()
  If ActiveSheet.Name <> "Feuil1" Then Exit Sub
  Dim dlg&: dlg = Cells(Rows.Count, 1).End(3).Row: If dlg < 3 Then Exit Sub
  Dim n As Byte: n = [A2]: If n <> 2 Then Exit Sub
  Dim plg As Range, col%(1 To 2), lig&, k%: k = 1: n = 0
  Do
    k = k + 1: If Cells(2, k) = "x" Then n = n + 1: col(n) = k
  Loop Until n = 2
  For lig = 3 To dlg
    If IsEmpty(Cells(lig, col(1))) And IsEmpty(Cells(lig, col(2))) Then
      If plg Is Nothing Then
        Set plg = Rows(lig)
      Else
        Set plg = Union(plg, Rows(lig))
      End If
    End If
  Next lig
  If plg Is Nothing Then Exit Sub
  Application.ScreenUpdating = 0
  plg.EntireRow.Hidden = -1
End Sub

soan
Merci Soan, çà fonctionne bien mais mon souci est que dans la réalité les cellules 2 ne sont pas vides d'où mon idée de sélectionner à la souris. Mais je vais commencer avec ta solution en modifiant la présentation de l'original.
 

Michel1942

XLDnaute Nouveau
Je n'ai toujours pas compris l'intérêt d'une macro par rapport aux filtres activés manuellement, mais si on ne répondait qu'aux questions auxquelles on trouve un intérêt on ne répondrait pas souvent... ;)

Je te propose donc cette macro, affectée à un bouton :
VB:
Sub Filtrage()
'
Dim MonTableau As Range
Dim MonCritere As String
Dim i As Integer

    With ActiveSheet

        ' On détermine la plage du tableau de la feuille
        Set MonTableau = .Range("A2:E" & .Range("A" & .Rows.Count).End(xlUp).Row)

        ' On supprime les filtres de la feuille active
        .AutoFilterMode = False

        If Union(MonTableau.Resize(1), Selection).Address = MonTableau.Resize(1).Address Then

            Application.ScreenUpdating = False

            ' On défini le critère de filtrage
            MonCritere = "="

            ' On masque les flèches de filtrage
            For i = 1 To MonTableau.Columns.Count
                If Intersect(MonTableau.Resize(1).Cells(1, i), Selection) Is Nothing Then
                    MonTableau.AutoFilter field:=i, Visibledropdown:=False
                Else
                    MonTableau.AutoFilter field:=i, Criteria1:=MonCritere, Visibledropdown:=False
                End If
            Next i

'            For i = 2 To MonTableau.Rows.Count
'                MonTableau.Cells(i, 1).Rows.Hidden = Not MonTableau.Cells(i, 1).Rows.Hidden
'            Next i

            Application.ScreenUpdating = False

        End If

    End With

End Sub

Tu sélectionnes les cellules A, B, C, D, ou E que tu veux sur la ligne 2, puis tu cliques sur le bouton qui est associé à la macro pour filtrer selon les cellules sélectionnées.
Si tu sélectionnes autre chose, quand tu cliques sur le bouton ça désactive le filtrage.


ps : tout comme le filtrage manuel proposé en #3, les filtres ne sont pas activés simultanément mais consécutivement, mais ça te conviendra peut-être mieux car le temps entre l'application des filtres est infime comparé à une action manuelle.

pps : si en fait c'est le filtrage inverse de celui que tu as demandé que tu veux réellement, alors "décommentarise" les trois lignes en fin de macro qui inversent le filtrage.
Merci pour ta solution. Je vais tester et faire un choix avec celle de Soan.
 

TooFatBoy

XLDnaute Barbatruc
Ma question était : comment récupérer 2 colonnes sélectionnées simultanément en VBA. Cà rentre dans plus grand que mon exemple. Le reste je me débrouille pour faire.
Si tu veux juste récupérer les numéros des colonnes sélectionnées, tu peux faire un truc de ce genre :

VB:
Sub test()
'
    For Each c In Selection
        NumeroColonne = c.Column
    Next c

End Sub
 
Dernière édition:

soan

XLDnaute Barbatruc
Inactif
Bonjour Michel, Marcel,

Merci Soan, ça fonctionne bien

merci pour ton retour ! 😊



mais mon souci est que dans la réalité les cellules de la ligne 2 ne sont pas vides

aïe, c'est effectivement plutôt gênant !



je vais commencer avec ta solution en modifiant la présentation de l'original

oui, c'est une très bonne idée ! :) 👍



malgré tout, je vais quand même te proposer une solution avec 2 inputbox ; bien sûr, en A2, j'ai supprimé l'ancienne formule qui était dans mon fichier précédent ! attention : cette version ne fait pas encore le filtrage, car c'est une version de démo, pour te montrer tout ce qui concerne les 2 inputbox.​



fais Ctrl f ➯ fenêtre de saisie de la 1ère colonne :

Image 1.jpg


* saisis "abc" et clique sur "OK" : y'a pas d'plantage, même si c'est du texte, et ça reste sur la même 1ère fenêtre de saisie.

* saisis 0 : refusé, ça reste sur la 1ère fenêtre ; c'est normal, car la colonne 0 n'existe pas !

* saisis 1 : refusé, même si la colonne 1 existe, et ça reste sur la 1ère fenêtre ; c'est normal, car il ne faut pas filtrer sur la 1ère colonne des communes !

* tu peux saisir 2 (ou plus) ; pour la démo, saisis 5 : accepté ➯ ça passe à la 2ème fenêtre de saisie.​



fenêtre de saisie de la 2ème colonne :

Image 2.jpg


* comme pour la 1ère fenêtre de saisie : minimum 2 ; en plus, faut que ça soit différent de la 1ère colonne choisie ; eh oui, hein ? faut y penser aussi ! 😜

* saisis "abc" et clique sur "OK" : y'a pas d'plantage, même si c'est du texte, et ça reste sur la même 2ème fenêtre de saisie.

* saisis 0 : refusé, ça reste sur la 2ème fenêtre ; c'est normal, car la colonne 0 n'existe pas !

* saisis 1 : refusé, même si la colonne 1 existe, et ça reste sur la 2ème fenêtre ; c'est normal, car il ne faut pas filtrer sur la 1ère colonne des communes !

* saisis 5 : refusé (car tu as déjà choisi 5 pour la 1ère colonne) ; ça reste sur la 2ème fenêtre.

* tu peux saisir 2 (ou plus, sauf 5) ; pour la démo, saisis 3 : accepté ➯ ça montre les 2 colonnes choisies 3 et 5 :​

Image 3.jpg


accessoirement, note que ça a aussi mis les numéros dans l'ordre 3 et 5, au lieu de ta saisie initiale de 5 puis 3 ; mais c'est en fait un petit plus inutile, car même en laissant 5 et 3, ça ferait ensuite le même traitement vu que par rapport au AND, ça fait pas de différence pour cette ligne de code VBA :

VB:
If IsEmpty(Cells(lig, col1)) And IsEmpty(Cells(lig, col2)) Then

je veux dire : If IsEmpty(Cells(lig, 5)) And IsEmpty(Cells(lig, 3)) Then

idem que : If IsEmpty(Cells(lig, 3)) And IsEmpty(Cells(lig, 5)) Then

clique sur OK pour sortir de la fenêtre ci-dessus.​



pour les 2 fenêtres de saisie : si tu veux abandonner l'opération, tu peux appuyer sur la touche Echap pour sortir de la boîte de dialogue ; ça quittera la sub aussitôt, sans rien faire.​



pour avoir la version définitive qui fait le filtrage, il te suffit, dans le code VBA, de supprimer cette ligne :​

VB:
MsgBox col1 & ", " & col2: Exit Sub



éventuellement, tu peux aussi supprimer cette ligne :

VB:
If col1 > col2 Then k = col1: col1 = col2: col2 = k

car c'est elle qui met les 2 colonnes dans l'ordre ; si tu fais ça, alors remplace cette ligne :​

VB:
  Dim plg As Range, msg$, chn$, col1%, col2%, k%, lig&

par ceci :

VB:
  Dim plg As Range, msg$, chn$, col1%, col2%, lig&

car la variable k est devenue inutile ; j'avais ajouté cette variable k uniquement pour faire l'échange des 2 numéros de colonne.​



t'es convaincu ? ça t'plaît ? si oui, j'en suis ravi, même si perso, j'préfère quand même largement la version sans inputbox, avec choix des 2 colonnes par coche "x" : y'a pas besoin d'faire tous les tests concernant la saisie effectuée dans les 2 inputbox, et peu importe l'ordre de cochage des 2 "x" ; bien sûr, il ne faut pas que l'utilisateur saisisse un "x" en A2, sinon il écrase cette formule : =NB.SI(B2:E2;"x") ; mais c'est aussi ça qui fait que la 1ère colonne des communes ne peut pas être choisie comme colonne de filtrage.

après, c'est juste une question de goût, et à chacun ses goûts et ses couleurs. 😄



code VBA (34 lignes) :

VB:
Option Explicit

Sub FiltrerBE()
  If ActiveSheet.Name <> "Feuil1" Then Exit Sub
  Dim dlg&: dlg = Cells(Rows.Count, 1).End(3).Row: If dlg < 3 Then Exit Sub
  Dim plg As Range, msg$, chn$, col1%, col2%, k%, lig&
  msg = "1ère colonne (minimum 2) :"
  Do
    chn = InputBox(msg, "Saisir le n° de la 1ère colonne")
    If chn = "" Then Exit Sub
    If Not IsNumeric(chn) Then col1 = 1 Else col1 = Val(chn)
  Loop Until col1 > 1
  msg = "2ème colonne (minimum 2, et différent de " & col1 & ") :"
  Do
    chn = InputBox(msg, "Saisir le n° de la 2ème colonne")
    If chn = "" Then Exit Sub
    If Not IsNumeric(chn) Then col2 = 1 Else col2 = Val(chn)
  Loop Until col2 > 1 And col2 <> col1
  If col1 > col2 Then k = col1: col1 = col2: col2 = k
MsgBox col1 & ", " & col2: Exit Sub
  For lig = 3 To dlg
    If IsEmpty(Cells(lig, col1)) And IsEmpty(Cells(lig, col2)) Then
      If plg Is Nothing Then
        Set plg = Rows(lig)
      Else
        Set plg = Union(plg, Rows(lig))
      End If
    End If
  Next lig
  If plg Is Nothing Then Exit Sub
  Application.ScreenUpdating = 0
  plg.EntireRow.Hidden = -1
End Sub

soan
 

Pièces jointes

  • Test2.xls
    72.5 KB · Affichages: 2

TooFatBoy

XLDnaute Barbatruc
merci pour ton retour ! 😊
Oui, on peut dire que tu as de la chance d'avoir un retour sur ton code toi... 😢


Moi je n'ai pas eu de retour,
ni sur #22 qui répondait pourtant à la question telle que posée en #12,
ni sur #17 qui répondait pourtant à la question telle que posée en #1...

Tu crois qu'en ajoutant un fichier en pièce jointe j'aurais plus de chance d'avoir un retour sur #17 ??? 🤔
Bon, je vais essayer...
 

Pièces jointes

  • Test2_Marcel32-v1.xls
    71.5 KB · Affichages: 1
Dernière édition:

soan

XLDnaute Barbatruc
Inactif
@Marcel32, Michel,
Oui, on peut dire que tu as de la chance d'avoir un retour sur ton code toi... 😢

si ça peut te consoler 😜, Michel t'a répondu plusieurs fois :

post #6 ; post #7 ; post #10 ; post #12 ; post #14.

mais effectivement, je n'ai pas vu de retour sur le code de ton post #17 ; c'est sans doute car tu n'as pas utilisé de inputbox ; or selon le post #18 de Michel, il y tient beaucoup vu qu'il y a cette ligne de code :
Set ref = Application.InputBox(prompt:="Sélectionner les colonnes", Type:=8)

il est d'accord pour essayer ma solution avec coche "x", mais apparemment, il n'est pas intéressé par ta version avec filtre, bien que le titre de ce sujet soit : « Filtre sur colonnes multiples » ; ça m'fait penser à dire pour Michel cette remarque importante : pour ma version avec coche "x" et pour ma version avec inputbox :

y'a pas besoin qu'tu sélectionnes les 2 colonnes à filtrer ➯ c'est plus sûr ; en effet, imagine qu'après avoir sélectionné les 2 colonnes tu appuies par mégarde sur la touche Suppression : tu effaces sans l'vouloir le contenu des 2 colonnes choisies ; bien sûr, tu peux faire Ctrl z pour annuler cette suppression, mais il faut que tu le fasses sans tarder, pour éviter qu'une autre opération rende irréversible la récupération des données supprimées (par exemple le lancement d'une macro ➯ commande "Annuler" en grisé et donc indisponible) ; il faut aussi, évidemment, que l'utilisateur sache qu'on peut faire Ctrl z ou Undo (commande Annuler, flèche arrondie vers la gauche) pour annuler une opération (si fait suffisamment tôt).


autre remarque importante pour Michel : merci de bien vouloir faire un retour sur le code VBA du post #17 de mon copain Marcel et sur celui de son post #22 , sinon Marcel sera inconsolable, et je ne vais pas savoir comment y remédier ! 😭

soan​
 
Dernière édition:

TooFatBoy

XLDnaute Barbatruc
Oui, j'ai bien vu ses réponses. ;)

En #1 il est demandé de filtrer le tableau en fonction des colonnes sélectionnées.
Les colonnes ne sont pas fixes et doivent être sélectionnées avant de lancer la macro.
C'est ce que fait #17. ;)


il n'est pas intéressé par ta version avec filtre, bien que le titre de ce sujet soit : « Filtre sur colonnes multiples »
C'est pourtant bien ce que dit le titre et ce que demande #1, il me semble... ;)

y'a pas besoin qu'tu sélectionnes les 2 colonnes à filtrer ➯ c'est plus sûr ; en effet, imagine qu'après avoir sélectionné les 2 colonnes tu appuies par mégarde sur la touche Suppression
Si tu as bien lu #17 et si j'ai été clair dans mes explications sur le fonctionnement, tu as vu qu'avec #17 on ne sélectionne pas les colonnes, donc le risque potentiel dont tu parles n'existe pas. ;)
Y a l'fichier dans #24 pour un ch'tit test plus fastoche. ;)


merci de bien vouloir faire un retour sur le code du post #17 de mon copain Marcel, sinon il sera inconsolable, et je ne vais pas savoir comment y remédier ! 😭
Et ce n'est qu'un euphémisme... 😭😭😭
Merci pour ton soutien dans cette épreuve ! 🥳
 
Dernière édition:

soan

XLDnaute Barbatruc
Inactif
Si tu as bien lu #17 et si j'ai été clair dans mes explications sur le fonctionnement, tu as vu qu'avec #17 on ne sélectionne pas les colonnes, donc le risque potentiel dont tu parles n'existe pas. ;)

oui, tu as raison ; mais ma remarque était seulement par rapport à mes 2 versions du fichier Excel ; ce n'était pas par rapport à ce que tu as proposé ! 😜

soan
 

Discussions similaires

Statistiques des forums

Discussions
315 080
Messages
2 116 003
Membres
112 636
dernier inscrit
fred 1969