Résolu Macro VBA ou ?

mzubka

Habitué
Bonjour,

J'ai comme problématique d'automatiser la recopie de colonne d'un fichier source excel ( A ) vers un fichier cible excel ( B ).

Je dois donc recopier certaines colonnes du fichier A pour les disposer dans les bonnes colonnes du fichier B.

Je n'ai encore jamais toucher au VBA je voulais donc m'assurer qu'il sagit bien du bon outil pour réaliser cette fonction.

Merci d'avance!
Paul

 

zeb

Modérateur
Salut Paul Mzubka
:hello:

C'est possible et facile à faire en VBA.
Et comme en posant ta question dans le forum programmation, tu t'adresses ici à des personnes qui ne font rien qu'en programmant, une seule réponse : OUI.
:D

Avant même que tu ne te plonges dans le VBA je vais te donner une piste.
La commande que tu cherches s'appelle copy.

Pour commencer, démarre l'enregistreur de macro, et fais à la main ce que tu cherches à faire faire par la macro. Du code (tout pourri) va s'enregistrer. Essaie de le comprendre avec l'aide de l'aide en ligne.

Dès que tu bloques, viens nous voir. On a des trucs à te montrer ;)

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

Attention, le modo est chiant sur un point : il faut utiliser la balise
Code:
 si tu veux publier des bouts de code
:spamafote:
 

mzubka

Habitué
Code:
    Range("R2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Selection.Copy
    Windows("Fichier2").Activate
    Range("Y2").Select
    ActiveSheet.Paste

L'enregistreur me donne cette structure.
J'ai donc multiplier ces actions par 7 pour effectuer toutes les copies.

Mais sur les colonnes à copier seule la 1ère se copie normalement, pour les 6 autres il sélectionne bien la colonne d'arrivé mais il n'y copie rien.

Second soucis, je copie la colonne du fichier source sans l'en-tête pour la copier à partir de la 3eme ligne de la colonne cible.
-> Erreur de taille entre les 2 objets :

Code:
    Range("R2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Selection.Copy
    Windows("Fichier2").Activate
    Range("Y3").Select
    ActiveSheet.Paste
Je pensais modifier Selection.End(xlDown) en Selection.End(xlDown-1) , mais c'est surement trop barbare .

Merci d'avance, j'espère avoir été compréhensible ^^
 

zeb

Modérateur
-------------
Si le modo voit que t'as utilisé [quote] au lieu de [code], ça va barder.
Modifie ton message : clique sur le petit crayon en bas à droit de ton message.
 

mzubka

Habitué
Attention, le modo est chiant sur un point : il faut utiliser la balise
Code:
 si tu veux publier des bouts de code
[/quote]

J'ai fais le boulet je crois :( . Rectification faites.
 

zeb

Modérateur
Comme le modo, c'est moi, j'ai plein de droits ! Dont celui de modifier vos messages (c'est fou non ?!) J'en ai abusé. Regarde j'ai ajouté =vb dans tes balises =>
Code:
 et c'est tout de suite tellement plus joli.
;)

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

Or donc, je regarde ton code, et j'y vois une certaine logique.

Tu sélectionnes (Select) un truc, tu copies (Copy <-- ne t'en avais-je pas parlé ? ;) ) et tu colles (Paste).
Ça semble logique.

Avant de le faire 7 fois, on va le faire 1 fois correctement.

En lignes 1 et 2, tu sélectionnes un truc, puis t'en sélectionnes un autre. A mon avis, tu aurais pu t'économiser une étape.

Tiens des devoirs à la maison : lis l'aide sur [b]Range()[/b], [b]End()[/b] et [b]Copy()[/b].
Regarde surtout le paramètre de [b]Copy()[/b].
 

mzubka

Habitué
Pour ma première erreur, c'était tout con il fallais simplement reselectionner le fichier de base avec :

Code:
 Windows("Macro_AVEX").Activate

Par contre pour le problème de taille de la colonne je n'ai pas trouvé ;(
Peut être faudrait il sélectionner un nombre fixe ( grand) de ligne ?
 

mzubka

Habitué
Merci pour ces conseils.

J'ai donc pu modifier les 2ères lignes en
Code:
 Range("R2").End(xlDown).Select

Mais dorénavant la fin du code est devenue obsolète , Erreur 9 l'indice n'appartient pas à la selection. Alors que je n'ai toujours pas rajouté la contrainte du décallage d'une ligne entre Fichier 1 et 2.


 

zeb

Modérateur
Republie ton code.
On verra les problèmes de taille de colonne juste après.
 

mzubka

Habitué
Depuis ce matin j'ai essayé un nombre incalculable de combinaison mais donc je vous met la dernière version :

Code:
    Range("R2").End(xlDown).Select
    Selection.Copy
    Windows("Fichier2").Activate
    Range("Y2").End(xlDown).Select
    ActiveSheet.Paste

Il faudrais dimensionner l'objet avec Dim?
 

zeb

Modérateur
APRES tes problèmes de taille.

D'abord, on revoit ton code.
J'y vois deux erreurs, que l'enregistreur de macro t'a fait faire.

La première, c'est de se servir du presse-papier comme variable temporaire.
Le presses-papier ne doit être utilisé que par l'utilisateur et à son initiative.
Imagine un peu si tous les programmes s'en servaient à leur guise !

Donc pour ça, il y a une solution - mainte fois discutée sur ce forum, dont je t'ai déjà donné une piste.
As-tu lu l'aide sur copy() ?

L'autre erreur, c'est de sélectionner un truc, pour ensuite agir sur la sélection. Autant directement agir sur le truc. T'as compris ? :pt1cable: :pt1cable: :pt1cable: (moi non plus !)
Alors je te donne un exemple :

Code:
' // Pas bon
Range("R2").End(xlDown).Select
Selection.Copy

' // Bien :
Range("R2").End(xlDown).Copy
C'est mieux, non.

Il y a un autre problème. C'est l'utilisation de la fonction Windows() qui dépend du nombre de fois qu'on a ouvert un même document. Il faut proscrire son utilisation.

A la place, on utilisera l'objet Workbook qui représente un classeur.

Comme on jongle avec plusieurs classeurs, plusieurs feuilles et plusieurs plages de cellules, on va être explicite et tout préciser :

Code:
Dim cellule1 As Range
Dim cellule2 As Range

Set cellule1 = Workbook("nom du classeur source").Worksheets(1).Range("R2")
Set cellule2 = Workbook("nom du classeur source").Worksheets(1).Range("R2").End(xlDown)

Workbook("nom du classeur source").Worksheets(1).Range(cellule1, cellule2).Copy
Workbook("nom du classeur destination").Worksheets(1).Range("Y2").End(xlDown).Paste

Bon, il y a trop de répétitions dans ce code. C'est moche.


Code:
Dim wk_source As Workbook
Dim wk_cible  As Workbook
Dim ws_source As Worksheet
Dim ws_cible  As Worksheet
Dim rg_source as Range
Dim rg_cible  as Range

Set wk_source = Workbooks("nom du classeur source")
Set wk_cible  = Workbooks("nom du classeur cible")

Set ws_source = wk_source.Worksheets(1)
Set ws_cible  = wk_cible.Worksheets(1)

Set rg_source = ws_source.Range(ws_source.Range("R2"), ws_source.Range("R2").End(xlDown))
Set rg_cible  = ws_cible.Range("Y2").End(xlDown)

rg_source.Copy
rg_cible.Paste
Regarde bien ce code. Il est trop détaillé, mais très didactique.

Voici une version plus condensée :
Code:
Dim ws_source As Worksheet
Dim ws_cible  As Worksheet

Set ws_source = Workbooks("nom du classeur source").Worksheets(1)
Set ws_cible  = Workbooks("nom du classeur cible").Worksheets(1)

ws_source.Range(ws_source.Range("R2"), ws_source.Range("R2").End(xlDown)).Copy
ws_cible.Range("Y2").End(xlDown).Paste

Tu suis ?
Alors si on relis l'aide de la commande Copy, comment améliorer ce code ?

(OUI JE SAIS, TU AS UN PROBLEME DE TAILLE DE COLONNE, ON VA Y VENIR)
 

mzubka

Habitué
J'ai compris le problème de taille apres :p

Sinon pour l optimisation j'aurais dis ca :


Code:
Dim ws_source As Worksheet
Dim ws_cible  As Worksheet
 
Set ws_source = Workbooks("nom du classeur source").Worksheets(1)
Set ws_cible  = Workbooks("nom du classeur cible").Worksheets(1)
 
ws_source.Range(ws_source.Range("R2"), ws_source.Range("R2").End(xlDown)).Copy _
Destination:=ws_cible.Range("Y2").End(xlDown)

Après j'ai pensé à ... sans grande conviction mais ça me paraissait pas mal :


Code:
Dim ws_source As Worksheet
Dim ws_cible  As Worksheet
 
Set ws_source = Workbooks("nom du classeur source").Worksheets(1).Range(("R2"),("R2")).End(xlDown)
Set ws_cible  = Workbooks("nom du classeur cible").Worksheets(1).Range(("Y2"),("Y2")).End(xlDown)
 
ws_source.Copy _
Destination:=ws_cible
 

zeb

Modérateur
Meilleure réponse
Yiiiiha ! :bounce:
T'as tout compris. Le fait d'utiliser une destination avec Copy permet de ne pas toucher au presse-papier.

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

Range(("R2"),("R2")).End(xlDown)
Ça, ça ne veut rien dire.

End(xlDown) permet, partant d'une cellule, d'aller à la dernière (End) cellule du même bloc de cellules, vers le bas (...je te laisse deviner...).
Donc il faut l'appliquer à une cellule.

Range() permet de désigner une plage de cellules, cette plage pouvant être réduite à 1 cellule.
Range() s'applique à une feuille ou à un autre plage de cellule.

objet.Range(("R2"),("R2")) Mets autant de parenthèses inutiles que tu veux, c'est comme en maths, si ça sert à rien, ça ne gêne pas.

Ce que tu écris revient à : objet.Range("R2","R2")

Et "R2" dans un Range(..) revient à dire : ActiveSheet.Range("R2")

Or si l'objet n'est pas la feuille active ou une plage de la zone active, ça va planter : objet1.Range(objet2.Range("R2"), objet3.Range("R2"))

Il faut écrire : objet.Range(objet.première_cellule, objet.dernière_cellule)

Tu sais que Range("R2") est ta première cellule.
Tu calcules que Range("R2").End(...) est ta dernière cellule.
Donc tu copies toute la plage : Range(Range("R2"), Range("R2").End(...)).Copy ...

Puisqu'on jongle avec plusieurs classeurs et plusieurs feuilles, on précise :
mafeuille1.Range(mafeuille1.Range("R2"), mafeuille1.Range("R2").End(...)).Copy destination:=mafeuille2.première_cellule

T'as compris ? (moi, en me relisant, je m'y pers un peu)

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

Si oui, passons à la taille de la colonne.

1°) Ouvre un classeur plein de colonnes qui ne sont pas à la bonne taille.
2°) Démarre l'enregistreur de macro
3°) Mets une colonne à la bonne taille
4°) Arrête l'enregistreur de macro
5°) Va lire le code enregistré
6°) Reste dubitatif devant le code pendant quelques instants
7°) Publie-le ici qu'on rigole :lol:
 

mzubka

Habitué
Oui c'est très clair , énorme merci Zeb!

"[Question_Bete=On]
Par contre je ne comprends pas bien comment je peux mettre une colonne à la bonne taille;
cela équivaut à sélectionner le bon nombre de cellule correspondant à la bonne taille?
[Question_Bete=Off]"

Edit :

J'obtiens donc quelque chose mais sans certitude !

Code:
 Range(Selection, Selection.End(xlDown)).Select
    Range("A1048576").Select
    Selection.ClearContents
    Range("A2:A1048575").Select
 

zeb

Modérateur
M'enfin !?

1°) Le Môssieu te demande de ne pas faire de Select, de ne pas utiliser Selection.
[:zeb:4]

2°) Qu'est-ce que ClearContents vient-il faire là ?
:heink:

Qu'est-ce que tu appelles mettre une colonne à la bonne taille ?
:??:

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

Pour "mettre une colonne à la bonne taille", je double-clique sur le bord droit de l'entête de la colonne.
Et ça fit la colonne automatiquement
:spamafote:
 

mzubka

Habitué
On s'est mal compris alors.

Quand je parlais d'un problème de taille de colonne, c'étais le nombre de cellule.
Quand je sélectionne toutes les cellules de la colonne A et que je souhaite les copier dans la colonne B mais a partir de la cellule 2 => Problème de taille ma colonne ne peut s'insérer.
 

zeb

Modérateur
Ah, oki. La solution est pourtant dans ce que je t'ai écrit. Je viens de relire l'aide d'Excel. Le baratin te conforte dans ton erreur, l'exemple, lui est correct.

Pour copier une plage de cellules vers une autre, il faut donner exactement la plage à copier, et soit donner une zone exactement de la même taille, soit ne donner que la première cellule.

Et surtout, il ne faut pas utiliser de Select.

;)
 

mzubka

Habitué
J'ai contourné le problème en rajoutant une ligne.

Mais après la copie des colonnes je souhaitais qu'Excel me remplisse automatiquement des colonnes avec des constantes. J'ai donc réaliser une boucle For pour parcourir le bon nombre d'itération.
Mais j'ai deux problèmes :/

1) Rien ne s'ecrit dans les colonnes :x

2) Quand j'adresse les coordonnées des cellules, j'ai une erreur si je dépasse la colonne C ( 3 )
cells(i,1) et cells(i,2) compilent, mais lorsque je passe à cells(i,3) j'ai l'erreur 1004


Code:
Sub test()
    
Dim ws_source As Worksheet
Dim ws_cible As Worksheet
Dim i As Integer
Dim x As Long

Set ws_cible = Workbooks("f13").Worksheets(1)
Set ws_source = Workbooks("Macro_AVEX").Worksheets(1)

'Je compte le nombre de ligne de mon fichier source

x = WorksheetFunction.CountA(ws_source.Columns(1))


'Pour compenser la taille de la colonne on ajoute une ligne au fichier source

ws_source.Rows("1:1").Insert Shift:=xlDown


'Certaines colonnes sont à remplir avec des constantes , et une colonne avec une incrémentation (numéro de ligne )

For i = 1 To x + 2

ws_cible.Range(Cells(i, 2)).Value = "YA6"

ws_cible.Range(Cells(i, 5)).Value = "09-00"

ws_cible.Range(Cells(i, 7)).Value = "09-00"

ws_cible.Range(Cells(i, 24)).Value = i - 2


Next

'Copie des 7 colonnes dans le fichier cible
    
ws_source.Range(ws_source.Range("R3"), ws_source.Range("R3").End(xlDown)).Copy Destination:=ws_cible.Range("Y3")
ws_source.Range(ws_source.Range("V3"), ws_source.Range("V3").End(xlDown)).Copy Destination:=ws_cible.Range("Z3")
ws_source.Range(ws_source.Range("U3"), ws_source.Range("U3").End(xlDown)).Copy Destination:=ws_cible.Range("AA3")
ws_source.Range(ws_source.Range("W3"), ws_source.Range("W3").End(xlDown)).Copy Destination:=ws_cible.Range("AB3")
ws_source.Range(ws_source.Range("S3"), ws_source.Range("S3").End(xlDown)).Copy Destination:=ws_cible.Range("AC3")
ws_source.Range(ws_source.Range("AC3"), ws_source.Range("AC3").End(xlDown)).Copy Destination:=ws_cible.Range("AI3")
ws_source.Range(ws_source.Range("AD3"), ws_source.Range("AD3").End(xlDown)).Copy Destination:=ws_cible.Range("AJ3")



End Sub

Une petite idée du pourquoi du comment ? je m'arrache les cheveux depuis pas mal de temps sans pouvoir expliquer l'apparition de l'erreur et pourquoi rien ne s'écrit.
 

drul

Obscur pro du hardware
Staff
Essaie de remplacer :
Code:
 ws_cible.Range(Cells(i, 2)).Value = "YA6"

par
Code:
 ws_cible.Cells(i, 2).Value = "YA6"
;)

:Hello: Zeb
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 098
Messages
6 717 055
Membres
1 586 282
Dernier membre
Yannick3553
Partager cette page
Haut