Import .xls vers une feuille et une seconde avec filtre

Salut à tous, grâce à votre aide je suis rendu avec un fichier excel qui permet de choisir un .xls, d'importer les données de la Feuil1 du classeur choisi (par une boîte de dialogue) et de les coller dans la Feuil2 du classeur où se trouve le bouton d'exécution.

Par la suite, j'ai rajouter des conditions de copie, pour filtrer les données. (condition : copier les lignes que si dans la colonne Q nous avons "PANNEAUX", "PLEXI" ou "STRAT"

Mon problème commence après, jusqu'ici tout marchait bien mais j'ai voulu créer dans le même principe, un copie/colle avec condition, vers une "Feuil3" et avec la condition "copier les lignes que si dans la colonne Q nous avons "MASSIF".

Excel ne semble pas aimer la copie de mon code ! Sa ne s'imbrique pas bien.

Cordialement

Bonjour,

En l'état actuel de ton code de ton code, il te suffisait d'ajouter une variable tablo3() et une autre pour l'incémenter, mettons m. Et doubler ta condition de constitution de tablo2 par l'introduction d'un ElseIf... pour tester la condition nouvelle et constituer le tablo3...

Inutile de doubler la procédure.

Cordialement.

NB- Il serait bon d'indenter correctement ton code...

Salut, bon alors je je ne maîtrise pas le code VBA mais je vais tenter de mettre en pratique tes conseils.

ajouter une variable tablo3() et une autre pour l'incémenter, mettons m

Dim tablo1, i&, tablo2(), n&, tablo3(), m&   't

doubler ta condition de constitution de tablo2 par l'introduction d'un ElseIf

Alors ici je bloque, le "Elself" n'est pas reconnue lorsque je le tape dans le code ? Je ne sais pas où le placer, et comment créer la boucle pour introduire le tablo3(), m

Sub Copie(x)

Dim nomUn, NewBook As Workbook
Dim tablo1, i&, tablo2(), n&, tablo3(), m&   't
Set nomUn = ThisWorkbook
   Set NewBook = Workbooks(x)
tablo1 = Sheets("Feuil1").Range("A1:Q" & Sheets("Feuil1").[A65536].End(xlUp).Row)
n = 0 'ajout initialisation explicite de n
For i = 1 To UBound(tablo1)
If tablo1(i, 17) Like "PANNEAUX" Or tablo1(i, 17) Like "PLEXI" Or tablo1(i, 17) Like "STRAT" Then
ReDim Preserve tablo2(17, n)
For j = 1 To 17 'ajout boucle
tablo2(j - 1, n) = tablo1(i, j) 'Modif pour incrémentation
Next j 'ajout boucle
n = n + 1
End If
Next i 'ajout i
If n Then
   nomUn.Activate
Sheets("Feuil2").[A1:Q65536].ClearContents
Sheets("Feuil2").[A1].Resize(n, 17) = Application.Transpose(tablo2)
End If

tablo1 = Sheets("Feuil1").Range("A1:Q" & Sheets("Feuil1").[A65536].End(xlUp).Row)
m = 0 'ajout initialisation explicite de n
For i = 1 To UBound(tablo1)
If tablo1(i, 17) Like "MASSIF" Then
ReDim Preserve tablo3(17, m)
For j = 1 To 17 'ajout boucle
tablo3(j - 1, m) = tablo1(i, j) 'Modif pour incrémentation
Next j 'ajout boucle
m = m + 1
End If
Next i 'ajout i
If m Then
   nomUn.Activate
Sheets("Feuil3").[A1:Q65536].ClearContents
Sheets("Feuil3").[A1].Resize(m, 17) = Application.Transpose(tablo3)
End If

   Application.CutCopyMode = False
   Cells(8, "S").Select
   NewBook.Close False

End Sub

J'ai essayer, sa ne colle rien en "Feuil3" mais pour autant, je n'ai pas de bug ?

Sinon "indenter" ton code, j'ai pas saisie le sens ?

Cordialement

Bon ! Si j'interviens sur ton code, je vais être tenté d'y apporter quelques modifications... Pas seulement en supprimer les Select résiduels et cet Application.CutCopyMode = False tout à fait incongru dans la mesure où ton code ne procède pas par copier-coller, et donc n'utilise nullement le presse-papier !

Je vais voir... @+

Merci pour ton aide alors.. et milles excuses pour ma maladresse !

Voilà déjà la première procédure, très peu modifiée... Je maintiens la dualité des procédures car cette façon en vaut largement bien d'autres et est susceptible d'offrir plus de souplesse pour introduire des modifications...

Sub SelectFichier()
    Dim QuelFichier, MonFichier As Workbook, x As String
    QuelFichier = Application.GetOpenFilename("Excel, *.xlsx")
    If QuelFichier <> False Then
        x = Workbooks.Open(QuelFichier).Name
        Copie x
    Else
        MsgBox "Vous n'avez pas sélectionné de fichier"
    End If
End Sub

NB- Ce code est indenté...

Sur le fond j'ai apporté deux petites modifications : ta seconde procédure attend qu'on l'appelle avec un argument qui n'est autre que le nom du fichier à traiter, que tu affectes à la variable x...

1) Inutile de mobiliser la fonction Dir pour cela, on récupère simplement le nom par la propriété Name du classeur, et on gagne une ligne et un peu de temps en le faisant simultanément à l'ouverture du classeur.

2) La 2e est d'avoir supprimé les parenthèses dans Copie x, ce qui mérite une explication.

De façon générale lorsqu'on appelle une procédure Function, les arguments sont mis entre parenthèses, si l'on veut récupérer les résultats renvoyés par la fonction. Mais lorsqu'on appelle une procédure Sub les arguments ne sont pas mis entre parenthèses, sauf cas particuliers...

Dans la ligne qui précède par exemple :

       x = Workbooks.Open(QuelFichier).Name

l'argument de la méthode Open est mis entre parenthèses, mais parce qu'elle est prolongée de façon à renvoyer le nom du fichier et que l'ensemble de l'expression se trouve à droite d'un signe =. Ce qui est une utilisation qui s'apparente formellement à l'utilisation d'une Function...

A l'inverse, tu te dispenses des parenthèses pour une fonction lorsque tu l'utilises en fait comme une Sub sans vouloir récupérer une valeur retournée par la fonction. Ce cas est fréquent avec MsgBox qui est une fonction mais est souvent utilisée pour simplement afficher un message sans rien attendre en retour.

Là on appelle directement la procédure Sub Copie pour qu'elle s'exécute. Si l'on l'appelait en utilisant Call, il faudrait mettre des parenthèses, mais sans Call, il ne faut pas en mettre.

Cependant cela ne déclenche pas d'erreur (note que s'il y avait plusieurs arguments, et que tu les mettes entre parenthèses, tu aurais une erreur !), mais pour un seul argument entre parenthèses pas d'erreur car elles ont une signification : forcer le passage de l'argument ByRef (par référence), ou autrement dit passer en fait par valeur (ByVal) un argument déclarée ByRef, mode de passage par défaut quand non précisé.

Ceci dit, les parenthèses t'éliminaient de ce fait involontairement une erreur ! En les supprimant, je rétablis l'erreur, car x est typée String, alors que le x, argument dans la déclaration de Copie n'est pas typé, donc Variant, et tu auras alors une erreur : Argument ByRef incompatible...

Mais nulle crainte, on va rectifier aussi la déclaration :

Sub Copie(x As String)

qui rétablira l'équilibre.

Je vais m'y attaquer mais après avoir grignoté un peu ! @+

Salut, bon alors avant de lire ton message, je me suis dit "merde, je vais jamais rien comprendre" mais après 2/3 lectures j'ai plutôt bien saisie la méthode ou du moins l'idée, merci d'avoir prit la peine d'expliquer.

Par ailleurs, l'adjectif "indenté" me parait plus clair.. c'est comme concaténé et synthétisé à la fois quoi !

Cordialement

Voilà la suite :

Sub Copie(x As String)
    Dim NewBook As Workbook, tablo1, i&, tablo2(), tablo3(), n&, m&
    Set NewBook = Workbooks(x)
    tablo1 = NewBook.Sheets("Feuil1").Range("A1").CurrentRegion
    For i = 1 To UBound(tablo1)
        Select Case tablo(i, 17)
            Case "PANNEAUX", "PLEXI", "STRAT"
                ReDim Preserve tablo2(n)
                tablo2(n) = WorksheetFunction.Index(tablo1, i, 0)
                n = n + 1
            Case "MASSIF"
                ReDim Preserve tablo3(m)
                tablo3(m) = WorksheetFunction.Index(tablo1, i, 0)
                m = m + 1
        End Select
    Next i
    With ThisWorkbook.Sheets("Feuil2").Range("A1")
        .CurrentRegion.ClearContents
        If n > 0 Then .Resize(n, 17).Value = WorksheetFunction.Transpose( _
         WorksheetFunction.Transpose(tablo2))
    End With
    With ThisWorkbook.Sheets("Feuil3").Range("A1")
        .CurrentRegion.ClearContents
        If m > 0 Then .Resize(m, 17).Value = WorksheetFunction.Transpose( _
         WorksheetFunction.Transpose(tablo3))
    End With
    NewBook.Close False
End Sub

L'indentation consiste à opérer un retrait initial par rapport à la déclaration de procédure, qui ne laissera sur le même alignement que les étiquettes de branchement lorsqu'il y en a, et ensuite des retraits successifs pour le code inclus dans une instruction composée (type : If... End If, For... Next, With... End With, etc.)? Cela permet de voir immédiatement (ou presque ! ) lorsqu'un élément de ce type d'instructions est oublié, en suivant des yeux les alignements verticaux, et facilite l'interprétation du code à la lecture.

J'ai donc rajouté les variables tablo3() et m dont il était question, supprimé au passage nomUn, car ThisWorkbook est une propriété de l'objet Application qui, n'importe où dans le code renverra le classeur dans lequel se trouve le code. Elle joue donc pratiquement le même rôle qu'une variable, et il est inutile de la doubler en l'affectant à une nouvelle variable.

J'ai de même supprimé l'initialisation de n à 0. Dès sa déclaration, une variable acquiert une valeur par défaut en fonction de son type, et une variable numérique vaudra 0 (de même qu'une variable String aura la valeur "", une Variant la valeur Empty (vide) et une variable booléenne la valeur False). Donc l'initialiser à 0 est lui donner la valeur qu'elle a déjà. Inutile.

Pour la suite, la modification est un peu plus conséquente. Entendons-nous bien la méthode utilisée était tout à fait correcte et donnait le résultat attendu :

En testant une ligne (col. Q) de la base mise en tableau, si test positif, on incrémentait un tablo2 à 2 dimensions en préservant les valeurs déjà affectées au tableau et on servait en utilisant une boucle chaque élément de tableau correspondant à une cellule de la ligne à prélever...

On va légèrement changer la méthode pour s'éviter cette boucle et gagner un peu de temps.

La mise en tableau (tablo1) est maintenu comme dans ta procédure initiale. J'ai utilisé CurrentRegion (au lieu de End(xlUp) pour le dimensionner) car plus simple et rapide quand on peut l'utiliser, ce qui m'a semblé faisable avec des tableaux occupant des feuilles...

Si une difficulté survenait à cet égard, me le faire savoir...

On teste donc ce tableau comme précédemment, et comme on va en constituer un second, j'ai modifié l'instruction conditionnelle If... ElseIf... End If en une instruction Select Case, au sein de laquelle on aura 2 cas à considérer : Case "PANNEAUX", "PLEXI", "STRAT" pour lequel on remplit tablo2 avec la ligne, et Case "MASSIF" pour lequel on remplit tablo3. On procèdera de la même façon pour chacun des tableaux.

La différence essentielle intervient ici : au lieu d'avoir des tablo2 et tablo3 à 2 dimensions, on va se contenter d'une part de tableaux à 1 dimension, plus rapides à servir, l'élément unitaire du tableau est donc une ligne, et on lui affecte la ligne entière qu'on doit prélever. Ainsi au lieu d'avoir un tableau de x lignes dont chaque ligne comporte 17 éléments, on aura un tableau de x éléments correspondant à x lignes, mais chaque élément sera la ligne entière, soit un tableau de 17 éléments (qu'on n'aura pas passé en revue pour les affecter un par un puisqu'on aura affecté la ligne).

Lors de l'affectation, les tableaux n'étant pas construit pareil, l'affectation sera un peu différente.

Auparavant on dimensionnait la plage à servir puis on affectait le tableau en le transposant (du fait qu'il s'agissait d'un tableau(colonnes, lignes) pour pouvoir incrémenter les lignes) pour le remettre d'aplomb.

Dans le nouveau cas, on a un tableau à 1 dimension (donc horizontal) qu'il faudra également transposer, mais son contenu est constitué de tableaux eux-mêmes à une dimension...

D'où après dimensionnement de la plage à servir (qui se fait de la même façon), on affecte le tableau en lui appliquant une double transposition qui le rétablira dans le bon sens. (C'est plus difficile à imaginer mais cela fonctionne très bien, et peut faire gagner du temps).

Cordialement.

Salut, alors j'ai rapidement lu tes explications dans un premier temps (il me tardait d'utiliser ton fichier), j'ai du juste corriger un "tablo" par "tablo1".

Je vais à présent lire tranquillement ton message, en tout cas merci pour ton aide.

Le code à diminuer de moitié, et on voit tout de suite comment l'adapter.

Cordialement

EDIT : Bon à croire que je deviens fou, mais l'erreur est revenue, au même endroit :

Select Case tablo(i, 17)

"L'indice n'appartient pas à la sélection"

Ah ! Mes excuses ! C'est tablo1 comme tu disais !

A croire que c'est moi qui est parler trop vite, j'ai la même erreur finalement.

Alors ça à marcher une fois, puis pas la deuxième

180930072531300394

Retape toujours le 1 pour t'assurer que c'est bien un 1 et pas l (L minuscule).

C'était bien 1, en fait c'est que j'avais modifier le fichier que j'importais, j'avais décaler la case 17, soit Q vers une autre colonne.

Du coup il ne comprenais pas, ce qui est normal !

Autant pour moi..

En effet, et l'erreur est la même !

Pas grave, ça arrive fréquemment de chercher une erreur partout alors qu'on a le nez dessus !

Bonsoir,

C'est encore moi, désolé, mais un petit soucis, lors de l'importation, que j'ai changer en R10 (au lieu de A1 de la Feuil2 et Feuil3), le code efface les valeurs dans les lignes au dessus. Le problème, c'est que ce sont mes désignations de colonnes..

EDIT :

Et le second problème, c'est qu'on copie les colonnes 1 à 17, on filtre la 17 mais on ne copie/colle pas les valeurs en colonne 18, 19 et 20 par exemple. (il est vrai que j'avais jamais préciser. )

Il suffisait, de changer le code (n, 20)

If n > 0 Then .Resize(n, 20).Value = WorksheetFunction.Transpose( _

Du moins, sa semble marcher !

Cordialement

Avec un prélèvement tableau (tablo1) basé sur CurrentRegion, les colonnes supplémentaires étaient automatiquement intégrées. De même la récupération de lignes entières dans tablo2 et tablo3 n'a pas besoin de se préoccuper du nombre de colonnes.

Le seul point restant non ajusté était le 17 lors du dimensionnement de la plage cible. Remplacer par 20 règle le problème s'il y a 20 colonnes.

Mais remplace-le par UBound(tablo1, 2), cela s'ajustera à la dimension des données prélevées si le nombre de colonnes varie encore.

Dans ce que j'avais vu jusqu'ici, et dans le code précédent, tu ne semblais pas avoir de ligne d'en-tête...

Si tu en as une, il faut savoir si elle présente dans le tableau source : si c'est le cas, elle peut-être récupérée systématiquement avec les lignes répondant aux tests.

Me l'indiquer, et confirmer que la plage source commence en A1.

Reste la configuration des feuilles cibles : si l'insertion se fait à partir d'une autre ligne que la 1, il faut indiquer laquelle et savoir exactement ce qu'il y a au-dessus de la ligne d'insertion pour maîtriser la plage renvoyée par CurrentRegion et ajuster son positionnement pour l'effacement préalable.

Cordialement.

Avec un prélèvement tableau (tablo1) basé sur CurrentRegion, les colonnes supplémentaires étaient automatiquement intégrées. De même la récupération de lignes entières dans tablo2 et tablo3 n'a pas besoin de se préoccuper du nombre de colonnes.

Le seul point restant non ajusté était le 17 lors du dimensionnement de la plage cible. Remplacer par 20 règle le problème s'il y a 20 colonnes.

Mais remplace-le par UBound(tablo1, 2), cela s'ajustera à la dimension des données prélevées si le nombre de colonnes varie encore.

Ok, je test ça ce soir, il me semblait que si je ne changais pas le 17 dans le tablo2 et tablo3, il ne me copiais/collais la ligne que jusqu'a la colonne 17.

Dans ce que j'avais vu jusqu'ici, et dans le code précédent, tu ne semblais pas avoir de ligne d'en-tête...

Si tu en as une, il faut savoir si elle présente dans le tableau source : si c'est le cas, elle peut-être récupérée systématiquement avec les lignes répondant aux tests.

Me l'indiquer, et confirmer que la plage source commence en A1.

Reste la configuration des feuilles cibles : si l'insertion se fait à partir d'une autre ligne que la 1, il faut indiquer laquelle et savoir exactement ce qu'il y a au-dessus de la ligne d'insertion pour maîtriser la plage renvoyée par CurrentRegion et ajuster son positionnement pour l'effacement préalable.

Cordialement.

En effet je voulais l'adapter après, mais je n'y arrive pas.

Il faudrait copier les données de la Feuil1 à partir de A2 (les entêtes sont dans la ligne 1).

Du coup pour la copie dans la Feuil2 et Feuil3 se ferait en R10, sans supprimer le contenue les lignes 1, 2, 3, 4 , 5, 6, 7, 8 et 9. (les entêtes sont dans la ligne 9, mais dans les lignes 1 à 8 j'ai autre choses)

En te remerciant, une nouvelle fois..

Cordialement

Tu as eu raison de changer le 17 en 20 pour le dimensionnement des plages accueillant les tablo2 et tablo3.

Et en remplaçant 20 par un élément variable (UBound(tablo1, 2)) qui renvoie le nombre de colonne de la plage source, cet ajustement deviendra automatique.

Je n'ai posé la question de la ligne d'en-tête de la source que pour savoir si tu souhaitais qu'on la prenne en compte d'office avec les lignes à transférer. Mais si tu souhaites mettre toi-même les lignes d'en-tête sur les feuilles cibles, je les laisserai de côté. C'est toi qui décide.

Pour les effacements, il faut que je sache quelle est la plage que me renverra CurrentRegion à partir de A10 (ou A9 selon choix précédent). Soit si la plage couvre toutes les lignes à partir de 1 ou non (ce serait le cas si une ligne entièrement vierge est intercalée, mais s'il y en a une il serait anormal que ce ne soit pas la ligne 8...)

Je prévois donc d'opérer un décalage de 9 lignes lors de l'effacement, mais il serait bon de confirmer qu'il n'y a pas de vide qui fractionnerait alors la plage.

Cordialement.

Tu as eu raison de changer le 17 en 20 pour le dimensionnement des plages accueillant les tablo2 et tablo3.

Et en remplaçant 20 par un élément variable (UBound(tablo1, 2)) qui renvoie le nombre de colonne de la plage source, cet ajustement deviendra automatique.

Il semble que ça marche, j'ai placer la ligne ici :

For i = 1 To (UBound(tablo1, 2))

Je n'ai posé la question de la ligne d'en-tête de la source que pour savoir si tu souhaitais qu'on la prenne en compte d'office avec les lignes à transférer. Mais si tu souhaites mettre toi-même les lignes d'en-tête sur les feuilles cibles, je les laisserai de côté. C'est toi qui décide.

Oui je préfère, c'est un repère même si les entêtes sont finalement identiques entre les données copiées et collées.

Pour les effacements, il faut que je sache quelle est la plage que me renverra CurrentRegion à partir de A10 (ou A9 selon choix précédent). Soit si la plage couvre toutes les lignes à partir de 1 ou non (ce serait le cas si une ligne entièrement vierge est intercalée, mais s'il y en a une il serait anormal que ce ne soit pas la ligne 8...)

Je prévois donc d'opérer un décalage de 9 lignes lors de l'effacement, mais il serait bon de confirmer qu'il n'y a pas de vide qui fractionnerait alors la plage.

Cordialement.

Alors il faudrait copier, à partir de A2, les colonnes A à AB (pour la Feuil1, où mes données sont), pour les copier dans l'autre classeur en R10, de R à AS (idem que ce soit la Feuil2 ou Feuil3).

Cordialement

Tu n'as pas bien compris ! Ne modifie pas cette ligne :

    For i = 1 To UBound(tablo1)

La macro ne va plus traiter les lignes si tu y touches c'est l'indice max lignes qui est indiqué ici, UBound(tablo1, 1) [le 1 est optionnel], mais UBound(tablo1, 2) est l'indice max colonnes.

[et n'ajoute pas de parenthèses inutiles, ça finit par jouer des tours...]

En fait, pour éviter la ligne de titres, il faut faire :

    For i = 2 To UBound(tablo1)

Les modifications doivent remplacer les 20 avec lesquels tu as remplacé les 17 antérieurs :

        If n > 0 Then .Resize(n, UBound(tablo1, 2)).Value = WorksheetFunction.Transpose( _
         WorksheetFunction.Transpose(tablo2))

et :

        If m > 0 Then .Resize(m, UBound(tablo1, 2)).Value = WorksheetFunction.Transpose( _
         WorksheetFunction.Transpose(tablo3))

Pour Feuil2 et 3, si R10, avec ligne 9 en ligne d'en-tête, la meilleure situation serait que la ligne 8 soit vide et la colonne Q vide (à partir de la ligne 8), ce qui rendrait la plage cible délimitable de façon autonome.

Sinon il faut m'indiquer avec précision la plage renvoyée par [R10].CurrentRegion sur ces deux feuilles, et que cela ne soit plus modifié. de façon à pouvoir opérer les décalages nécessaires.

[Ou bien, puisque tu prédéfinis la ligne d'en-tête, constituer avec cette ligne des tableaux Excel dans lequel mettre les données prélevées, et me communiquer les noms des tableaux.]

Cordialement.

Rechercher des sujets similaires à "import xls feuille seconde filtre"