Créer un échéancier en fonction d'un tableau aux informations multiples

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

adelitodelapampa

Nouveau membre
Hello tout le monde !

Je suis face à un besoin qui dépasse mes connaissances :) en cherchant sur différents forums je suis tombé sur ce topic, qui correspond à ma demande à quelques éléments différents près : https://forum.tomshardware.fr/threa...-si-une-condition-est-respectée.895999/page-5

Je crois avoir compris la démarche mais comme mes conditions sont plus développées, je n'arrive pas à l'adapter et il me semble que le code proposé serait la première étape vers ce que je cherche à obtenir.

Pour vous résumer la situation :
- mon fichier excel comporte 2 feuilles (+ en fait mais seules les 2 premières sont concernées ici)
- sur la première :
  1. j'ai un tableau à multiples colonnes et lignes
  2. la colonne AG correspond à une date d'échéance
  3. la colonne C à un service
  4. la colonne N à un nom
- sur la deuxième
  1. j'ai un plus petit tableau
  2. la colonne O correspond à une date d'échéance
  3. la colonne A à un service
  4. la colonne I à un nom
- je souhaiterais in fine créer un échéancier, qui se MAJ seul en fonction des modifs apportées dans les feuilles 1 et 2, dans une nouvelle feuille qui me permette de :
  1. Visualiser toutes les échéances avec le nom et service associé
  2. Qu'ils soient triés par mois
J'imaginais des colonnes en fonction de la date du jour mais peut-être que je m'emballe o_O
Vous devez être connecté pour voir les pièces jointes.


Si je pouvais déjà copier coller les éléments qui m'intéressent sans logique de tri ce serait TOP TOP !

Est-ce que ça motive quelqu'un de m'aider là dessus ? MERCI !!
 

svoglimacci

check memory failed but no bug detected
Salut :)

Bon alors attention, je suis une bille en règle générale, et je suis deux tanches en VB.
Cela étant posé, je peux peut-être t'aider à démarrer.

Ton besoin étant déjà assez bien expliqué, je vais le retranscrire un peu, à toi de dire si c'est bon ou pas, le corriger, bref, te l'approprier.

Si je comprends bien : la taille des tableaux, les noms des colonnes et les feuilles concernées mises à part, on peut dire que :
- tu as deux feuilles,
- sur chaque feuille trois colonnes : service, nom, échéance.
Tu voudrais, sur une troisième feuille :
- avoir une ligne de titres ("Service", "Nom","Échéance"),
- ajouter bout à bout les contenus des colonnes des deux premières feuilles,
- trier ce contenu selon le critère "échéance" (service et nom ne font pas partie du critère de tri ?).
(Ensuite, cerise sur le gâteau, regrouper cela par paquet de trois colonnes pour chaque mois mais on pourra voir cela plus tard).

Si j'ai bon, essaie un peu de faire un algo (en français moyen, pas avec des schémas) disant ce que tu doit programmer, genre : je lis de la ligne colonne 2 jusqu'à la première ligne cellule vide etc.
 
Dernière édition:

svoglimacci

check memory failed but no bug detected
Je me suis marré, j'ai fait toute la partie jusqu'à la feuille avec les colonnes triées. Le classement par mois n'est pas encore fait.
Si tu veux le faire avec un coup de main dis le, si tu veux le code direct, dis le aussi. Il n'est pas très élégant mais bon, VBA n'est pas mon fond de commerce. Les structures Excel non plus :D
 

svoglimacci

check memory failed but no bug detected
Bon c'est fini, à part la mise en forme. Comme sur ton graphique.
Il y a "une" (trois en fait) colonne par mois rencontré. Ce qui veut dire que si un mois n'apparait pas dans les deux listes originelles, il n'y aura pas de colonne pour lui (on passerait par exemple de janvier à mars). On peut mettre un "trou" (donc avoir un février vide), cela pourrait se faire.
La mise en forme n'est pas faite.
Merci pour le machin, je me suis bien marré (grâce aux forums d'aide !!), donc si tu ne reviens pas ce n'est pas grave.
Par contre VBA c'est lourd...
 

adelitodelapampa

Nouveau membre
Hello !

Alors déjà merci de tes réponses et de t'être penché sur mon problème !

Je suis partante pour essayer de comprendre la démarche et pas juste reproduire ton code mais je n'ai jamais fait de VB donc je pars un peu de 0 :)

Je rebondis d'abord sur ton premier message pour préciser quelque chose en espérant que ça ne perturbe pas toutes tes démarches !

- Mon classeur contient 3 feuilles (une en plus de celles-citées appelée reporting avec des suivi d'indicateurs)
- Sur les deux premières feuilles il y a bien les colonnes NOM / SERVICE / ECHEANCE mais il y a aussi d'autres colonnes !
 

svoglimacci

check memory failed but no bug detected
Salut :)
--- Structure :
Pour tes questions sur la structure de ton fichier, sache que quelques soient les feuilles et les colonnes concernées, cela n'a pas d'importance. Sauf qu'il ne faut ni les bouger ni les renommer, sinon il te faudra adapter la macro. Ce n'est pas mortel mais je ne l'ai pas faite assez "paramétrable" (pour les colonnes) pour que cela se fasse d'un claquement de doigts. Je modifierai cela.
--- Qualité du code :
Je ne suis pas un bon codeur, il se peut que cela puisse être plus propre, les avis sont les bienvenus.
Et toi, il t'est arrivée de programmer ? En quel langage ?
--- Sources et apprentissage :
Pour les sources, je vais tout simplement te les donner, répondre à tes questions et le modifier avec toi . Je pourrais te le faire construire au fur et à mesure, mais 1) cela prendrait des plombes que tu n'as pas forcément, 2) je ne suis certainement pas un bon codeur en VB donc je pourrais te donner des conseils mal avisés, ce que je n'aime pas faire. Je préfère donc te donner du code en vrac, et te l'expliquer. Cette phase d'explication est absolument nécessaire, elle te permettra d'être plus à même de modifier le code en cas de besoin, voire de créer d'autres macros un jour.
--- Contexte :
Sinon, une question : c'est pour le boulot ou perso ? Parce que il va falloir faire accepter à Excel de stocker / exécuter des macros dans cette feuille, et je n'ai pas très bien compris mais il peut y avoir une politique globale entreprise pouvant être gérée par un "admin". Bon, je sais à peu près faire pour perso, et aussi pour une boite qui ne gère pas ces trucs.
--- Gestion des macros :
Je n'ai rien préparé pour la partie "accéder aux macros, les modifier, tout ça". Il va falloir que je le fasse. Là je n'ai absolument pas le temps mais je pourrai le faire d'ici ce soir.
--- Donc, après tout ce verbiage :)
Je te livre, ci-dessous, le code. Celui-ci n'est pas "structuré" au sens où (avant en tous les cas) on disait qu'une fonction ne devait dépasser 15/20 lignes. Là, tout est d'un bloc :) Je reviens vers toi plus tard avec une version plus détaillée, expliquée, plus paramétrée pour les noms des colonnes concernée.
En attendant, je te conseille de lire, essayer de comprendre tranquilos. Certes, tu ne pourras rien exécuter pour le moment, mais cela viendra.
Ok ? Ok ! :D
Code:
Sub TriPlanning()
'
' TriPlanning Macro
'

'   -- La copie des données de 1 et 2 vers 3 --

' Variables pour la partie Copie
Dim Tab1NbLig As Integer
Dim Tab2NbLig As Integer
' Pour simplifier la lecture et surtout le remplacement des noms de feuilles.
Dim W1 As Worksheet
Set W1 = Worksheets("Feuil1")
Dim W2 As Worksheet
Set W2 = Worksheets("Feuil2")
Dim W3 As Worksheet
Set W3 = Worksheets("Feuil3")
' On nettoie Feuil3
    W3.Cells.Clear
' On met les titres dans Feuil3
    W3.Range("A1") = "SERVICE"
    W3.Range("B1") = "NOM"
    W3.Range("C1") = "ECHEANCE"
' On récupère le nombre de lignes dans Feuil1
    Tab1NbLig = W1.Range("A65536").End(xlUp).Row ' Méthode discutable, je n'ai pas mieux.
' Feuil1 : On copie les parties de colonnes et on les colle dans Feuil3
    W1.Range("A2:A" & Tab1NbLig).Copy
    W3.Range("A2").PasteSpecial
    W1.Range("B2:B" & Tab1NbLig).Copy
    W3.Range("B2").PasteSpecial
    W1.Range("C2:C" & Tab1NbLig).Copy
    W3.Range("C2").PasteSpecial
' On récupère le nombre de lignes dans Feuil2
    Tab2NbLig = W2.Range("A65536").End(xlUp).Row
' Feuil2 : On copie les parties de colonnes et on les colle dans Feuil3
    W2.Range("A2:A" & Tab2NbLig).Copy
    W3.Range("A" & Tab1NbLig + 1).PasteSpecial
    W2.Range("B2:B" & Tab2NbLig).Copy
    W3.Range("B" & Tab1NbLig + 1).PasteSpecial
    W2.Range("C2:C" & Tab2NbLig).Copy
    W3.Range("C" & Tab1NbLig + 1).PasteSpecial

'   -- Le tri des données de 3 --
' Variables pour la partie Tri
Dim Tab3NbLig As Integer
' On récupère le nombre de lignes dans Feuil3
    Tab3NbLig = W3.Range("A65536").End(xlUp).Row
' On trie, pas mal de choses à faire.
    Range("A1:C" & Tab3NbLig).Select
    W3.Sort.SortFields.Clear
    W3.Sort.SortFields.Add Key:=Range("C2:C" & Tab3NbLig) _
        , SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    W3.Sort.SortFields.Add Key:=Range("A2:A" & Tab3NbLig) _
        , SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    W3.Sort.SortFields.Add Key:=Range("B2:B" & Tab3NbLig) _
        , SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    With W3.Sort
        .SetRange Range("A1:C" & Tab3NbLig)
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With
' On vire le cadre de sélection, c'est casse pieds, on se met sur A1
    Range("A1:A1").Select

' Le découpage par mois
    Dim LigCpt As Integer ' La variable qui va parcourir le tableau
    Dim LigNbTot As Integer
    Dim DateTrav As Date
    Dim AnMoisTrav As String
    Dim AnMoisBase As String
    Dim ARemplirCol As Integer
    Dim ARemplirLig As Integer
' L'idée est de parcourir le tablea, dates étant triées, et de faire des ruptures par An/Mois
' On récupère le nombre otal de lignes
    LigNbTot = W3.Range("C65536").End(xlUp).Row ' Méthode discutable, je n'ai pas mieux.
    LigCpt = 2 ' On commence à la 2ème ligne, la première est celle des titres
    AnMoisBase = "" ' Pour avoir une rupture dès le début
    ARemplirCol = 0 'Pour donnée la 1ère colonne (paquet de 3) à remplir. La première remplie sera la 2
' On parcourt le tableau
    While (LigCpt <= LigNbTot)
        DateTrav = CDate(W3.Cells(LigCpt, "C"))
' On formatte An/mois avec cas spécial pour avoir 0 devant le mois si < 6. Il devrait y avoir une option de formatage de nombres mais je ne trouve pas
        AnMoisTrav = Year(DateTrav) & "/"
        If (Month(DateTrav)) <= 6 Then
            AnMoisTrav = AnMoisTrav & "0" & Month(DateTrav)
        Else
            AnMoisTrav = AnMoisTrav & Month(DateTrav)
        End If
' Examen des ruptures (changement de Année/mois)
        If (AnMoisBase <> AnMoisTrav) Then ' Si rupture
            AnMoisBase = AnMoisTrav ' On prépare la "base" pour détecter la rupture suivante
            ARemplirCol = ARemplirCol + 1 ' On va remplir le paquet de 3 colonnes suivant.
            ARemplirLig = 3 ' On demarre le remplissage des colonnes en ligne 3 (une ligne pour année mois, une ligne pour les titres
            W3.Cells(1, (ARemplirCol * 3) + 1) = AnMoisTrav ' On colle Année/Mois dans la première ligne
'   On fusionne les trois colonnes pour la date : Cells(x,y).address permet d'éviter des bidouilles pour avoir les lettres
            W3.Range( _
                Cells(1, (ARemplirCol * 3) + 1).Address(RowAbsolute:=False, ColumnAbsolute:=False), _
                Cells(1, (ARemplirCol * 3) + 3).Address(RowAbsolute:=False, ColumnAbsolute:=False) _
            ).MergeCells = True
' Les titres en ligne 2
            W3.Cells(2, (ARemplirCol * 3) + 1) = "SERVICE"
            W3.Cells(2, (ARemplirCol * 3) + 2) = "NOM"
            W3.Cells(2, (ARemplirCol * 3) + 3) = "ECHEANCE"
        End If
' On copie les données vers la colonne but
        W3.Cells(ARemplirLig, (ARemplirCol * 3) + 1) = W3.Cells(LigCpt, 1)
        W3.Cells(ARemplirLig, (ARemplirCol * 3) + 2) = W3.Cells(LigCpt, 2)
        W3.Cells(ARemplirLig, (ARemplirCol * 3) + 3) = W3.Cells(LigCpt, 3)
' On passe à la ligne à remplir suivante
        ARemplirLig = ARemplirLig + 1
' On passe à la ligne à lire suivante
        LigCpt = LigCpt + 1
    Wend
' On supprime les trois premières colonnes qui ne servent plus
Columns("A:C").Delete Shift:=xlToLeft
' On centre les deux premières lignes
Rows("1:2").HorizontalAlignment = xlCenter

    
End Sub
 

adelitodelapampa

Nouveau membre
Hello !

Merci pour ta réponse :)
Alors, je n'ai jamais codé si ce n'est un touuuut petit peu en java, je m'étais lancé dans un MOOC mais ça prenait du temps pour bien le faire et comme ça n'a strictement rien à voir avec ce que je fais ... mais disons que ça m'a donné quelques bases.

Sinon ça me va pour partir de ton code et essayer de le comprendre !

----

Je crois avoir compris la première partie de ton code, enfin en tous cas son action même si je ne comprends pas tous les éléments (ex : Sub TriPlanning(), c'est le titre ?)

Ma compréhension :
- Tu définies Dim Tab1NbLig et Dim Tab2NbLig comme les éléments à intégrer dans la feuille 3
- Tu nommes les feuilles 1, 2 et 3 : "Feuil1" / "Feuil2" / "Feuil3" (j’imagine que c'est là que je peux adapter leur dénomination)
- Tu prépares la Feuil3 en la nettoyant
- Tu prépares le tableau SERVICE / NOM/ ECHEANCE en feuil3
- Tu récupère les lignes de la Feuil1, mais cela va-t-il récupérer que les lignes qui ont une échéances ? Beaucoup n'en ont pas donc ça risque de faire des lignes vides ?
- Tu colles les éléments dans la feuil3, est-ce là qu'il faut définir les colonnes à récupérer de la Feuil1 ? En l’occurrence :
  • SERVICE : C
  • NOM : N
  • DATE D'ECHEANCE : AG
J'avoue que cette partie est un peu obscure en terme de compréhension du code :p

- En tous cas tu fais la même chose pour la feuille 2, sachant qu'ici ce ne sont plus les mêmes colonnes mais
  • SERVICE : A
  • NOM : I
  • DATE D'ECHEANCE : O
J'avoue que pour la 2ème partie je suis carrément paumée, je vois la démarche de :
1- trier par ordre chronologique
2 - créer des ruptures quand on change de mois
Ensuite c'est un peu plus fou mais j'imagine que c'est ce qui permet de tout mettre en forme correctement !

Hate de le tester :bounce:
 

drul

Obscur pro du hardware
Staff
@svoglimacci , un petit détail (j'ai pas tout lu, mais c'est quand même loin d'être mal codé)
W2.Range("A65536").end(xlup).row est mieux ainsi: W2.Range(rows.count).end(xlup).row, excel gère plus de 65536 ligne de nos jours ...
 

magellan

Modérâleur
Staff
+1 sorti d'une seule chose à savoir
Code:
 W3.Cells(ARemplirLig, (ARemplirCol * 3) + 1) = W3.Cells(LigCpt, 1)
        W3.Cells(ARemplirLig, (ARemplirCol * 3) + 2) = W3.Cells(LigCpt, 2)
        W3.Cells(ARemplirLig, (ARemplirCol * 3) + 3) = W3.Cells(LigCpt, 3)
Que j'aurais fait en boucle for (i de 1 à 3) histoire de rendre la chose plus dynamique si tu étais amené à ajouter des lignes, je n'ai rien vu qui me choque outre mesure (au contraire même)

Code:
For increment = 1 To 3
 W3.Cells(ARemplirLig, (ARemplirCol * 3) + increment) = W3.Cells(LigCpt, increment)
next
Cela fait la même chose... et si tu changes l'indice tu augmentes le nombre de passages ;)

mais là je chipote: c'est plus clair et compréhensible avec trois lignes comme fait actuellement
 

svoglimacci

check memory failed but no bug detected
W2.Range("A65536").end(xlup).row est mieux ainsi: W2.Range(rows.count).end(xlup).row, excel gère plus de 65536 ligne de nos jours ...
Merci c'est fait !
Par ailleurs, justement à casue de mes bétises de 65536, j'ai eu des problèmes avec les grands nombres et je n'avais pas envie de caster dans tous les coins, du coup j'ai passé tous les Integer en Long. Tant pis pour l'esthétique. Je dois pouvoir maintenant, grâce à toi, remettre des Integer.
+1 sorti d'une seule chose à savoir : Que j'aurais fait en boucle for (i de 1 à 3) histoire de rendre la chose plus dynamique si tu étais amené à ajouter des lignes, je n'ai rien vu qui me choque outre mesure (au contraire même).
Oui tu as tout à fait raison. En fait je ne voulais pas alourdir le code qui est déjà mahousse mais je tâcherai de penser à faire comme tu dis. C'est plus propre !

Par ailleurs, j'ai déjà rendu les choses plus paramétrables (n° de colonnes entre autres). Par contre, je vais éclaircir un peu ce code avec des appels de fonctions, juste histoire de découper. Je vais voir si je peux faire des fonctions "riches" mais les fonctions à "20" paramètres...

Merci en tous les cas, vos conseils sont super sympas et surtout aident bien !

@adelitodelapampa :
- Sub TriPlanning() est bien le titre de la macro. Je te montrerai plus tard (je n'arrive pas à tout faire d'un coup vu que mon fils me prend énormément de temps (je le coach en tournoi FortNite :) ) ) comment faire pour accéder aux macros, en créer pour quelles enregistrent ton travail, les modifier.... Tu verras, ça va vite. J'aurais peut-être du commencer par là.
- "Dim Tab1NbLig as Integer" (Integer va devenir Long dans la prochaine version) définit une variable nommée Tab1NbLig. C'est un entier (Integer) et maintenant c'est un grand entier (Long). Le nom de cette variable essaie d'être court tout en étant parlant, un vrai challenge. Là, en l'occurence, c'est dans le Tableau 1 (Feuille 1, tu vois, déjà une erreur de nommage de ma part), le nombre de lignes. Ne t'attache pas trop aux nom des variables, cela risque de changer. Essaye pour le moment de plutôt comprendre certaines instructions et l'idée générale de la macro. Plus tard, j'expliquerai mieux.
- Tu nommes les feuilles 1, 2 et 3 : "Feuil1" / "Feuil2" / "Feuil3" (j’imagine que c'est là que je peux adapter leur dénomination) --> Yes Sir !
- Tu prépares la Feuil3 en la nettoyant --> Yes Sir ! On ne sait jamais, c'est plus propre Par contre, il faudra savoir si elle existe déjà ou pas ! Rude oubli de ma part.
- Tu prépares le tableau SERVICE / NOM/ ECHEANCE en feuil3 --> Yes Sir !
- Tu récupère les lignes de la Feuil1, mais cela va-t-il récupérer que les lignes qui ont une échéances ? Beaucoup n'en ont pas donc ça risque de faire des lignes vides ? --> Alors là, si certaines lignes existent mais n'ont pas d'échéance, ça risque de causer un souci. On verra cela lors des premiers essais, et on ajoutera une suppression des lignes (dans feuille 3 avant voire après le tri) qui n'ont pas d'échéance.
- Pour ce qui est de savoir dans quelles colonnes on récupère les données, tant en feuille 1 que en feuille 3, cela est pour l'instant le souk. Pour éviter que tu te tues à aller modifier partout A par C, B par N etc, je rends cela paramétrable, comme les noms de feuilles le sont déjà.
- Oui, on trie. Je ne me suis pas cassé les pieds, j'ai enregistré une macro en faisant le tri, et je l'ai copiée :D
- Oui, on analyse la liste pour créer des ruptures. Et, au fur et à mesure, on bascule cela dans les colonnes (par paquets de trois colonnes) qui suivent, selon Année/Mois.
- Très peu de mise en forme : fusionné/centré pour Année/Mois, pour le moment :)

Continue à lire, tranquilos, vas-y par petits bouts, normalement une suite arrivera demain. Elle sera plus paramétrée, donc un peu plus délicate à lire, mais on s'y fait tu verras.
Pour un peeeeeeeutit peu de Java, je trouve que tu n'as pas peur de lire du code, c'est bien :)
Et n'hésite pas avec les questions :)
 

svoglimacci

check memory failed but no bug detected
C'est trop prenant le développement ;)
Il reste encore de l'assainissement.
Promis, je prépare un topo pour tout ce qui est accès aux macros.
Code:
Function CLAlpha(Col As Long, Lig As Long) As String
' Transforme N° Colonne et N° Ligne en nom alpha de cellule.
' Exemple : (2, 3) -> "B3"
    CLAlpha = Cells(Lig, Col).Address(RowAbsolute:=False, ColumnAbsolute:=False)
End Function
Function CLRange(Col1 As Long, Lig1 As Long, Col2 As Long, Lig2 As Long) As String
' Transforme Col 1, Lig 1, Col 2, Lig 2 en Range.
' Exemple : (2, 3, 4, 5) -> "B3:D5"
    CLRange = CLAlpha(Col1, Lig1) & ":" & CLAlpha(Col2, Lig2)
End Function
Function LettreNumCol(Col As Long) As String
' Transforme N° Colonne en tettre
' genre 2 -> B ou 27 -> AA
' Cela semble bidouillé mais je n'ai pas mieux. Une fonction purement VBA Excel serait mieux.
    LettreNumCol = Split(Cells(, Col).Address(RowAbsolute:=True, ColumnAbsolute:=False), "$")(0)
End Function
Function CopieVersFeuille(WOri As Worksheet, _
                          NumColOriService As Long, NumColOriNom As Long, NumColOriEcheance As Long, _
                          WBut As Worksheet, _
                          NumColButService As Long, NumColButNom As Long, NumColButEcheance As Long, _
                          OffsetBut As Long) As Long
' Copie les zones concernées d'une WOri vers une WBut
' Renvoie le nombre de lignes trouvées, on en a en fait besoin pour la deuxième copie.

' On récupère le nombre de lignes de la feuille
    Dim NbLig As Long
    NbLig = WOri.Range(CLAlpha(NumColOriService, Rows.Count)).End(xlUp).Row
' On met ce nombre de ligne dans la zone de renvoi car l'appelant en aura besoin
    CopieVersFeuille = NbLig
' On copie les parties de colonnes de WOri et on les colle dans WBut
    WOri.Range(CLRange(NumColOriService, 2, NumColOriService, NbLig)).Copy
    WBut.Range(CLAlpha(NumColButService, OffsetBut)).PasteSpecial
    WOri.Range(CLRange(NumColOriNom, 2, NumColOriNom, NbLig)).Copy
    WBut.Range(CLAlpha(NumColButNom, OffsetBut)).PasteSpecial
    WOri.Range(CLRange(NumColOriEcheance, 2, NumColOriEcheance, NbLig)).Copy
    WBut.Range(CLAlpha(NumColButEcheance, OffsetBut)).PasteSpecial
End Function
Function InitVariables(W1 As Worksheet, W2 As Worksheet, W3 As Worksheet, _
                       NumColF1Service As Long, NumColF1Nom As Long, NumColF1Echeance As Long, _
                       NumColF2Service As Long, NumColF2Nom As Long, NumColF2Echeance As Long, _
                       NumColF3Service As Long, NumColF3Nom As Long, NumColF3Echeance As Long, _
                       TitreCol1, TitreCol2, TitreCol3 As String _
    )
    Set W1 = Worksheets("Feuil1"): Set W2 = Worksheets("Feuil2"): Set W3 = Worksheets("Feuil3")
    NumColF1Service = 2: NumColF1Nom = 1: NumColF1Echeance = 3
    NumColF2Service = 2: NumColF2Nom = 1: NumColF2Echeance = 3
    NumColF3Service = 1: NumColF3Nom = 2: NumColF3Echeance = 3
    TitreCol1 = "Service": TitreCol2 = "Nom": TitreCol3 = "Echeance"
End Function
Sub TriPlanning()
'
' TriPlanning Macro
'
' Les noms de feuilles, numéros de colonnes, qui simplifient la paramétrabilité
    Dim W1 As Worksheet, W2 As Worksheet, W3 As Worksheet
    Dim NumColF1Service As Long, NumColF1Nom As Long, NumColF1Echeance As Long
    Dim NumColF2Service As Long, NumColF2Nom As Long, NumColF2Echeance As Long
    Dim NumColF3Service As Long, NumColF3Nom As Long, NumColF3Echeance As Long
    Dim TitreCol1 As String, TitreCol2 As String, TitreCol3 As String
' On initialise les variables (il en manque sûrement).
' Pourquoi diantre faut-il un retour à cette fonction ??
    i = InitVariables(W1, W2, W3, _
                      NumColF1Service, NumColF1Nom, NumColF1Echeance, _
                      NumColF2Service, NumColF2Nom, NumColF2Echeance, _
                      NumColF3Service, NumColF3Nom, NumColF3Echeance, _
                      TitreCol1, TitreCol2, TitreCol3 _
    )

' On nettoie la Feuille 3
    W3.Cells.Clear
' On met les titres dans Feuile 3
' (inutiles, les colonnes vont être supprimées mais en cas de débug...)
    W3.Range(CLAlpha(NumColF3Service, 1)) = TitreCol1
    W3.Range(CLAlpha(NumColF3Nom, 1)) = TitreCol2
    W3.Range(CLAlpha(NumColF3Echeance, 1)) = TitreCol3

' -- La copie des données de 1 et 2 vers 3 --
    Dim Tab1NbLig As Long ' Nbre de lignes dans feuille 1 : Pour l'offset du deuxième appel à la fonction de copie.
    Dim Tab2NbLig As Long ' Nbre de lignes dans feuille 2 : Ne sert à rien mais semble obligatoire pour le retour de la fonction.
    Tab1NbLig = CopieVersFeuille(W1, NumColF1Service, NumColF1Nom, NumColF1Echeance, _
                                 W3, NumColF3Service, NumColF3Nom, NumColF3Echeance, 2)
    Tab2NbLig = CopieVersFeuille(W2, NumColF2Service, NumColF2Nom, NumColF2Echeance, _
                                 W3, NumColF3Service, NumColF3Nom, NumColF3Echeance, Tab1NbLig + 1)


'   -- Le tri des données de 3 -- VA SORTIR EN FONCTION
' Variables pour la partie Tri
    Dim Tab3NbLig As Long
' On récupère le nombre de lignes dans Feuil3
    Tab3NbLig = W3.Range(CLAlpha(NumColF3Service, Rows.Count)).End(xlUp).Row
' On trie, pas mal de choses à faire.
    Range(CLRange(NumColF3Service, 1, NumColF3Echeance, Tab3NbLig)).Select
    W3.Sort.SortFields.Clear
    W3.Sort.SortFields.Add Key:=Range(CLRange(NumColF3Echeance, 2, NumColF3Echeance, Tab3NbLig)) _
        , SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    W3.Sort.SortFields.Add Key:=Range(CLRange(NumColF3Service, 2, NumColF3Service, Tab3NbLig)) _
        , SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    W3.Sort.SortFields.Add Key:=Range(CLRange(NumColF3Nom, 2, NumColF3Nom, Tab3NbLig)) _
        , SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    With W3.Sort
        .SetRange Range(CLRange(NumColF3Service, 1, NumColF3Echeance, Tab3NbLig))
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

' Le découpage par mois VA SORTIR EN FONCTION
    Dim LigCpt As Long ' La variable qui va parcourir le tableau
    Dim LigNbTot As Long
    Dim DateTrav As Date
    Dim AnMoisTrav As String
    Dim AnMoisBase As String
    Dim ARemplirCol As Long
    Dim ARemplirLig As Long
' L'idée est de parcourir le tablea, dates étant triées, et de faire des ruptures par An/Mois
' On récupère le nombre otal de lignes
    LigNbTot = W3.Range(CLAlpha(NumColF3Service, Rows.Count)).End(xlUp).Row ' Méthode discutable, je n'ai pas mieux.
    LigCpt = 2 ' On commence à la 2ème ligne, la première est celle des titres
    AnMoisBase = "" ' Pour avoir une rupture dès le début
    ARemplirCol = 0 'Pour donnée la 1ère colonne (paquet de 3) à remplir. La première remplie sera la 2
' On parcourt le tableau
    While (LigCpt <= LigNbTot)
        DateTrav = CDate(W3.Cells(LigCpt, LettreNumCol(NumColF3Echeance)))
' On formatte An/mois avec cas spécial pour avoir 0 devant le mois si < 6. Il devrait y avoir une option de formatage de nombres mais je ne trouve pas
        AnMoisTrav = Year(DateTrav) & "/"
        If (Month(DateTrav)) <= 6 Then
            AnMoisTrav = AnMoisTrav & "0" & Month(DateTrav)
        Else
            AnMoisTrav = AnMoisTrav & Month(DateTrav)
        End If
' Examen des ruptures (changement de Année/mois)
        If (AnMoisBase <> AnMoisTrav) Then ' Si rupture
            AnMoisBase = AnMoisTrav ' On prépare la "base" pour détecter la rupture suivante
            ARemplirCol = ARemplirCol + 1 ' On va remplir le paquet de 3 colonnes suivant.
            ARemplirLig = 3 ' On demarre le remplissage des colonnes en ligne 3 (une ligne pour année mois, une ligne pour les titres
            W3.Cells(1, (ARemplirCol * 3) + 1) = AnMoisTrav ' On colle Année/Mois dans la première ligne
'   On fusionne les trois colonnes pour la date : Cells(x,y).address permet d'éviter des bidouilles pour avoir les lettres
            W3.Range( _
                Cells(1, (ARemplirCol * 3) + 1).Address(RowAbsolute:=False, ColumnAbsolute:=False), _
                Cells(1, (ARemplirCol * 3) + 3).Address(RowAbsolute:=False, ColumnAbsolute:=False) _
            ).MergeCells = True
' Les titres en ligne 2
            W3.Cells(2, (ARemplirCol * 3) + 1) = "SERVICE"
            W3.Cells(2, (ARemplirCol * 3) + 2) = "NOM"
            W3.Cells(2, (ARemplirCol * 3) + 3) = "ECHEANCE"
        End If
' On copie les données vers la colonne but
        W3.Cells(ARemplirLig, (ARemplirCol * 3) + 1) = W3.Cells(LigCpt, 1)
        W3.Cells(ARemplirLig, (ARemplirCol * 3) + 2) = W3.Cells(LigCpt, 2)
        W3.Cells(ARemplirLig, (ARemplirCol * 3) + 3) = W3.Cells(LigCpt, 3)
' On met la colonne d'Echeance au format Date
        Columns(LettreNumCol((ARemplirCol * 3) + 3) & ":" & LettreNumCol((ARemplirCol * 3) + 3)).Select
        Range(LettreNumCol((ARemplirCol * 3) + 3) & "2").Activate 'Qu'est-ce que ce fichu "2" vient faire ici ?
        Selection.NumberFormat = "m/d/yyyy"
' On passe à la ligne à remplir suivante
        ARemplirLig = ARemplirLig + 1
' On passe à la ligne à lire suivante
        LigCpt = LigCpt + 1
    Wend
' On supprime les trois premières colonnes qui ne servent plus
    Columns(LettreNumCol(NumColF3Service) & ":" & LettreNumCol(NumColF3Echeance)).Delete Shift:=xlToLeft
' On centre les deux premières lignes
    Rows("1:2").HorizontalAlignment = xlCenter
' On se positionne sur la première cellule
'    Range(CLRange(NumColF3Service, 1, NumColF3Service, 1)).Select
    Range("A1:A1").Select

' La mise en forme n'est absolument pas faite (cadre, gras, centrage, couleurs ...) C'est faisable.

    
End Sub
 

magellan

Modérâleur
Staff
Etant dev pro depuis 20 ans (le temps passe...) et codeur amateur depuis bientôt 30... je suis féru de code "propre" pas au sens esthétique mais efficacité. En gros, j'aime qu'on puisse aisément lire le code, paramétrer correctement, anticiper tant que faire se peut, et faire en sorte qu'on puisse réutiliser le code!

Dans les faits, ça n'est pas toujours évident, mais un peu de bon sens et de méthode aident énormément.

Par exemple: on traite en gestion énormément de notions de dates (par exemple "est-ce que la date X est comprise entre les dates a et b). On se fait une "caisse à outils" (librairie) et on y cumule les indispensables. De cette manière, hop pas besoin de réinventer la roue! Après, faut être méticuleux et suivre les dossiers avec un Excel pour avoir le contenu, des thèmes et se garantir de ne pas refaire X fois le même job.
 

svoglimacci

check memory failed but no bug detected
++
30 ans. La mienne est plus longue. Oui, c'est nul.
 

svoglimacci

check memory failed but no bug detected
@adelitodelapampa
Attaquons par les manipulations à faire sur Excel pour les Macros.
Ce qui est en dessous parait long et fastidieux parce que je suis bavard, mais c'est nécessaire et c'est un grand pas en avant.​

(Avertissement : je suis sur Excel 2003. Certains paramètres ne seront pas au même endroit pour toi, certaines questions posées par Excel seront différentes, il te faudra peut-être faire des recherches. Par contre, côté codage, je pense que cela ira, il n'y a après tout rien d'extraordinaire donc rien qui ne devrait avoir changé
Avertissement : je te conseille de faire les manipulations ci-dessous sur un fichier vierge ou sur une copie :D

1) Accès aux Macros
Il faut afficher le menu déroulant "Développeur". Pour cela :
- Bouton "Windows" en haut à gauche / Bouton "Options Excel" / A gauche choisir "Standard" / Coche la case "Afficher l'onglet Développeur dans le ruban"
--> Quand tu reviens, tu as maintenant en haut à droite le menu développeur.
2) Pour enregistrer une Macro :
- Dans le menu Développeur / A gauche "Enregistrer une Macro"
- Excel te demande le nom de la Macro, laisse pour le moment ce qu'il te propose (Macro1) par défaut mais tu peux aussi le changer. Pas d'espaces, d'accents, de caractères spéciaux, autant éviter.
- Fais Ok
- Vas sur n'importe quelle cellule / Tape un truc / Centre la cellule
- Clique en haut à gauche "Arrêter l'enregistrement"
3) Pour visualiser / modifier ta Macro :
- En haut à gauche "Macros",
- Une nouvelle fenêtre s'ouvre : "Modifier"
Ou alors :
- Alt+F11 depuis ta feuille.
4) Exécuter ta Macro méthode 1 :
- (Efface ta cellule pour constater que cela fonctionne)
- Macros / Choix de la bonne Macro (à ce stade, la 1 pour toi à priori)
- Exécuter
- On constate le résultat.
- Recommence en modifiant la macro (la cellule, la valeur mise dedans...)
5) Exécuter ta Macro méthode 2 :
- Dans le code de la Macro, fais F5. Attention, si tu es dans un autre "Sub xxx()" c'est xxx qui s'exécutera.
Ayé, tu es officiellement développeur en VBA.​
6) Ce qui est dans la Macro :
Là on s'en moque. Des lignes de code qui te permettent de comprendre le comportement de telle ou telle fonction. Tu enregistres, tu arrêtes, tu vas voir, tu n'as plus qu'à comprendre et t'approprier le savoir. C'est un bon outil pour les analphabètes comme moi qui ne savent pas lire les docs de Micro$oft : on enregistre, on regarde comment ça marche.
7) Inutile de fermer la fenêtre des Macros :
- En effet, le classeur Excel a sa fenêtre, les Macros ont la leur, on peut laisser les deux ouvertes sans soucis.
- La sauvegarde de l'un sauvegardera l'autre. Normal, la Macro est "dans" le fichier Excel (on verra cela plus loin).
Bref notre Macro est faite, on la comprend à peu près et o, sait se balader dedans.

Attention : Ce qui suit peut dépendre de la politique de ta boite, donc demande avant de faire des choses interdites. Cependant, mes conseils font que la Macro sera confinée dans ton fichier (car on peut aussi faire des Macros générales) ce qui ne devrait pas poser problème. Mais demande quand même !

8) Enregistrer notre classeur Excel :
- Ctrl-S ou Enregistrer ou Enregistrer sous, comme tu veux.
- Excel t'avertit que "les fonctionnalités suivantes ... pour enregistrer un fichier avec ces fonctionnalités, cliquez sur Non puis... prenant en charge les macros dans la liste Types de Fichiers".
- Là on clique non (sinon adieu les Macros). On nomme son fichier comme dans toute sauvegarde MAIS dans le type, on choisit "Classeur Excel prenant en charge les Macros --> .xlsm"
- Enregistrer.
- Confidentialité, tout ça... clique sur "Ok"
- Il est possible qu'il te pose une autre question sur la confidentialité. En ce qui ME concerne (Excel 2003, travail chez moi, pas de responsable au dessus de ma tête ou de règles à suivre) :
- Touche Windows en haut à gauche / Options Excel / Centre de Gestion de la confidentialité / Paramètres su centre de gestion de la confidentialité / Options de confidentialité / décocher 'Supprimer les informations personnelles ..."
- Là, cela fonctionne.
9) Enregistrer les Macros : Normalement il n'y a ensuite qu'à faire Ctrl+S pour sauvegarder Macros et feuille Excel.

Voilà. Tu t'entraines un peu ? La suite sera plus simple, on appliquera le code (sur une copie de ton fichier) et on s'expliquera sur son contenu (au code). ET on testera :D
 

svoglimacci

check memory failed but no bug detected
Quoi j'ai fait ?
C'est moi qui ai mis ces jolis yeux ?
 

svoglimacci

check memory failed but no bug detected
1) Essaie de mumuser avec les macros,
2) Regarde le code
3 Pose des questions sur tout.

A ton service, cela me fait bien plaisir de me replonger dans ce genre de choses, même si je suis très laborieux. Et j'ai le temps pour le faire.
 

magellan

Modérâleur
Staff
1) Essaie de mumuser avec les macros,
2) Regarde le code
3 Pose des questions sur tout.

A ton service, cela me fait bien plaisir de me replonger dans ce genre de choses, même si je suis très laborieux. Et j'ai le temps pour le faire.
L'essentiel est de partager le savoir, c'est notre but ici ;)
 

svoglimacci

check memory failed but no bug detected
Petite question @magellan :
Je structure beaucoup. Pour les opérations répétées bien entendu (elles ont en général peu de paramètres) mais aussi pour découper le code, pour que ma fonction principale ne fasse pas 200 lignes. Pour que la fonction principale devienne par exemple : Init, Copie, Trie, Dispatche.
Et là, le nombre de paramètres est conséquent, 15 par exemple. Et déclarer ces paramètres en entrée de la fonction prend de la place, alourdit la lisibilité (surtout en VBA) ...
Du coup, une question se pose : je n'aime pas du tout déclarer en variables globales des variables non globales mais franchement, y aurait-il dans ce cas de quoi s'en vouloir ?
[Edit]Surtout que ces variables servent vraiment un peu partout :D
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 098
Messages
6 717 060
Membres
1 586 286
Dernier membre
petitangebleu1977
Partager cette page
Haut