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 ?
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.
@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.