Conserver l’historique des modifications

Est-ce qu'on peut appliquer un tri automatique avant la fermeture du classeur ?

oui, à ajouter dans

Private Sub Workbook_BeforeClose(Cancel As Boolean) 'masque toutes les feuilles avant de fermer

' tri de la BDD

Dim i As Integer
    Sheets("Accueil").Visible = True
    Sheets("Accueil").Select
    For i = 1 To Sheets.Count
        If Sheets(i).Name <> "Accueil" Then Sheets(i).Visible = xlVeryHidden
    Next
End Sub

quel tri veux-tu ?

Donc il me reste à voir l'incidence du tri sur la feuille log ... un peu de réflexion s'impose !

Bonsoir,

pour le "soucis" de la stagnation de la cellule "validée" vous pouvez ajouter la sélection de la cellule d'en-dessous comme ceci, juste avant la fin du code :

    ActiveCell.Offset(1).Activate

@ bientôt

LouReeD

ou alors, car tu as pu aller vers la droite, vers le bas , ou ailleurs, mets une mémoire de la sélection au début de la macro

Private Sub Workbook_Sheetchange(ByVal feuille As Object, ByVal cible As Range)
    Dim memoire As Range

' ...

    Set memoire = Selection

' ...

    memoire.Select

fin:
    Application.EnableEvents = True
    If Err Then MsgBox "Erreur #" & Err.Number & " !"

End Sub

Bonjour Steelson,

Lorsqu'une nouvelle ligne est saisie dans la base de données, seul ce qui a été saisi dans la colonne "Adresse" sera reporté ; quant à ce qui est saisi dans la colonne "Destination", il n'est pas reporté dans la feuille "log".

Même si j'inverse la saisie et que je commence par la colonne B (Adresse), cette dernière ne sera pas copiée, contrairement à la colonne A (destinataire) qui le sera.

Je pense savoir où se situe le problème, mais malheureusement je n'ai pas la solution:

    Application.EnableEvents = False
    ReDim avant(1 To cible.Rows.Count, 1 To cible.Columns.Count)
    ReDim apres(1 To cible.Rows.Count, 1 To cible.Columns.Count)
    Application.Undo
    For lig = 1 To UBound(avant)
        For col = 1 To UBound(avant, 2)
            avant(lig, col) = cible.Cells(1, 1).Offset(lig - 1, col - 1).FormulaLocal
        Next
    Next
    Application.Undo
    For lig = 1 To UBound(apres)
        For col = 1 To UBound(apres, 2)
            apres(lig, col) = cible.Cells(1, 1).Offset(lig - 1, col - 1).FormulaLocal
        Next
    Next
MsgBox cible.Address
    For lig = 1 To cible.Rows.Count
        For col = 1 To cible.Columns.Count
            If avant(lig, col) <> apres(lig, col) Then
                With Sheets("Log").ListObjects(1)
                    .ListRows.Add
                    i = .ListRows.Count
                    With .DataBodyRange
                        .Cells(i, 1) = Now
                        .Cells(i, 2) = feuille.Name
                        .Cells(i, 3) = feuille.Cells(2, cible.Cells(1, 1).Offset(lig - 1, col - 1).Column)
                        .Cells(i, 4) = cible.Cells(1, 1).Offset(lig - 1, col - 1).Address
                        .Cells(i, 6) = "'" & avant(lig, col)
                        .Cells(i, 7) = "'" & apres(lig, col)
                        .Cells(i, 8) = utilisateur    'Environ("username")
                    End With
                End With
            End If
        Next
    Next
    ActiveCell.Offset(1).Activate
fin:
    Application.EnableEvents = True
    If Err Then MsgBox "Erreur #" & Err.Number & " !"

End Sub

Le premier Application.Undo ne fonctionne pas. Donc si je saisi, par exemple W1, cette partie du code retourne la chaine "W1" au lieu d'une chaîne vide "" (vide) :

    Application.EnableEvents = False
    ReDim avant(1 To cible.Rows.Count, 1 To cible.Columns.Count)
    ReDim apres(1 To cible.Rows.Count, 1 To cible.Columns.Count)
    Application.Undo
    For lig = 1 To UBound(avant)
        For col = 1 To UBound(avant, 2)
            avant(lig, col) = cible.Cells(1, 1).Offset(lig - 1, col - 1).FormulaLocal
        Next
    Next

Ce qui veut dire :

avant(lig, col) = "W1"

Par conséquent, cette condition ne sera pas satisfaite :

If avant(lig, col) <> apres(lig, col) Then

et il n'y aura donc pas de copie de la valeur saisie vers la feuille "Log".

au passage, je ne sais pas ce qui se passe si on supprime une ligne ...

Il est nécessaire de transférer les valeurs de la ligne dans "Log" avant la suppression.

/!\ il faut protéger ton code VBA

D'accord.

quel tri veux-tu ?

Tri de la BDD.

Par défaut, le log est déjà trié par date.

Je ne sais, pour quelle raison, mais la page d’accueil, pour se connecter au classeur, ne s'affiche pas à l'ouverture du classeur ?

5log-v004.xlsm (34.94 Ko)

Même si j'inverse la saisie et que je commence par la colonne B (Adresse), cette dernière ne sera pas copiée, contrairement à la colonne A (destinataire) qui le sera.

Je pense savoir où se situe le problème, mais malheureusement je n'ai pas la solution:

Le premier Application.Undo ne fonctionne pas. Donc si je saisi, par exemple W1, cette partie du code retourne la chaine "W1" au lieu d'une chaîne vide "" (vide) :

Merci pour cette analyse ... et je crois que c'est tout simplement parce que les données sont structurées en tableau (ce qui est très bien en soi) et que le fait d'ajouter une ligne en fin de tableau fait faire à excel 2 actions : l'ajout de la donnée et l'ajout d'une ligne du tableau. Du coup le undo n'efface que la dernière action.

Je vais réfléchir, mais je pense que là on touche aux limites d'un tel système. Il faudrait ajouter dans le code le contrôle de la taille du tableau.


- Je souhaite mettre les cellules modifiées en lien dans le code vba, car le tri dans la feuille l'affecte, comme tu l'as mentionné.

Après plusieurs essais, le fait de mettre une formule ne fonctionne pas avec le tri, la formule reste accrochée à la même adresse. Donc la seule solution serait de mettre un identifiant unique de ligne dans la ase de donnée.


Du coup, on a 2 alternatives : la 2cv ou la Rolls

- soit on s'en tient à quelque chose de très simple sans undo : on a juste l'info ajoutée ... on peut même facilement mettre toute la ligne du tableau où cette info est ajoutée ce qui permet quand même de retrouver par analyse de l'ensemble du log comment la base de données a évolué

- soit on poursuit le développement en conservant l'info avant/après et le lien hypertexte, mais qui impose d'avoir un identifiant de ligne et de réussir à piéger les actions induites par excel (comme ici l'augmentation des lignes du tableau

- enfin on peut aussi imaginer que les personnes n'accèdent pas directement à la BdD mais le font via une transaction (je n'aime pas les userform mais on peut facilement le faire avec un onglet dédié au formulaire)

Bonjour,

- soit on s'en tient à quelque chose de très simple sans undo : on a juste l'info ajoutée ... on peut même facilement mettre toute la ligne du tableau où cette info est ajoutée ce qui permet quand même de retrouver par analyse de l'ensemble du log comment la base de données a évolué

- soit on poursuit le développement en conservant l'info avant/après et le lien hypertexte, mais qui impose d'avoir un identifiant de ligne et de réussir à piéger les actions induites par excel (comme ici l'augmentation des lignes du tableau

- enfin on peut aussi imaginer que les personnes n'accèdent pas directement à la BdD mais le font via une transaction (je n'aime pas les userform mais on peut facilement le faire avec un onglet dédié au formulaire)

dans quelle voie souhaites-tu poursuivre ? je pense que la dernière est la plus pertinente, ensuite la première plus simple.

Bonjour Steelson,

dans quelle voie souhaites-tu poursuivre ? je pense que la dernière est la plus pertinente, ensuite la première plus simple.

Je pense que la seconde me va bien !

Merci.

Bonjour,

Manque-t-il quelque chose ?

Oui, un moment d'intense réflexion ... mais je vais m'y mettre, c'est la solution la plus complexe.

Alors prends le temps possible

J'ai repris les bases car en effet, en cas de tableau, excel fait une opération induite s'il y a une colonne ou une ligne en plus.

Je peux donc maintenant repérer s'il s'agit d'une extension du tableau ou d'une modification d'une donnée.

Attention, je reprécise que pour permettre le tri en ayant aussi les liens, il faudra une référence unique de ligne dans le tableau.

Il faudra aussi que je traite la modification de l'en-tête.

Bonjour,

Attention, je reprécise que pour permettre le tri en ayant aussi les liens, il faudra une référence unique de ligne dans le tableau.

Je pense que le tri est nécessaire sur la feuille BDD et non pas sur la feuille "Log" (historique des modifications).

Parce que dans la feuille BDD, il peut y avoir une utilité lors de la suppression d'une ligne entière de la feuille, afin de ne pas laisser de ligne vide au milieu du tableau, ou simplement pour trier et organiser les données existantes.

Il faudra aussi que je traite la modification de l'en-tête.

Tu veux dire, ignorer les modifications apportées aux en-têtes de colonne?

A tester intensivement ...

Toutes les modifications de la base de données sont tracées : déplacement, agrandissement, diminution colonnes et lignes, et modifications.

Le tri est possible et le lien reste pointé vers la donnée.

Attention aux modifications des identifiants, tout à fait possible, mais le lien peut en être perturbé pour les anciennes modifications puisque c'est sur cet identifiant que je base le lien.

Private Sub Worksheet_change(ByVal cible As Range)
Dim avant, apres, id As Object, log As Worksheet
Dim memoire As Range, plage As Range

On Error GoTo fin

    ' pas de modification d'une ligne entière ou d'une colonne entière
    If cible.Columns.Count = Columns.Count Or cible.Rows.Count = Rows.Count Then
        Application.EnableEvents = False
        Application.Undo
        Application.EnableEvents = True
        MsgBox "Impossible d'agir sur une ligne ou une colonne complète !"
        Exit Sub
    End If

    If Not Intersect(cible, ActiveSheet.ListObjects(1).DataBodyRange) Is Nothing Then

        Set memoire = Selection
        Set log = Sheets("Log")

        ' contrôle des identifiants uniques
        apres = ActiveSheet.ListObjects(1).ListColumns("ID").DataBodyRange
        Set id = CreateObject("Scripting.Dictionary")
        For i = 1 To UBound(apres)
            If apres(i, 1) = "" Then
                MsgBox "Manque identifiant !"
                Application.EnableEvents = False
                    Application.Undo
                Application.EnableEvents = True
                Exit Sub
            End If
            If id.exists(apres(i, 1)) Then
                MsgBox "Les identifiants doivent être uniques !"
                Application.EnableEvents = False
                    Application.Undo
                Application.EnableEvents = True
                Exit Sub
            End If
            id(apres(i, 1)) = ""
        Next

        ' traitement des modifications
        Application.EnableEvents = False
        With ActiveSheet.ListObjects(1)

            Set plage = Intersect(cible, .DataBodyRange)
            apres = .DataBodyRange
            Application.Undo
            avant = .DataBodyRange
            Application.Undo

            ' cas standard
            n = plage.Cells.Count
            If n > 0 Then
                For Each Cel In plage
                    i = Cel.Row - .HeaderRowRange.Cells(1, 1).Row
                    j = Cel.Column - .HeaderRowRange.Cells(1, 1).Column + 1
                    ' cas de changement de taille du tableau
                    If i <= UBound(avant) And i <= UBound(apres) And j <= UBound(avant, 2) And j <= UBound(apres, 2) Then
                        If avant(i, j) <> apres(i, j) Then
                            loguer .DataBodyRange(i, 1), j, avant(i, j), apres(i, j), ""
                        End If
                    End If
                Next
            End If

            ' taille du tableau
            If UBound(apres) > UBound(avant) Then
                loguer "", "", "", "", "La BdD a augmenté de " & -UBound(avant) + UBound(apres) & " ligne(s)"
                For i = UBound(avant) + 1 To UBound(apres)
                    For j = 1 To UBound(apres, 2)
                        If apres(i, j) <> "" Then
                            loguer .DataBodyRange(i, 1), j, "", apres(i, j), ""
                        End If
                    Next
                Next
            End If

            If UBound(apres) < UBound(avant) Then
                loguer "", "", "", "", "La BdD a diminué de " & UBound(avant) - UBound(apres) & " ligne(s)"
            End If

            If UBound(apres, 2) > UBound(avant, 2) Then
                loguer "", "", "", "", "La BdD s'est élargie de " & -UBound(avant, 2) + UBound(apres, 2) & " colonne(s)"
                For i = 1 To UBound(apres)
                    For j = UBound(avant, 2) + 1 To UBound(apres, 2)
                        If apres(i, j) <> "" Then
                            loguer .DataBodyRange(i, 1), j, "", apres(i, j), ""
                        End If
                    Next
                Next
            End If

            If UBound(apres, 2) < UBound(avant, 2) Then
                loguer "", "", "", "", "La BdD s'est rétrécie de " & UBound(avant, 2) - UBound(apres, 2) & " colonne(s)"
            End If

        End With
        Application.EnableEvents = True
    End If

    If Not memoire Is Nothing Then memoire.Select
fin:
    Application.EnableEvents = True
    If Err Then MsgBox "Erreur #" & Err.Number & " !"

End Sub

Sub loguer(id, colonne, avant, apres, commentaire)
    'Date & heure    ID  Ligne   Colonne Avant   Après   Commentaire Lien vers … Auteur
    With Sheets("Log").ListObjects(1)
        .ListRows.Add
        ligne = .ListRows.Count
        With .DataBodyRange
            .Cells(ligne, 1) = Now
            .Cells(ligne, 2) = id
            .Cells(ligne, 4) = colonne
            .Cells(ligne, 5) = avant
            .Cells(ligne, 6) = apres
            .Cells(ligne, 7) = commentaire
            .Cells(ligne, 9) = utilisateur
            .Cells(ligne, 10) = Environ("username")
        End With
    End With
End Sub

Merci Steelson, je vais faire des tests.

Bonjour,

Lors du premier test de connexion au classeur, et en cas d'utilisateur valide et un mot de passe incorrect, une erreur sera déclenchée sur la ligne:

Sheets("Accueil").Visible = False

dans la procédure Ouvrir().

J'espère également que la demande d'autorisation d'accès sera obligatoire lors de l'ouverture du classeur.

Enlève cette instruction qui a priori ne sert à rien.

J'espère également que la demande d'autorisation d'accès sera obligatoire lors de l'ouverture du classeur.

avec la macro de fermeture qui masque en xlveryhidden oui, on revient sur accueil

@atlas,

si pas de nouveau problème, n'oublie pas de clore le fil de discussion en cliquant sur

Bonjour,

Je n'ai pas encore terminé les tests.

Bonjour,

  • J'ai amélioré l'authentification et l'accès au classeur.
  • J'ai du mal à ajouter un commentaire approprié lors de la création, de la modification ou de la suppression.
  • Pour supprimer une ligne, je procède comme suit :
    Clic gauche, puis, dans le menu contextuel, choisir "Supprimez une ligne du tableau" (la suppression avec la touche Suppr provoque une erreur !)
    "Manque identifiant !"
  • La date ajoutée dans la feuille "Log" est toujours sous forme américaine, mais dans le code elle est sous forme française.
  • L'erreur #9 , apparaît toujours lors de l'authentification dans la feuille "Accueil".
  • Il y a d'autres erreurs que je n'ai pas enregistrées.

Voilà tout pour le moment.

Merci.

Rechercher des sujets similaires à "conserver historique modifications"