I have a workbook where several people will make an entry during the week.
Every entry is on its own row. Now i would like to have excel automatic insert the "Windows log-in name" of the user who made the entry, lets say on column K in that speciffic row.
I have found and tried to use the following script.
Function GetName(Optional NameType As String) As String
'Function purpose: To return the following names:
'Defaults to MS Office username if no parameter entered
'
'Formula should be entered as =GetName([param])
'
'For Name of Type Enter Text OR Enter #
'MS Office User Name "Office" 1 (or leave blank)
'Windows User Name "Windows" 2
'Computer Name "Computer" 3
'Force application to recalculate when necessary. If this
'function is only called from other VBA procedures, this
'section can be eliminated. (Req'd for cell use)
Application.Volatile
'Set value to Office if no parameter entered
If Len(NameType) = 0 Then NameType = "OFFICE"
'Identify parameter, assign result to GetName, and return
'error if invalid
Select Case UCase(NameType)
Case Is = "OFFICE", "1"
GetName = Application.UserName
Exit Function
Case Is = "WINDOWS", "2"
GetName = Environ("UserName")
Exit Function
Case Is = "COMPUTER", "3"
GetName = Environ("ComputerName")
Exit Function
Case Else
GetName = CVErr(xlErrValue)
End Select
End Function
I would then call GetName(2) from the relevant cell, but when a new user enter a new entry, all the previous user names are set to the new user.
Any help on this problem, are welcome
Thx
Taz
UPDATE:
Thx for the answers, they helped me get a bit further in solving my problem.
I have now come up with this code, but theres some strange things going on sometimes.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim User As String
User = Environ("UserName")
If Not Intersect(Target, Range("a7:a30")) Is Nothing Then
ActiveSheet.Unprotect
Application.EnableEvents = False
ActiveCell.Offset(0, 10).Value = User
Application.EnableEvents = True
ActiveSheet.Protect
End If
End Sub
This is pretty much working like it should, however it is possible to kinda fool the offset, so it will sometimes write the username only 9 offsets away.
Is it possible to change the code so i can write to a cell in a fixed column, on that row that is active ?
/Taz
With the help of this forum, i was able to make excel do what i wanted, i post the code here.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim row, col, user, ColCell As String
user = Environ("UserName")
col = "G" 'Set the Column ?
If Not Intersect(Target, Range("B7:B30")) Is Nothing Then
ActiveSheet.Unprotect
Application.EnableEvents = False
row = Split(Selection.Address, "$")(2) 'Get row number
ColCell = col & row
Range(ColCell).Value = user
'MsgBox "ColCell is : " & ColCell
Application.EnableEvents = True
ActiveSheet.Protect
End If
End Sub
But i have one question still, i have alot of sheets in my workbook, do i need to put this code in all the sheets, or is there a way that i can avoid this, and only have the code run from one place ?
Related
I have this code but it only work for my first row.
It is suppose to look if the checkbox on B, C or D is checked, and if so, a date + username will automaticaly fill in F and G.
here is a picture of my table:
This is what my code looks like:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("B2") Or Range("C2") Or Range("D2") = True Then
Range("G2").Value = Environ("Username")
Range("F2").Value = Date
Else
Range("F2:G2").ClearContents
End If
End Sub
Enter this code in a regular module, select all your checkboxes and right-click >> assign macro then choose ReviewRows.
This will run the check whenever a checkbox is clicked - a bit of overhead since all rows will be checked, but should not be a big deal.
Sub ReviewRows()
Dim n As Long
For n = 1 To 100 'for example
With Sheet1.Rows(n)
If Application.CountIf(.Cells(2).Resize(1, 3), "TRUE") > 0 Then
If Len(.Cells(6).Value) = 0 Then 'only enter if currently empty?
.Cells(6) = Date
.Cells(7) = Environ("Username")
End If
Else
.Cells(6).Resize(1, 2).ClearContents
End If
End With
Next n
End Sub
If you want to be more precise then Application.Caller will give you the name of the checkbox which was clicked, and you can use that to find the appropriate row to check via the linkedCell.
Sub ReviewRows()
Dim n As Long, shp As CheckBox, c As Range, ws As Worksheet
Set ws = ActiveSheet
On Error Resume Next 'ignore error in case calling object is not a checkbox
Set shp = ActiveSheet.CheckBoxes(Application.Caller) 'get the clicked checkbox
On Error GoTo 0 'stop ignoring errors
If Not shp Is Nothing Then 'got a checkbox ?
If shp.LinkedCell <> "" Then 'does it have a linked cell ?
With ws.Range(shp.LinkedCell).EntireRow
If Application.CountIf(.Cells(2).Resize(1, 3), "TRUE") > 0 Then
If Len(.Cells(6).Value) = 0 Then 'only enter if currently empty?
.Cells(6) = Date
.Cells(7) = Environ("Username")
End If
Else
.Cells(6).Resize(1, 2).ClearContents
End If
End With
End If 'has linked cell
End If 'was a checkbox
End Sub
However this appraoch is sensitive to the exact positioning of your checkbox
You have a long way to go!
Unfortunately, If Range("B2") Or Range("C2") Or Range("D2") = True Then is beyond repair. In fact, your entire concept is.
Start with the concept: Technically speaking, checkboxes aren't on the worksheet. They are on a layer that is superimposed over the worksheet. They don't cause a worksheet event, nor are they responding to worksheet events. The good thing is that they have their own.
If Range("B2") Or Range("C2") Or Range("D2") = True Then conflates Range with Range.Value. One is an object (the cell), the other one of the object's properties. So, to insert sense into your syntax it would have to read, like, If Range("B2").Value = True Or Range("C2").Value = True Or Range("D2").Value = True Then. However this won't work because the trigger is wrong. The Worksheet_Change event won't fire when when a checkbox changes a cell's value, and the SelectionChange event is far too common to let it run indiscriminately in the hope of sometimes being right (like the broken clock that shows the correct time twice a day).
The answer, therefore is to capture the checkbox's click event.
Private Sub CheckBox1_Click()
If CheckBox1.Value = vbTrue Then
MsgBox "Clicked"
End If
End Sub
Whatever you want to do when the checkbox is checked must be done where it now shows a MsgBox. You can also take action when it is being unchecked.
I need to loop the below function to retrieve email address based on LAN IDs. Copied below code from an existing spreadsheet.
Requirement: Retrieve "Outlook email address" (Column A) based on "User LAN ID" (Column D).
fldUserLogonID is no longer 1 cell (it changes weekly) - depends how many "User LAN ID" comes through
Code below:
Private Sub CommandButton1_Click()
Dim user As String
Dim fldUserLogonID As String
If (ActiveSheet.range("fldUserLogonID").Value = "") Then
MsgBox "Please enter the User's Lan ID and then click on Populate Button"
Else
Call Module5.username1
Call Module5.FindUser
End If
Application.EnableEvents = True
Application.EnableEvents = False
If ActiveSheet.Range("User_ID").Value = "" Then
End Sub
Let's assume that the 500-values are listed in the range A1:A500.
Here is one way of looping through all of the values in the column:
Private Sub CommandButton1_Click()
Dim user As String
Dim fldUserLogonID As String
For i = 1 To 500
If (ActiveSheet.range("A" & I).Value = "") Then
MsgBox "Missing value at cell A" & I
'You may want to exit the loop when you encounter the first empty cell
'Otherwise, continue to the next cell below
Exit For
Else
Call Module5.username1
Call Module5.FindUser
End If
Next
Application.EnableEvents = True
End Sub
I'm creating a quiz.
Questions on one worksheet and the answers on another.
When a question is answered another field with this formula
=IF(C5="","",IF(C5=Answers!A5,"Correct","Incorrect"))
tells the person if the answer is correct or incorrect.
I am using data validation with dropdown lists so they can only choose true/false, (a, b, c, d) etc.
Is there a way to lock in a selected answer, until a master reset button is pressed?
For example,
Question is in A1
The possible answers are in the form of a dropdown menu in B1.
Sometimes the answer is in the form of a true false, sometime it is in the form of a multiple choice. In the example of true false, if the person puts in true, c3 will say correct or if they put false, then incorrect.
As it is now, the person can switch back and forth as much as they want.
I am looking to make it so once an answer is selected, they cannot change it.
You can use Sheet Protection, combined with Range Locking and a Change event.
Put this code in the relevant Worksheet Module. Adjust the Private constants to suit your needs.
Option Explicit
' Reference the cells that your users may enter data into
Private Const DataCells As String = "J1,J3,J5"
Private Const PW As String = "password"
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cl As Range
Dim DataRange As Range
Set DataRange = Me.Range(DataCells)
'Loop thru changed cells
For Each cl In Target.Cells
'If changed cell is in the DataCells range and is not blank, lock it
If Not Application.Intersect(cl, DataRange) Is Nothing Then
If Not IsEmpty(cl) Then
Me.Unprotect PW
Target.Locked = True
Me.Protect PW
End If
End If
Next
End Sub
'Re-enable data entry to all DataCells
Sub MasterReset()
'Unlock the sheet, prompt for password
Me.Unprotect
'Unlock the cells
Me.Range(DataCells).Locked = False
'Optional, clear DataCells
Me.Range(DataCells).ClearContents
'Lock the sheet again
Me.Protect PW
End Sub
This works pretty good:
In the "This Workbook" module, insert the code:
Private Sub Workbook_Open()
Sheet1.Protect userinterfaceonly:=True 'allows macros to run
Sheet1.Range("A1:A20").Locked = False 'replace this range with the range the user deals with.
End Sub
In the sheet module that the user will be interacting with, add this code:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Locked = True Then Exit Sub
If Target.Locked = False Then
If Target.Value = "" Then Exit Sub
If Target.Value <> "" Then Target.Locked = True
End If
End Sub
That should take care of things for you!
I have the following macro to execute a before_print check. There are certain fields that must be populated in order for the user to print the template. The macro works fine but the message box will appear as many times as there is a blank field. Meaning if 3 of the 5 fields are blank then the message box will appear (3) times which means the user will have to close each message box.
Question: I would like to see what I would need to modify so that the message box only appears once regardless of how many of the required fields are left blank. All I care about is if any of the fields are blank to show the message box and cancel the print job.
Private Sub Workbook_BeforePrint(Cancel As Boolean)
If ActiveSheet.Name = "Template" Then
Dim jRange As Range
Set jRange = Sheets("Template").Range("C4,C5,B9,B10,B11")
For Each cell In jRange
If cell.Value = "" Then
MsgBox ("Cannot leave Invoice Number, Invoice Date or Vendor Name blank."), vbCritical
Cancel = True
End If
Next
End If
End Sub
Revised macro after assistance:
Private Sub Workbook_BeforePrint(Cancel As Boolean)
If ActiveSheet.Name = "Template" Then
Dim jRange As Range
Set jRange = Sheets("Template").Range("C4,C5,B9,B8,B10")
Dim ReqFields As Boolean
For Each cell In jRange
If cell.Value = "" Then
ReqFields = True
End If
Next
If ReqFields Then
MsgBox ("Cannot leave Invoice Number, Invoice Date or Vendor Name blank."), vbCritical
Cancel = True
End If
End If
End Sub
Instead of showing a MsgBox each time through the loop, set a Boolean variable to "True". After the loop, if the Boolean is true, then you know that there was at least one field blank. At that point, show your error message and set "Cancel = True".
This is the first time I'm working with Macros.
I've created a dropdown in B2 with a "Yes" and "No" options.
If User selects "Yes", Row 10 Shows / Row 11 Hides
If User Selects "No", Row 11 Shows / Row 10 Hides
I used this code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$2" Then
If Range("B2") = Yes Then
ActiveSheet.Rows("10:10").EntireRow.Hidden = False
ActiveSheet.Rows("11:11").EntireRow.Hidden = True
ElseIf Range("B2") = No Then
ActiveSheet.Rows("10:10").EntireRow.Hidden = True
ActiveSheet.Rows("11:11").EntireRow.Hidden = False
End If
End If
End Sub
I Created a new Module in Sheet1, and put it there. I saved the excel as a Macro Enabled Tamplate, however nothing happens when I change the dropdown.
Thanks for your help!
Do yourself a huge favor and get in the habit of writing Option Explicit at the top of every module of VBA code you write.
I have added comments as well explaining your needed revisions.
'this requires you to dimension all variables
'when you used '= yes' VBA thought you were saying
'the same as, = aVariable
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$2" Then
If Range("B2").Value = "Yes" Then
'You can reference the row directly on the same sheet
'and do not need ActiveSheet
Rows("10:10").EntireRow.Hidden = False
Rows("11:11").EntireRow.Hidden = True
ElseIf Range("B2").Value = "No" Then
Rows("10:10").EntireRow.Hidden = True
Rows("11:11").EntireRow.Hidden = False
End If
End If
End Sub
Also be aware this is only using "Yes" - using "yes" or "YES" will cause problems. You can use the UCase method as follows if you want to avoid these situations in the future:
If UCase(Range("B2").Value) = "YES" Then
If Range("B2") = "Yes" Then
and similarly with the "No " option