Se connecter avec
S'enregistrer | Connectez-vous

VBA : Info pour une lecture de feuille ligne par ligne

Dernière réponse : dans Programmation

Tout d'abord Bonjour le forum .


Je débute en VBA et je peine beaucoup sur une partie de mon code .

J'aimerais pouvoir avancer case par case dans le sens de la ligne et qu'a chaque mot rencontré ( et seulement les mots ) je puisse les copier-coller un a un , dans une unique colonne dans une autre feuille , et ainsi de suite jusqu'a la fin de la feuille .

Actuellement j'ai ceci :

  1. Sub CopierColler
  2.  
  3. For i = 1 To 54550
  4.  
  5. If Application.Worksheets("Production Data").Cells(1, i) = vbString Then
  6. Application.Worksheets("TabTraduction").Range("A1" & ":A" & i).Value = Application.Worksheets("Production Data").Cells(1 , i).Value
  7.  
  8. End If
  9.  
  10. Next i
  11.  
  12. End Sub


Dans mon code actuel , je vois bien sûr de nombreux problèmes , tout d'abord le "Cells" ne semble pas accepter par mon application.ws , le problème c'est que je ne sais pas comment lire ligne par ligne avec un Range .
De plus , je ne sais pas comment faire pour aller a la ligne suivante .
Pour finir , mon code me retourne toujours la même valeur en boucle dans ma colonne :pfff:  .

Si quelq'un a un peu de temps pour m'aiguiller ou me proposer un code , je lui serait très reconnaissant car je ne voit vraiment pas du tout comment faire et cela fait des jours que je bloque dessus .


Désolé pour le pavé .

NoirCafe , débutant déspéré :( 
Lassé par la pub ? Créez un compte

Meilleure solution

Expert Programmation

Set TB_row = Worksheets("TabTraduction" ).Columns(2).
Non mais ça va pas :o 

---------------

  1. Set PD_zone = PB.Range(PB.Rows(2), PB.Rows(250))
Citation :
Tout n'est pas selectionné dans ma feuille

Ben je fais exprès de considérer les lignes de 2 à 250. Ce n'est qu'un exemple.

Tu peux considérer :
  1. '// 1 seule cellule
  2. Set PD_cellB250 = PB.Cells(250, 2)
  3. Set PD_cellB250 = PB.Range("B250")
  4. Set PD_cellB250 = PB.[B250]
  5.  
  6. '// 1 seule ligne :
  7. Set PD_ligne2 = PB.Rows(2)
  8.  
  9. '// Toutes les cellules entre deux bornes :
  10. Set PD_lignes2a250 = PB.Range(PB.Cells(2, 2), PB.Rows(4, 250))
  11.  
  12. '// Toutes les lignes entre deux bornes :
  13. Set PD_lignes2a250 = PB.Range(PB.Rows(2), PB.Rows(250))
  14.  
  15. ' // Plusieurs zone en particulier
  16. Set PD_lignes2et250 = Union(PB.Cells(2, 2), PB.Rows(250))
  17.  
  18. ' // Les cellules qui appartiennent à plusieurs zones à la fois
  19. Set PD_cellB250 = Intersect(PB.Columns(2), PB.Rows(250))
  20.  
  21. ' // Toutes les cellules
  22. Set PD_tout = PB.Cells

Amuse-toi, avec un MsgBox PB_xxx.Address() pour voir le résultat :) 

---------------

  1. PD_row.Copy destination
Toute la ligne va être copiée. Et une ligne, c'est plusieurs cellules. Donc la destination doit en contenir plusieurs. D'où la nécessité de réviser ta demande.
Avant de vouloir le programmer, exprime-toi en français, simple et simplement. (parce que sinon, moi, je ne comprends pas).

Etudie ça :
  1. Dim ws_source As Worksheet
  2. Dim plg_source As Range
  3. Dim row_source As Range
  4. Dim cel_source As Range
  5. Dim cel_target As Range
  6. Dim passer_a_ligne As Boolean
  7.  
  8. '// Plage source des données 2:250
  9. Set ws_source = Worksheets("PD")
  10. Set plg_source = ws_source.Range(ws_source.Rows(2), ws_source.Rows(250))
  11.  
  12. '// Première cellule cible
  13. Set cel_target = Worksheets("TB").Cells(2, 1)
  14.  
  15. For Each row_source In plg_source.Rows
  16. For Each cel_source In row_source.Cells
  17. passer_a_ligne = False
  18. If Not IsNull(cel_source.Text) And Not IsNumeric(cel_source.Value) Then
  19. ' // Au moins une cellule a été copiée, il faudra passer une ligne
  20. passer_a_ligne = True
  21.  
  22. cel_target.Value = cel_source.Text
  23. Set cel_target = cel_target.Offset(0, 1)
  24. End If
  25. If passer_a_ligne Then
  26. ' // Bien regarder ça :^)
  27. Set cel_target = cel_target.Offset(1).EntireRow.Cells(1)
  28. Next
  29. Next
Expert Programmation

Salut,

T'es bien tombé :)  Vais m'occuper de toi, moi... :D 

Tu vas apprendre à indenter ton code. Ce n'est pas un conseil, c'est une exhortation. Ceci permettra à ton code d'être lisible et donc lu. Condition importante si tu cherches de l'aide. (En plus, ça te dispensera de mettre des noms de variables derrière tes Nexts, pratique ancestrale - ~1985 - mais dépréciée depuis 1991)

Seconde bonne pratique - et condition sine qua none pour que j'accepte de t'aider, c'est d'utiliser l'Option Explicit (RTFM!) et de déclarer tes variables.

Worksheets, c'est la collection des feuilles. Elles n'appartiennent pas à Excel (Application) mais à un classeur (Workbook). En général, on aime bien travailler sur le classeur dans lequel le code est écrit. Dans ce cas, on utilise ThisWorkbook. Dans de nombreux cas, il n'est pas indispensable de préciser le classeur, bien que je m'oppose à ce genre de considération.

Une cellule, c'est un objet qui contient des tas de choses. Une valeur, un texte, une apparence, etc. Alors, merci d'être précis. Parce que sinon, Excel va décider pour toi. Par exemple, pour une cellule, c'est la méthode .Text en général. Et donc Cells(1, i).Text = vbString n'a aucun sens. En passant, tu vas me consulter l'aide de vbString et constater qu'il te manque des choses.

----------------------------

Worksheets, ce sont les feuilles.
Worksheets(x), c'est la feuille x.
Worksheets(x).Cells, ce sont les cellules de la feuille x.

Mais on peut aussi considérer les lignes ou les colonnes :
Worksheets(x).Rows, ce sont les lignes de la feuille x.
Worksheets(x).Columns, ce sont les colonnes de la feuille x.

Facile !

Voici deux codes légèrement différents pour parcourir les lignes d'une feuille :
  1. ' // CTRL+Pause pour arrêter, parce que ça va être long, surtout vers la fin !
  2. Dim lig_num As Long
  3. For lig_num = 1 To Worksheets(1).Rows.Count
  4. MsgBox "Ligne n°" & lig_num
  5. Next
  1. ' // CTRL+Pause pour arrêter, parce que ça va être long, surtout vers la fin !
  2. Dim lig As Range ' // Lire explications plus loin
  3. For Each lig In Worksheets(1).Rows
  4. MsgBox "Ligne n°" & lig.Row
  5. Next


Une ligne ou une colonne est un ensemble de cellules. Mais on pourrait considérer n'importe quelle zone de cellules.
Soit donc plage, un ensemble de cellules :
  1. Dim plage As Range

Pour parcourir ses cellules, ou utilise Cells():
  1. Dim lig_n As Long, col_n As Long
  2. For lig_n = 1 To Plage.Rows.Count
  3. For col_n = 1 To Plage.Columns.Count
  4. MsgBox "Cellule " & lig_n & "x" & col_n
  5. Next
  1. Dim cel As Range
  2. For Each cel In Plage.Cells
  3. MsgBox "Cellule " & cel.Row & "x" & cel.Column & vbCrLf & "On peut aussi écrire ça comme ça : " & cel.Address
  4. Next


T'as tout compris ?
  • Non ? Relis tout depuis le début.
  • Oui ? On continue...

    Maintenant, on mélange tout :
    1. Dim ligne As Range
    2. Dim cellule As Range
    3.  
    4. For Each ligne In Rows ' // Attention, je te précise ni le classeur, ni la feuille,
    5. For Each cellule In ligne
    6. Next
    7. Next


    ----------------------------

    J'ai conscience que je n'ai pas résolu ton problème, mais on va y aller doucement.
    Ingurgite d'abord tout ça et revois ton programme.
    Alors ?

    Bonjour Zeb, Bonjour le Forum.

    Il m'a fallu un peu de temps pour "ingurgiter" comme tu dis ce que tu m'as appris hier ( encore merci ) et je vais dejà essayer de l'appliquer .
    Je ne sais pas si tu as lu mon message , mais j'ai plancher dessus hier soir , mon code ne fonctionne toujours pas mais il a un peu évolué .

    Le voici :

    1. Option Explicit ' Je ne pense plus m'en passer maintenant que j'en ai compris l'utilité
    2.  
    3. Private Sub BtnCopierColler ()
    4.  
    5. Dim iPD As Long
    6. Dim iTB As Long
    7. Dim PD As Worksheet
    8. Dim TB As Worksheet
    9.  
    10. Set PD = Worksheets("Production Data") 'Feuille où je veut copier
    11. Set TB = Worksheets("TabTraduction") 'Feuille où je veut coller
    12.  
    13. iTB = 2
    14. For iPD = 2 To 250
    15. If PD.Cells(2, iPD).Text Then
    16. PD.Range(iPD & ":" & iPD).Copy TB.Cells(iTB, 1)
    17. iTB = iTB + 1
    18. End If
    19. Next
    20.  
    21.  
    22. End Sub



    J'ai une joli " Erreur d'execution 13, incompatibilité de type " , un numero de colonne contrairement a un numero de ligne n'est un pas de type Long ?
    Dommage qu'il y ait une erreur car j'ai un doute sur le fonctionnement du code , principalement si le " .text" suffirait a ne pas copier les chiffres de mes feuilles ( c'est pour cela que je ne veut que les mots uniquement composés de lettres .)

    Y a du mieux ? ( J'ai comme un mauvais pressentiment , patapay :whistle:  )



    Edit :

    J'ai plus de message d'erreur desormais avec ce code , mais il ne fonctionne toujours pas :heink:  .

    J'ai remplacé cette ligne " If PD.Cells(2, iPD).Text Then " par
    1. If PD.Cells(2, iPD).Text Like "[a-z]" Then





    NoirCafe

    ps : Comment indenter mon code ? ( = 1ere ligne , 1G = G a la fin ? :ouch:  )
    Expert Programmation

    Salut,

    Je ne comprends ta question sur l'indentation. Ta présentation est parfaire.
    Tiens, un bon point avec ruban :


    Le type Long est nécessaire aux lignes (>32 767), et convient aussi aux colonnes : qui peut le plus peut le moins.

    1. PD.Range(iPD & ":" & iPD)
    C'est pour référencer la ligne iPD ? Alors il y a plus logique !
    1. PD.Rows(iPD)


    Mets le curseur sur .Text et appuie sur [F1]. Lis tout le baratin.
    Cette méthode de l'objet Range renvoie le contenu texte et non pas oui ou non en fonction de la nature "textuelle" du contenu.

    A la ligne 15, la condition du If .. Then doit être un booléen. Toi, tu y mets du texte, d'où l'incompatibilité de type.

    Il faudrait que la méthode IsTextOnly existe. Ce n'est pas le cas. On pourrait créer une fonction :
    1. Function IsTextOnly(ByVal texte As String) As Boolean
    2. ' // Code pour analyser le contenu de la variable texte
    3.  
    4. End Sub
    1. ...
    2. If IsTextOnly(PD.Cells(2, iPD).Text) Then ...
    3. ...


    Sinon, on peut raisonner autrement. Tu dis vouloir considérer les cellules qui ne contiennent que du texte.
    Moi, je dis qu'on peut considérer les cellules non vides, quine sont pas des nombres !
    Le test devient :
    1. If Not IsNull(PD.Cells(2, iPD).Text) And Not IsNumeric(PD.Cells(2, iPD).Value) Then


    Sauf que je retiens par exemple les mots a123 123a 12z34 dont tu ne peux peut être pas.

    Ah d'accord , grosse incomprehension sur le ".text" , mea culpa ^^ .

    Bon bah j'ai pris ton code , en effet pour référencer , c'est plus clean .
    1. PD.Rows(iPD)


    J'ai pris aussi ton code pour les conditions en compte car il me convient parfaitement , en effet je n'ai pas de cas de mots du style "a1az3" .

    Mon code devient donc :

    1. Private Sub CopierColler
    2.  
    3. Dim iPD As Long
    4. Dim iTB As Long
    5. Dim PD As Worksheet
    6. Dim TB As Worksheet
    7.  
    8. Set PD = Worksheets("Production Data") 'Feuille ou je veut copier
    9. Set TB = Worksheets("TabTraduction") 'Feuille où je veut coller
    10.  
    11. iTB = 2
    12. For iPD = 2 To 250
    13.  
    14. If Not IsNull(PD.Cells(2, iPD).Text) And Not IsNumeric(PD.Cells(2, iPD).Value) Then ' Conditions a respecter
    15.  
    16. PD.Rows(iPD).Copy TB.Cells(iTB, 1)
    17.  
    18. iTB = iTB + 1
    19.  
    20. End If
    21. Next
    22.  
    23. End Sub


    Le code est bon mais il ne se passe rien , en fait je soupçonne les chinois que le code ne traite pas toute la feuille et ne selectionne rien et donc n'ai rien a copier .
    Mais je ne vois pas du tout ou je me suis planté :heink:  .

    J'ai pas envie d'abuser en faisant mon assisté de service non plus , donc si tu en as marre , n'hésite pas a me le dire , je comprendrais .

    Je continue de chercher ,


    NoirCafé


    EDIT :

    Bon je sais pourquoi ça ne marche pas , mon code ne retourne pas à la ligne , or la premiere ligne ( ici 2 ) est vide .
    1. If Not IsNull(PD.Cells(2,iPD).Text) And Not IsNumeric(PD.Cells(2,iPD).Value) Then


    J'ai mis 5 a la place et j'ai eu des mots a s'afficher mais plusieurs problemes aparaissent , le code copie colle tout , même mes chiffres et mes bordures de tableau et de plus ils ne se cantonnent pas en une colonne dans "TabTraduction" mais sur toute la feuille .
    Je ne comprend pas pourquoi , même les conditions ne sont pas respectées ...
    Je continue de chercher et en priorité pour retourner a la ligne .
    Expert Programmation

    Je ne te lâcherai pas tant que tu n'auras pas une solution. Et en plus, quand tu en auras une, je continuerai à faire mon pénible, jusqu'à l'obtention d'une solution optimale (*) et élégante (*).

    Bon, si ça ne fait pas ce que tu veux, il faut déboguer.
    Lis ça : http://www.presence-pc.com/forum/ppc/Programmation/tuto...

    Juste pour le plaisir, je réécris ton code avec des objets, plutôt qu'avec des indices de lignes et de colonnes. Je trouve ça tellement plus simple à expliquer !
    1. Dim PD As Worksheet
    2. Dim PD_zone As Range
    3. Dim PD_row As Range
    4. Dim TB_row As Range
    5.  
    6. '// Feuille ou tu veux copier
    7. Set PD = Worksheets("Production Data")
    8. ' // Zone de cette feuille que tu veux copier
    9. Set PD_zone = PB.Range(PB.Rows(2), PB.Rows(250))
    10.  
    11. '// Ligne où tu veut coller
    12. Set TB_row = Worksheets("TabTraduction").Rows(2)
    13.  
    14. For Each PD_row In PB_zone.Rows
    15. If Not IsNull(PD_row.Cells(2).Text) And _
    16. Not IsNumeric(PD_row.Cells(2).Value) _
    17. Then
    18. ' // Copie une ligne complète dans ... une ligne
    19. PD_row.Copy TB_row
    20. ' // La prochaine dans la ligne suivante
    21. Set TB_row = TB_row.Offset(1)
    22. End If
    23. Next


    ___________________
    (*) Ce qui viole la règle du pire c'est mieux. :o 

    Tu peut faire ton pénible , plus mon code sera propre , plus j'en serait heureux , je suis en aprentissage , les bonnes habitudes je dois les acquerirent maintenant .

    Je pense me baser sur ce code , il est effectivement plus simple .

    Il y a 3 problèmes :

    - Tout n'est pas selectionné dans ma feuille , j'ai beau régler les lignes , les mots du haut de ma feuille n'aparaissent pas .

    -Le copier-Coller affiche aussi mon tableau ( ou sont contenus mots et chiffres ), je ne sais même pas si il existe une condition pour empecher celà :??: 

    -Enfin et ce n'est pas un problème a proprement parler , puisque ici le code est bon , j'aimerais que mes mots ne soit pas collé dans une ligne mais dans une seule colonne , chaque mots étant placé dans une cellule de cette colonne .
    J'ai donc remplacé
    1. Set TB_row = Worksheets("TabTraduction").Rows(2)

    par
    1. Set TB_row = Worksheets("TabTraduction").Columns(2)


    mais j'ai un message d'erreur qui m'indique que ma colonne n'ai pas assez large , je dois splitter ( il me semble que c'est le terme ) ma ligne avant de la coller peut-être ?

    Je regarde pour le debogage et le reste

    NoirCafé

    Désolé , j'avais pas été forcement été très clair dans mon explication .

    J'ai un message d'erreur "Impossible de lire la propriété texte de la classe Range " lié aparemment a tout les "cel_source.Text"

    Ici
    1. If Not IsNull(cel_source.Text) And Not IsNumeric(cel_source.Value) Then


    et ici
    1. cel_target.Value = cel_source.Text



    Ah et sinon , la ligne :
    1. Set cel_target = cel_target.Offset(1).EntireRow.Cells(1)


    Je l'ai compris comme servant a "casser" la ligne en une unique cellule mais j'ai un doute , c'est bien ça ?

    Et pour finir , et là j'ai peur de passer pour un idiot mais bon :
    Cette ligne , ci dessous , signifie bien qu'elle va "lire" dans la feuille , une zone comprise entre la ligne 2 a 250 ?
    1. Set plg_source = ws_source.Range(ws_source.Rows(2), ws_source.Rows(250))


    Beaucoup de questions désolé .
    NoirCafé
    Expert Programmation

    noircafe a dit :
    Désolé , j'avais pas été forcement été très clair dans mon explication .

    J'ai un message d'erreur "Impossible de lire la propriété texte de la classe Range " lié aparemment a tout les "cel_source.Text"

    Ici
    1. If Not IsNull(cel_source.Text) And Not IsNumeric(cel_source.Value) Then


    et ici
    1. cel_target.Value = cel_source.Text


    Option Explicit [:zeb:4]
    noircafe a dit :


    Ah et sinon , la ligne :
    1. Set cel_target = cel_target.Offset(1).EntireRow.Cells(1)


    Je l'ai compris comme servant a "casser" la ligne en une unique cellule mais j'ai un doute , c'est bien ça ?

    :non: 
    cel_target partant de telle cellule,
    Offset(1) je descends d'une ligne
    EntireRow je considère toute cette ligne
    Cells(1) et je vais à sa première cellule.
    Bref, je fait un Carriage Return / Line Feed


    noircafe a dit :


    Et pour finir , et là j'ai peur de passer pour un idiot mais bon :
    Cette ligne , ci dessous , signifie bien qu'elle va "lire" dans la feuille , une zone comprise entre la ligne 2 a 250 ?
    1. Set plg_source = ws_source.Range(ws_source.Rows(2), ws_source.Rows(250))


    Beaucoup de questions désolé .
    NoirCafé

    Euh, oui, enfin non, ou plutôt à peu prêt. :D 
    Range = Intervalle [:l_ecorcheur]
    Donc on ne fait que définir une zone, qui va de la deuxième ligne à la deux-cent-cinquantième. Stou.

    :) 

    Ah d'accord ^^ .
    Vivement que je ne soit plus un débutant ^^ .

    En attendant , mon problème est résolu !!
    Et c'est en grande partie grâce a toi , je vais pouvoir continuer et enfin avancer .

    Encore un grand merci , pour avoir pris le temps et la patience de m'aider .

    J'espere te revoir sur les forums .

    NoirCafé
    Lassé par la pub ? Créez un compte