Résolu VBA : Info pour une lecture de feuille ligne par ligne

  • Auteur de la discussion noircafe
  • Date de début

noircafe

Nouveau membre
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 :

[cpp]
Sub CopierColler

For i = 1 To 54550

If Application.Worksheets("Production Data").Cells(1, i) = vbString Then
Application.Worksheets("TabTraduction").Range("A1" & ":A" & i).Value = Application.Worksheets("Production Data").Cells(1 , i).Value

End If

Next i

End Sub


[/cpp]

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é :(
 

zeb

Modérateur
Salut,

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

Tu vas apprendre à 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 :
Code:
' // CTRL+Pause pour arrêter, parce que ça va être long, surtout vers la fin !
Dim lig_num As Long
For lig_num = 1 To Worksheets(1).Rows.Count
    MsgBox "Ligne n°" & lig_num
Next
Code:
' // CTRL+Pause pour arrêter, parce que ça va être long, surtout vers la fin !
Dim lig As Range ' // Lire explications plus loin
For Each lig In Worksheets(1).Rows
    MsgBox "Ligne n°" & lig.Row
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 :
Code:
Dim plage As Range
Pour parcourir ses cellules, ou utilise Cells():
Code:
Dim lig_n As Long, col_n As Long
For lig_n = 1 To Plage.Rows.Count
For col_n = 1 To Plage.Columns.Count
    MsgBox "Cellule " & lig_n & "x" & col_n
Next
Code:
Dim cel As Range
For Each cel In Plage.Cells
    MsgBox "Cellule " & cel.Row & "x" & cel.Column & vbCrLf & "On peut aussi écrire ça comme ça : " & cel.Address
Next

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

Maintenant, on mélange tout :
Code:
Dim ligne As Range
Dim cellule As Range

For Each ligne In Rows ' //  Attention, je te précise ni le classeur, ni la feuille, 
    For Each cellule In ligne
    Next
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 ?
 

noircafe

Nouveau membre
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 :

[cpp]

Option Explicit ' Je ne pense plus m'en passer maintenant que j'en ai compris l'utilité

Private Sub BtnCopierColler ()

Dim iPD As Long
Dim iTB As Long
Dim PD As Worksheet
Dim TB As Worksheet

Set PD = Worksheets("Production Data") 'Feuille où je veut copier
Set TB = Worksheets("TabTraduction") 'Feuille où je veut coller

iTB = 2
For iPD = 2 To 250
If PD.Cells(2, iPD).Text Then
PD.Range(iPD & ":" & iPD).Copy TB.Cells(iTB, 1)
iTB = iTB + 1
End If
Next


End Sub


[/cpp]


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
[cpp]


If PD.Cells(2, iPD).Text Like "[a-z]" Then

[/cpp]




NoirCafe

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

zeb

Modérateur
Salut,

Je ne comprends ta question sur l'indentation. Ta présentation est parfaire.
Tiens, un bon point avec ruban :
Vous devez être connecté pour voir les images.

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

Code:
PD.Range(iPD & ":" & iPD)
C'est pour référencer la ligne iPD ? Alors il y a plus logique !
Code:
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 :
Code:
Function IsTextOnly(ByVal texte As String) As Boolean
    ' // Code pour analyser le contenu de la variable texte
    
End Sub
Code:
...
If IsTextOnly(PD.Cells(2, iPD).Text) Then ...
...

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 :
Code:
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.
 

noircafe

Nouveau membre
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 .
[cpp]

PD.Rows(iPD)

[/cpp]

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 :

[cpp]
Private Sub CopierColler

Dim iPD As Long
Dim iTB As Long
Dim PD As Worksheet
Dim TB As Worksheet

Set PD = Worksheets("Production Data") 'Feuille ou je veut copier
Set TB = Worksheets("TabTraduction") 'Feuille où je veut coller

iTB = 2
For iPD = 2 To 250

If Not IsNull(PD.Cells(2, iPD).Text) And Not IsNumeric(PD.Cells(2, iPD).Value) Then ' Conditions a respecter

PD.Rows(iPD).Copy TB.Cells(iTB, 1)

iTB = iTB + 1

End If
Next

End Sub[/cpp]

Le code est bon mais il ne se passe rien , en fait je soupçonne [strike]les chinois[/strike] 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 .
[cpp]If Not IsNull(PD.Cells(2,iPD).Text) And Not IsNumeric(PD.Cells(2,iPD).Value) Then[/cpp]

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 .
 

zeb

Modérateur
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 :

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 !
Code:
Dim PD      As Worksheet
Dim PD_zone As Range
Dim PD_row  As Range
Dim TB_row  As Range

'// Feuille ou tu veux copier
Set PD = Worksheets("Production Data")
' // Zone de cette feuille que tu veux copier
Set PD_zone = PB.Range(PB.Rows(2), PB.Rows(250))

'// Ligne où tu veut coller
Set TB_row = Worksheets("TabTraduction").Rows(2)

For Each PD_row In PB_zone.Rows
    If Not IsNull(PD_row.Cells(2).Text) And _
       Not IsNumeric(PD_row.Cells(2).Value) _
    Then
        ' // Copie une ligne complète dans ... une ligne
        PD_row.Copy TB_row
        ' // La prochaine dans la ligne suivante
        Set TB_row = TB_row.Offset(1)
    End If
Next

___________________
(*) Ce qui viole la règle du . :o
 

noircafe

Nouveau membre
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é
[cpp]Set TB_row = Worksheets("TabTraduction").Rows(2)[/cpp]
par
[cpp]Set TB_row = Worksheets("TabTraduction").Columns(2)[/cpp]

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é

 

zeb

Modérateur
Meilleure réponse
Set TB_row = Worksheets("TabTraduction" ).Columns(2).
Non mais ça va pas :o

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

Code:
Set PD_zone = PB.Range(PB.Rows(2), PB.Rows(250))
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 :
Code:
'// 1 seule cellule
Set PD_cellB250 = PB.Cells(250, 2)
Set PD_cellB250 = PB.Range("B250")
Set PD_cellB250 = PB.[B250]

'// 1 seule ligne :
Set PD_ligne2 = PB.Rows(2)

'// Toutes les cellules entre deux bornes :
Set PD_lignes2a250 = PB.Range(PB.Cells(2, 2), PB.Rows(4, 250))

'// Toutes les lignes entre deux bornes :
Set PD_lignes2a250 = PB.Range(PB.Rows(2), PB.Rows(250))

' // Plusieurs zone en particulier
Set PD_lignes2et250 = Union(PB.Cells(2, 2), PB.Rows(250))

' // Les cellules qui appartiennent à plusieurs zones à la fois 
Set PD_cellB250 = Intersect(PB.Columns(2), PB.Rows(250))

' // Toutes les cellules
Set PD_tout = PB.Cells
Amuse-toi, avec un MsgBox PB_xxx.Address() pour voir le résultat :)

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

Code:
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 :
Code:
Dim ws_source      As Worksheet
Dim plg_source     As Range
Dim row_source     As Range
Dim cel_source     As Range
Dim cel_target     As Range
Dim passer_a_ligne As Boolean

'// Plage source des données 2:250
Set ws_source = Worksheets("PD")
Set plg_source = ws_source.Range(ws_source.Rows(2), ws_source.Rows(250))

'// Première cellule cible
Set cel_target = Worksheets("TB").Cells(2, 1)

For Each row_source In plg_source.Rows
    For Each cel_source In row_source.Cells
        passer_a_ligne = False
        If Not IsNull(cel_source.Text) And Not IsNumeric(cel_source.Value) Then
            ' // Au moins une cellule a été copiée, il faudra passer une ligne
            passer_a_ligne = True
            
            cel_target.Value = cel_source.Text
            Set cel_target = cel_target.Offset(0, 1)
        End If
        If passer_a_ligne Then
                                          ' // Bien regarder ça :^)
            Set cel_target = cel_target.Offset(1).EntireRow.Cells(1)
        Next
Next
 

noircafe

Nouveau membre
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
[cpp]
If Not IsNull(cel_source.Text) And Not IsNumeric(cel_source.Value) Then
[/cpp]

et ici
[cpp] cel_target.Value = cel_source.Text[/cpp]


Ah et sinon , la ligne :
[cpp]

Set cel_target = cel_target.Offset(1).EntireRow.Cells(1)
[/cpp]

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 ?
[cpp]Set plg_source = ws_source.Range(ws_source.Rows(2), ws_source.Rows(250))
[/cpp]

Beaucoup de questions désolé .
NoirCafé
 

zeb

Modérateur
Option Explicit [:zeb:4]
: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



Euh, oui, enfin non, ou plutôt à peu prêt. :D
Range
Vous devez être connecté pour voir les images.
= 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.

:)
 

noircafe

Nouveau membre
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é
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 136
Messages
6 718 120
Membres
1 586 398
Dernier membre
mookie767
Partager cette page
Haut