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.
* 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
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.
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.
tu as zappé mon post #15 ET mon post #16 ! la solution du post #16 devrait t'intéresser plus, car elle permet de choisir 2 colonnes sans inputbox ; pour les 2 fichiers Excel : quel est ton avis ?
* 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
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.
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.
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.
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 :
* 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 :
* 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 :
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
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...
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 !
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 !
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é !