Locking specific cells in excel VBA - vba

I have a macro I am working on currently.
Purpose
The objective in that once there is a value in column L , i need cells in the revelant row to lock. However this should not lock the whole worksheet, just the cells.
Code
Below is the code i have been been playing with. I am trying amend the code so to achieve my purpose above.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Row = 1 Then
If Target.Column = 3 Or Target.Column = 5 Then
Beep
Cells(Target.Row, Target.Column).Offset(0, 1).Select
End If
End If
End Sub
Example
The cells which will be locked are in yellow, if there is a date in column L
The reason why locking the whole worksheet wont overcome the problem is because any additional users will not be able to input there own data into the worksheet.

Merely locking the cells has no effect unless you protect the sheet. Firstly, unlock all the cells in the sheet, and then try this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 12 Or Target.Row = 1 Then Exit Sub
Range(Cells(Target.Row, 2), Cells(Target.Row, 11)).Locked = True
ActiveSheet.Protect
End Sub

Change the password in the first line of code with the actual password to unprotect the sheet.
Const PW As String = "123"
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.CountLarge > 1 Then Exit Sub
Dim r As Long
If Target.Column = 12 And Target.Row > 1 Then
ActiveSheet.Unprotect Password:=PW
r = Target.Row
If Target <> "" Then
Range("B" & r & ":K" & r).Locked = True
Else
Range("B" & r & ":K" & r).Locked = False
End If
ActiveSheet.Protect Password:=PW
End If
End Sub

Related

Applying formula with changing row position to VBA

I have a worksheet that count the number of days between a designated date in column A and today() date in column B which stops the counting in column C if there is the word "CLOSED" in Column D. But I have a problem where I want to reapply back the formula if column D is blank again. I'm not sure how to make the column rows appear at the right place for the formula to be used
Below is the VBA code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells = "CLOSED" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row) = Range("C" & Target.Row).Value
Range("B" & Target.Row) = Range("B" & Target.Row).Value
Application.EnableEvents = True
End If
End If
If Target.Cells = "" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
Range("B" & Target.Row).Value = "=Today()"
Application.EnableEvents = True
End If
End If
End Sub
I would really appreciate it if someone can teach me how to properly change the code:
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
as I am still new to VBA programming and would like to learn from my mistake
Below will do what you want. Learn that you can use the .FormulaR1C1 similar to effect of filling up/down. The potential issues including more than 1 cells is changed. Have not put checks if the cells in columns A/B are empty.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim oRng As Range
Application.EnableEvents = False
For Each oRng In Target.Cells
With oRng
If .Column = 4 Then
If UCase(Trim(.Value)) = "CLOSED" Then
.Worksheet.Cells(.Row, "B").Value = .Worksheet.Cells(.Row, "B").Value
.Worksheet.Cells(.Row, "C").Value = .Worksheet.Cells(.Row, "C").Value
ElseIf Len(Trim(.Value)) = 0 Then
.Worksheet.Cells(.Row, "B").Formula = "=Today()"
.Worksheet.Cells(.Row, "C").FormulaR1C1 = "=TRUNC(RC[-2]-RC[-3])"
End If
End If
End With
Next oRng
Application.EnableEvents = True
End Sub
My understanding is that:
you need to act for any column 4 cell change, only
there can be more than one changed cell in column 4
so I'd go like follows (explanations in comments):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rangeToProcess As Range
Set rangeToProcess = Intersect(Target, Columns(4)) 'mind edited cells in column 4 only
If rangeToProcess Is Nothing Then Exit Sub
Dim cell As Range
Application.EnableEvents = False
For Each cell In rangeToProcess 'loop through edited cells in column 4
With cell.Offset(, -2).Resize(, 2) ' reference a 2-cells range at the left of current cell
Select Case cell.Value 'process current cell value
Case "CLOSED" ' if it's "CLOSED" ...
.Value = .Value ' ... then leave values in referenced cells
Case "" ' if it's "" ...
.FormulaR1C1 = Array("=Today()", "=TRUNC(RC[-1]-RC[-2])") ' ... then restore formulas
End Select
End With
Next
Application.EnableEvents = True
End Sub

Copy cell value to a range of cells

I'm new to VBA and I am trying to copy values from one cell to multiple cells when its value changes.
The value of A2 is constantly changing and when that happens I want that value to be copied to cells C2:C21 (and then eventually to cells D2:D21)
Here is an example of what I would like to achieve:
http://i.stack.imgur.com/xJZyZ.jpg
So far I wrote this code:
Sub Worksheet_Change(ByVal Target As Range)
For i = 0 To 19
If Not Intersect(Target, Range("AS2")) Is Nothing Then
Cells(Target.Row + i, 58).Value = Cells(Target.Row, 45).Value
End If
Next i
End Sub
but this only copies one single value of A2 to all the cells C2 to C22.
May anyone help me write this code properly?
Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("AS2")) Is Nothing Then
For CurCol = 3 to 4
For CurRow = 2 to 21
If Cells(CurRow, CurCol).Value = "" Then
Cells(CurRow, CurCol).Value = Target.Value
Exit Sub
EndIf
Next CurRow
Next CurCol
End If
End Sub
I guess this is what you're after:
Option Explicit
Sub Worksheet_Change(ByVal Target As Range)
Dim nVals As Long
If Not Intersect(Target, Range("A2")) Is Nothing Then
With Range("C2:D21")
nVals = WorksheetFunction.CountA(.Cells)
If nVals = .Count Then Exit Sub
Application.EnableEvents = False
On Error GoTo exitsub
.Cells(nVals Mod .Rows.Count + 1, IIf(nVals >= .Rows.Count, 2, 1)).Value = Target.Value
End With
End If
exitsub:
Application.EnableEvents = True
End Sub

VBA Excel - How to Automatically Fill a date in multi-columns if i filled column A

This is my first time to write a code and i try to write a code thats helps me to fill Columns B, C and D Automatically thats will happen when i fill Column A by myself.
this is the picture of that sheet i work on it now
Worksheet Explaining what i Want
The final result must be like this Picture
i try to google the code and i found a code but it not work at all
This is the first code
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, B As Range, Inte As Range, r As Range
Set A = Range("A:A")
Set Inte = Intersect(A, Target)
If Inte Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In Inte
r.Offset(0, 1).Value = Date
Next r
Application.EnableEvents = True
End Sub
also i try to write another code thats may helps me to fill Column B and C based on above code results but still not work.
This is the code written by me
Private Sub Worksheet_Change1(ByVal Target As Range)
Dim i As Integer
For i = 6 To 1000
If Cells(i, "A").Value <> "" And Cells(i, "B").Value <> "" Then
Cells(i, "C").Value = Date
Cells(i, "C").NumberFormat = "mmm"
Cells(i, "D").Value = Date
Cells(i, "D").NumberFormat = "yyyy"
End If
Next
Range("C:C").EntireColumn.AutoFit
Range("D:D").EntireColumn.AutoFit
End Sub
anyone can help with that?
The Worksheet_Change event macro is triggered when one or more cells on the worksheet changes value. If you write values into the worksheet within the Worksheet_Change procedure (like you are with the dates) without first turning off event handling then another Worksheet_Change is triggered and the procedure tries to run on top of itself. Always turn off event handling with Application.EnableEvents = False before writing values to the worksheet.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A:B")) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Dim rw As Long, rng As Range
For Each rng In Intersect(Target, Range("A:B"))
If Application.CountA(Cells(rng.Row, "A").Resize(1, 2)) = 2 Then
Cells(rng.Row, "C").Resize(1, 2).Value = Date
Cells(rng.Row, "C").NumberFormat = "mmmm"
Cells(rng.Row, "D").NumberFormat = "yyyy"
End If
Next rng
Range("C:C").EntireColumn.AutoFit
Range("D:D").EntireColumn.AutoFit
End If
bm_Safe_Exit:
If CBool(Val(Err.Number)) Then _
Debug.Print Err.Number & ": " & Err.Description
Application.EnableEvents = True
End Sub
Remember to turn events back on with Application.EnableEvents = True before exiting the Worksheet_Change procedure or future value changes will not trigger the Worksheet_Change procedure again.
btw, the correct number format for October is mmmm, not mmm. The former gives the full month name; the latter only the three letter abbreviation (e.g. Oct).

Change cell to clear content of other cells

i want to clear the cells in column C D E if date change in column B
but only cells in same row where date is changed (Date =Sheet1!c2) so date is from sheet 1 but from different cells and different rows
Sample xls file
This is what i did but its not working until manually change date in Column B sheet 2:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("b1:b100")) Is Nothing Then
Cells(Target.Row, 3) = ""
Cells(Target.Row, 4) = ""
Cells(Target.Row, 5) = ""
End If
End Sub
Here is an extremely simple, limited, example. We are only monitoring cell B5 which contains a formula. The formula retrieves a date from another worksheet:
In the worksheet code area for this sheet we install the following Event macro:
Private Sub Worksheet_Calculate()
Dim Monitor As Range, Helper As Range
Dim rw As Long
Set Monitor = Range("B5")
Set Helper = Range("H5")
rw = Monitor.Row
Application.EnableEvents = False
If Helper.Value = "" Then
Helper.Value = Monitor.Value
Else
If Helper.Value <> Monitor.Value Then
Helper.Value = Monitor.Value
Range("C" & rw & ":E" & rw).ClearContents
End If
End If
Application.EnableEvents = True
End Sub
The code uses cell H5 as a "helper" The first time the code runs, the helper cell is filled. Each time after that, the code compares the "helper" against H5. If they become different, cells C thru E in that row are cleared.
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!
EDIT#1:
Completely discard the original macro and install this one instead:
Private Sub Worksheet_Calculate()
Dim Monitor As Range, Helper As Range
Dim rw As Long, r As Range
Set Monitor = Range("B2:B100")
Set Helper = Range("H2:H100")
Application.EnableEvents = False
For Each r In Helper
If r.Value = "" Then
r.Value = r.Offset(0, -6).Value
End If
Next r
For Each r In Helper
If r.Value <> r.Offset(0, -6).Value Then
r.Value = r.Offset(0, -6).Value
rw = r.Row
Range("C" & rw & ":E" & rw).ClearContents
End If
Next r
Application.EnableEvents = True
End Sub
As you see, we must loop over each item in the ranges.
Try this using the Worksheet_Change Event (see https://msdn.microsoft.com/EN-US/library/office/dn301178.aspx)
Private Sub Worksheet_Change(ByVal Target As Range)
With Target
If .Column = 2 Then
Rem Disable Events. So it's not triggered by changes to columns D, E & F
Application.EnableEvents = 0
Rem Clear Columns D, E & F same row
.Cells.Offset(, 2).ClearContents
.Cells.Offset(, 3).ClearContents
.Cells.Offset(, 4).ClearContents
Rem Enable Events after changes
Application.EnableEvents = 1
End If: End With
End Sub

Emptying specific cells in the same row of an amended cell

I am relatively new to VBA.
Below is my code that works on just row 2.
Option Explicit
Public precedent
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Me.[D2]) Is Nothing Then
If Me.precedent <> Me.[D2].Value Then
Me.[F2] = ""
Me.[H2] = ""
Me.precedent = Me.[D2].Value
End If
End If
End Sub
I would like this code to run on every row except row 1 as this is my header.
How do I do this? Would I use a loop?
It shouldn't be so complicated. Just check Target.Row and Target.Column. If the former is greater than 1 and the latter is equal to 4, trigger whatever action you want.
Modify the following code accordingly.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row > 1 And Target.Column = 4 Then
Range("F" & Target.Row) = vbNullString
Range("H" & Target.Row) = vbNullString
End If
End Sub
Let us know if this helps.
You wouldn't have to use a loop. Since you want to omit the first row, you should set a range that you want this code to fire when it is modified. Currently, you are checking it against D2 only. When your If statement is checking for your entire range, you can then use Target as the specific cell that was changed (instead of using D2.)
Here's some code that should do what you want:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rangeToCheck As Range
rangeToCheck = Range(Cells(2,4),Cells(Application.ActiveSheet.UsedRange.Rows.Count,4)) 'If your range isn't dynamic, you could put static numbers here
If Not Intersect(Target, rangeToCheck) Is Nothing Then 'Now checks against all of Column D, omitting Row 1
If Target.precedent <> Target.Value Then
Target.Offset(0,2).Value = "" 'Clear Column F in Target Row
Target.Offset(0,4).Value = "" 'Clear Column H in Target Row
Target.precedent = Target.Value
End If
End If
End Sub
Below is code that will skip row 1. Note the .Row and .Column properties of 'Target'
Option Explicit
Public precedent
Private Sub Worksheet_Change(ByVal Target As Range)
Debug.Print Target.Column
Debug.Print Target.Row
If Target.Row <> 1 Then
If Not Intersect(Target, Me.[D2]) Is Nothing Then
If Me.precedent <> Me.[D2].Value Then
Me.[F2] = ""
Me.[H2] = ""
Me.precedent = Me.[D2].Value
End If
End If
End If
End Sub
I think you need this one:
Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 4 Then Exit Sub
If Me.Cells(Target.Row, 4) = "" Then
Me.Cells(Target.Row, 6) = ""
Me.Cells(Target.Row, 8) = ""
End If
End Sub