It will be a lot more user friendly if the users only needs to enter their details on opening the workbook.
Further it is quite easy to do, but there is some work involved in order to make it reasonable fool proof.
In essence:
If a user does not enable the macros, then the workbook should be locked for writing, with a message mentioning this
Each worksheet will need to contain the macro in its module.
A hidden empty template sheet with the macro is required, in case a user adds a new sheet
Weakness:
A savvy excel user can always break the system
A user can enter anyone's name in the entry box
If more users use only one PC then you are stuck with asking each time, although this could be improved by not asking when the changes are done within say a minute of each other.
Or the users need to close Excel when they are finished.
Improvements:
If the users all use their own PC, then the user initials can be extracted from Excel, or from Windows.
OK here goes:
- Add a new sheet to the workbook
- Name it 'UserLog'
- add the following in the sheet
4. You need to add some named ranges:
A5: Log
E3: CurrentUser
G3: DateTime
5. Add a new sheet to the workbook
6. Name it 'Warning'
7. Add some text to it with appropriate font size and colours to tell the user that macro's need to be enabled in order to make changes
8. Add a new sheet to the workbook
9. Name it 'NewShtTemplate'
10. Right click on the name tab and select 'View Code'
11. Paste the following code in the VBA window that has opened.
VBA Code:
Option Explicit
Const iDelay As Integer = 1
Dim vPreviousVal As Variant
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Cells.Count = 1 Then
vPreviousVal = Target.Value
Else
vPreviousVal = "Unknown"
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim sN As String
Dim vL(1 To 7) As Variant, vU(1 To 3) As Variant
vL(1) = Sheets("UserLog").Range("CurrentUser")
vL(2) = Sheets("UserLog").Range("CurrentUser").Offset(0, 1)
If Now() > Sheets("UserLog").Range("DateTime") + iDelay / (24 * 60) Then
GetName:
sN = InputBox("Enter First/Last name (separated by / (slash))", _
Title:="User name", Default:=vL(1) & "/" & vL(2))
If Len(sN) And sN Like "*/*" Then
vL(1) = Split(sN, "/")(0)
vL(2) = Split(sN, "/")(1)
vU(1) = vL(1)
vU(2) = vL(2)
vU(3) = Now()
Sheets("UserLog").Range("CurrentUser").Resize(1, 3).Value = vU
Else
GoTo GetName
End If
Else
vU(3) = Now()
End If
vL(3) = Me.Name
vL(4) = Target.Address
vL(5) = vPreviousVal
vL(6) = Target.Value
vL(7) = vU(3)
vU(3) = vL(7)
With Sheets("UserLog").Range("Log").CurrentRegion
.Offset(.Rows.Count, 0).Resize(1, 7).Value = vL
End With
End Sub
12. While you are in the VBA editor, in the left top window, you will see the list of sheets in the workbook and 'ThisWorkbook'
Double click on ThisWorkbook to open the workbook module.
Now paste the following code in the window.
VBA Code:
Option Explicit
Const sWBPW As String = "MyPW"
Dim wsActive As Worksheet
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Dim shT As Worksheet
Dim sN As String
Application.ScreenUpdating = False
With Sheets("NewShtTemplate")
.Visible = xlSheetVisible
.Copy after:=Sh
Set shT = ActiveSheet
.Visible = xlSheetHidden
End With
sN = Sh.Name
Application.DisplayAlerts = False
Sh.Delete
Application.DisplayAlerts = True
shT.Name = sN
Application.ScreenUpdating = True
End Sub
Private Sub Workbook_Open()
Dim bB As Boolean
Workbook_AfterSave b
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim shSh As Worksheet
Set wsActive = ActiveSheet
For Each shSh In Me.Sheets
If shSh.ProtectContents = False Then
shSh.Protect sWBPW
End If
Next shSh
With Sheets("Warning")
.Visible = xlSheetVisible
.Activate
End With
End Sub
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Dim shSh As Worksheet
Const sDontUnprotect As String = "Sheet1;Warning"
For Each shSh In Me.Sheets
If Not "*;" & shSh.Name & ";*" Like sDontUnprotect Then
shSh.Unprotect sWBPW
End If
Next shSh
Sheets("Warning").Visible = xlSheetHidden
If Not wsActive Is Nothing Then wsActive.Activate
End Sub