[Excel 2000] copier un plage (range) filtrée dans un tableau

Résolu
G0lg0th Messages postés 6 Date d'inscription jeudi 21 janvier 2010 Statut Membre Dernière intervention 6 février 2010 - 6 févr. 2010 à 14:52
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 - 6 févr. 2010 à 23:46
Bonjour,

j'ai un peti souci qui est resté sans solution.

Je voudrai faire des manipulation dans un tableau qui contiendrai une plage de valeur filtrée.

voici une partie du code:

Dim rng As Range
Dim tabFilter As Variant
Dim KKColonneNumber as Integer 'la colonne ou l'on filtre
Dim Item As string 'le critère du filtre
[...]
Selection.AutoFilter Field:=KKColonneNumber, Criteria1:=Item
Set rng = ActiveSheet.AutoFilter.Range
'On copie l'ensemble des données filtrées dans un tableau:
tabFilter = rng.Offset(1, 0).SpecialCells(xlCellTypeVisible) 'Offset pour ne pas prendre la ligne d'en-tête
Nbreligne = UBound(tabFilter, 1)
NbreCol = UBound(tabFilter, 2)
[...]



Tout fonctionne parfaitement, mais à la condition que les données filtrées soient contigue...

Exemple ou cela fonctionne:

(les données se suivent ( 6 et 7 ) et la copie dans tabFilter est bonne)

Mais si par exemple on a des lignes filtrées entre les données:

(une ligne en 6, puis ligne en 8)
Alors je n'ai que la première partie qui est copiée dans mon tabFilter (uniquement la ligne 6, comme si suite à la présence d'une (ou des) ligne invisible, seul la première partie était "copié")

En résumé si on a des lignes masquées dans la plage de données filtrées, lors de la copie dans mon tableau, seul la première portion de données contigües sont copiées.


La solution que j'ai trouvé est de trier préalablement les données sur la colonne ou le filtre sera appliqué de tel sorte de n'avoir que des données filtrées qui se suivent.

Seulement je trouve cela vraiment curieux de ne pas pouvoir simplement mettre dans un tableau l'ensemble des données d'un filtre, alors qui si je devais simplement copier ces données dans une autres feuilles, là, il n'y aurait pas de problème que les données soient en un bloque ou pas.

Si un quelqu'un a une solution, car impossible de trouver la réponse sur le Web de se comportement étrange.

Merci

14 réponses

ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 15:46
Bonjour,
l'aide en ligne le précise ; vers tableau dynamique et vice-versa uniquement si plage dans solutions de continuité !
Il te faut donc nécessairement "changer ton fusil d'épaule"

____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
3
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 22:34
Minute !
Un bug trouvé ===>> rectif ===>>

Dim R As Range
  Set R = Sheets("feuil1").Range("A1:C8")
  ReDim tablo(1 To R.Rows.Count, 1 To R.Columns.Count)
  itablo = 1
  For i = 1 To R.Rows.Count
    If R.Rows(i).Hidden = False Then
      For j = 1 To R.Columns.Count
        tablo(itablo, j) = R.Cells(i, j).Value
      Next
      itablo = itablo + 1
    End If
  Next
  Sheets("feuil2").Range("F11:H18").Value = tablo

Et maintenant plus de bug ...
____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
3
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 23:46
Juste pour le plaisir (et je vais au dodo)
La dernière touche (la ultima).
Elle sert :
1) à ne pas dimensionner ton tableau au delà du nécessaire
2) à ne pas copier au delà du nécessaire
3) à faciliter la détermination de la plage de copie, en se contentant de dire à partir dez quelle cellule de la Feuille 2 (le reste se fait seul) :
 Dim R As Range
  Set R = Sheets("feuil11").Range("A1:C12")
  titi = R.SpecialCells(xlCellTypeVisible).Count \ R.Columns.Count
  ReDim tablo(1 To titi, 1 To R.Columns.Count)
  itablo = 1
  For i = 1 To R.Rows.Count
    If R.Rows(i).Hidden = False Then
      For j = 1 To R.Columns.Count
        tablo(itablo, j) = R.Cells(i, j).Value
      Next
      itablo = itablo + 1
      If itablo > titi Then Exit For
    End If
  Next
  Dim ou1 As Range, ou2 As Range
  Set ou1 = Sheets("feuil2").Range("F11") '<<<<<<==== c'est là que du dis où ============
  Set ou2 = Sheets("feuil2").Cells(ou1.Row + titi - 1, ou1.Column + R.Columns.Count - 1)
  Sheets("feuil12").Range(ou1.Address(False, False) & ":" & ou2.Address(False, False)).Value = tablo


Bonne nuit (tout est maintenant super complet)

____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
3
G0lg0th Messages postés 6 Date d'inscription jeudi 21 janvier 2010 Statut Membre Dernière intervention 6 février 2010
6 févr. 2010 à 16:22
Autant pour moi...

enfin si c'est comme ça, soit

Au moins je sais pourquoi. Merci.

j'ai toujours la solution du tri, on peut aussi penser à copier les cellules visibles dans une feuille temporaire avant de les mettre dans un tableau (vu qu'avec copier-coller en VBA, là ça fonctionne).

Ce qui est curieux c'est que après certains tests, il me semble qu'on est capable de parcourir les cellules visibles d'un range filtrer: je vais donc voir si je n'arrive pas à faire une fonction qui remplirait individuellement mon tableau sur base de mon range filtré...

Dommage qu'on ne puisse pas simplement faire une affectation directe du range filtré dans un variant
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 16:31
Ta solution est de :
- constituer une plage de tes cellules qui t'intéressent
- à partir de cette plage (par exemple pour chacune de ses lignes ... for each row...) :
----- alimenter un tableau dynamique à deux dimensions

Reste maintenant à savoir pourquoi (ce que tu comptes en faire) créer ce tableau dynamique. Si c'est pour alimenter une autre feuille ou alimenter un autre Range(continu, lui...) va bene ... sinon ... je vois mal la raison.
____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 16:35
Une autre solution est :
1) constituer une plage M des lignes masquées
2) de ne pas filtrer et envoyer tout le range R dans ton tableau
3) te servir de ton tableau
4) de masquer (voire de supprimer, si c'est ce que tu voulais) toutes les lignes qui se trouvent dans la plage M, au besoin par "décalage" par rapport à la différence entre le 1er rang de ton Range R et le premier rang d'utilisation.


____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 16:47
Si cette dernière solution est celle que tu retiens :
Faire une plage des cellules masquées est lent à l'aide d'une boucle for.
J'ai récemment fait une fonction allant beaucoup plus vite et m'apprêtais à en déposer un snippet, mais elle est restée chez moi car personne ne semblait intéressé (pas de réponse à une question que je posais quant à l'intérêt suscité).
Si tu en as le besoin, je dépose le snippet aujourd'hui même.


____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
0
G0lg0th Messages postés 6 Date d'inscription jeudi 21 janvier 2010 Statut Membre Dernière intervention 6 février 2010
6 févr. 2010 à 18:08
Si j'ai opté pour cette solution d'un tableau d'un range filtré, c'est car j'ai pas mal d'opération à faire pour tester le contenu.

Pour faire simple, j'ai des données qui représente des fils reliant différentes bornes de différentes armoires dans une feuilles.

Je dois regrouper ces fils en fonctions d'un paramètre x qui indique le nombre minimum de fils pour réaliser un regroupement pour en faire un câbles qui reliera les jonctions de et vers des mêmes armoires/bornes pour permettre de gagner du temps lors du câblage électrique des dites armoires... Seulement, il n'y a pas que des fils pouvant être regroupés, mais aussi des fils qui resterons isolés, des cavaliers, des fusibles, du blindage, etc.

en moyenne, il y a dans les 900 fils/cavaliers/fusibles/...

Tous ça serait plus simple dans une vraie base de données, mais bon, je dois faire ça dans Excel...

Donc mon but est de commencer par automatiser une série de filtre sur un simple critère, la borne de départ et la borne d'arrivée, je filtre donc en utilisant la fonction d'Excel, car je me suis dit que ce serai plus rapide. Et je boucle sur une centaine de filtre distinct pour par courir tous les couples de borne de départ/borne d'arrivée.

Chaque résultats de ces filtres sont mis dans un tableau, pour que dans ce tableau, je teste certaines valeurs pour décider de copier dans une feuille "fils à regrouper en câbles", "connexions" (c-à-d fils isolés, cavalier, fusible,... et enfin une feuille "Autres" pour tous les fils qui ne sont dans aucunes des 2 possibilités (par exemple des fils qui ne sont pas encore clairement identifié.)

Alors effectivement je n'ai peut-être pas choisi la solution la plus élégante?

Mais en triant avant les couples de bornes, alors la copie du range filtré fonctionne et ça marche très bien et c'est plutôt rapides (une dizaine de seconde, je trouve ça très satisfaisant, après tout, je n'ai pas des milliers lignes à traiter, si non, j'aurais tout mis dans Access :p )

Note : par curiosité j'ai testé ceci pour la copie dans le cas ou je ne trie pas (et donc où les données filtrées ne sont pas forcement contiguës) :

Set rng = ActiveSheet.AutoFilter.Range
Dim vtab() As String
Dim rC, rL As Range
Dim nbCol, nbLigne, ic, il As Integer
nbLigne = rng.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count - 2
nbCol = rng.Rows(1).SpecialCells(xlCellTypeVisible).Cells.Count - 1
ReDim vtab(nbLigne, nbCol)
il = 0
ic = 0
For Each rL In rng.Offset(1, 0).Resize(rng.Rows.Count - 1).Rows.SpecialCells(xlCellTypeVisible)
  If ic > 18 Then 'Pour passer d'une ligne à l'autre dans le tableau
    il = il + 1
    ic = 0
  End If
  vtab(il, ic) = rL.Value
  ic = ic + 1
Next rL



Je crois que c'est l'une des solutions dont tu parlais, même si mon code est ? pas très joli (je suis plutôt un débutant en VBA et je préfère faire simple du moment que ça fonctionne, question de temps).


Ce qui me déplait fortement dans mon code, c'est que je n'ai pas trouvé comment par courir "proprement" le rng filtré, c'est à dire avec 2 for each.

Du genre:
For Each ligne In rng.[????].[???]
For Each Cellule in Ligne
[là je met la cellule dans le tableau(iL,iC)]
[iC = iC + 1]
Next Cellule
[j'indique que je passe à une autre ligne de mon tableau(iL,iC) genre iL = iL + 1]
Next Ligne

Résultat, je joue avec un if then pour savoir quand je doit passer à une autre ligne de mon tableau... Enfin bon, ça fonctionne quand même



Je pense que je vais aller au plus simple et "pré-trier" la feuille pour avoir des données filtrées qui se suive.

Mais il faudra bien que je me mette à maîtriser la gestion des Ranges dans Excel, c'est le B à BA
0
G0lg0th Messages postés 6 Date d'inscription jeudi 21 janvier 2010 Statut Membre Dernière intervention 6 février 2010
6 févr. 2010 à 18:16
Petite correction de mon code:

If ic > 18 Then

If ic > nbCol Then



Coder dans son lit avec le portable un Samedi... c'est pas une bonne idée
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 18:26
Pas vraiment certain d'avoir compris ton problème ...
Serait-ce ceci (ezxemple) ?

Dim R As Range
Set R = Range("A1:C8")
For i = 1 To R.Rows.Count
  For j = 1 To R.Columns.Count
    MsgBox R.Cells(i, j)
  Next
Next


Je t'ai mis des msgbox (toi, si j'ai bien compris, tu alimentes ton tableau dynamique avec ces valeurs
Est-ce ce que cela répond à ta préoccupation ?

____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 18:41
Tiens ... je t'ai fait un petit exemple :
essaye-le sur un projet nouveau (avec des données dans la place A1:C8

Je pense que tu vas comprendre :

Dim R As Range
  Set R = Range("A1:C8")
  ReDim tablo(1 To R.Rows.Count, 1 To R.Columns.Count)
  '  on alimente tablo
  For i = 1 To R.Rows.Count
    For j = 1 To R.Columns.Count
      tablo(i, j) = R.Cells(i, j).Value
    Next
  Next
  ' on va se servir d e tablo et voir ...
  Range("F1:H8").Value = tablo



____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 févr. 2010 à 20:55
Je ne t'entends plus, ami...
Je me régalais pourtant avec la suite
Allez ! je t'invite à monter aux agrès avec moi (voilà pourtant près de 50 ans que je suis trop vieux pour y monter encore )

Ce que je t'ai montré jusqu'à présent n'était qu'une "ké"mia" préliminaire ...
Ton problème ? Tu as des lignes masquées du fait de ton filtrage, pardi ...
Et alors ?
Exercice numéro 2 :
sur un projet nouveau : 20 feuilles : Feuil1 net Feuil 2, les deux ouvertes.
Sur Feuil1 :
- des données dans la plage A1:C8
- 1 ou 25 lignes masquées dans la même plage
- un bouton de commande et ce code :

Private Sub CommandButton1_Click()
  Dim R As Range, i as integer, j as integer, itablo as integer
  Set R = Sheets("feuil11").Range("A1:C8")
  ReDim tablo(1 To R.Rows.Count, 1 To R.Columns.Count)
  i = 1
  itablo = 1
  For Each toto In R.Rows
    If toto(i).Hidden = False Then
      For j = 1 To R.Columns.Count
        tablo(itablo, j) = R.Cells(i, j).Value
      Next
      itablo = itablo + 1
    End If
     i = i + 1
     If i > R.Rows.Count Then Exit For
  Next
  Sheets("feuil12").Range("F11:H18").Value = tablo
End Sub

Tu lances, cliques sur le bouton ===>> va voir dans feuil2
Vu ?

___________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
0
G0lg0th Messages postés 6 Date d'inscription jeudi 21 janvier 2010 Statut Membre Dernière intervention 6 février 2010
6 févr. 2010 à 23:02
Je viens de tester le code avec les lignes 2 et 5 masquées, et il saute les lignes 2 et 3 ??? Là je capte pas car en debug je le vois bien sauter 2 et 3 car hidden =true alors que c'est 2 et 5... Est-ce compatible Excel 2000 (et oui au boulot, on est encore avec l'office 2000 )

Maintenant mon problème est plutôt dans la gestion d'un Range obtenu par
Set rng = ActiveSheet.AutoFilter.Range

après un filtre

et de manipuler ce range avec la propriété .SpecialCells(xlCellTypeVisible)
pour créer une "copie" des valeurs filtrées dans un tableau à 2 dimensions :

voilà le dernier code que j'ai testé et qui semble bien fonctionner:


[...]
[note: on a créé une plage filtrée en vba]
[...]
Dim tabFilter() As String
Dim rC, rL As Range
Dim nbLigne, nbCol, ic, il As Integer
Set rng = ActiveSheet.AutoFilter.Range
'On copie l'ensemble des données filtrées visibles dans un tableau:
'On calcul la taille du range des cellules visibles        
nbLigne = rng.Columns(1).SpecialCells(xlCellTypeVisible).Count - 1 '-1 car on ignorera la ligne d'entête des colonnes
nbCol = rng.Rows(1).SpecialCells(xlCellTypeVisible).Count
'On redimensionne le tableau pour être = au nbre de cellules visibles
ReDim tabFilter(1 To nbLigne, 1 To nbCol)
il = 1
'Pour chaque ligne dans la plage (range) filtrée des données visibles sans la ligne d'entête:
For Each rL In rng.Offset(1, 0).Resize(rng.Rows.Count - 1, 1).SpecialCells(xlCellTypeVisible).Rows 'Offset pour ignorer la première ligne qui est l'entête des colonnes
        'Pour chaque colonne de cette ligne
        For ic = 1 To nbCol
                tabFilter(il, ic) = rL.Columns(ic).Value
        Next ic
        il = il + 1
 Next rL
'on copie pour voir le résultat 
 Worksheets("Temp").Select 'Feuil pour tester la copie
 Worksheets("Temp").Cells.Clear 'on la vide
 Worksheets("Temp").Range(Cells(1, 1), Cells(nbLigne, nbCol)) = tabFilter




Moi, ça me semble plutôt correcte comme code, non?


Si non, maintenant je suis perturbé par ton dernier code et le résultat étrange que j'ai eu
0
G0lg0th Messages postés 6 Date d'inscription jeudi 21 janvier 2010 Statut Membre Dernière intervention 6 février 2010
6 févr. 2010 à 23:11
Ha! oui c'est mieux comme ça

Pendant que tu corrigeais ton code, j'écrivais mon message

J'avais pas vu le bug par contre, mais à cette heure, ça doit être la fatigue.

Merci
0
Rejoignez-nous