Conditional Lock Cell , unable to sort - vba

I am trying to write a macro that will lock any cell greater than 0. When I run the code below it works but locks the 1st row where I have a drop down arrow that does sorting and number filters. Is there a way to add to this code so that the first row wont be locked?
Sub Test()
Dim Cell As Range
Dim MyPlage As Range
With ThisWorkbook.ActiveSheet
.Unprotect
.Cells.Locked = False
Set MyPlage = .Range("J2:AA1074")
For Each Cell In MyPlage
If Not IsError(Cell) Then
If Cell.Value > "0" Then
Cell.Locked = True
End If
End If
Next
.Protect
End With
End Sub

The most simplest was is to define your range which doesn't include the Top Row :)
Change
.Range("J2:AA1074")
to
.Range("J3:AA1074")
Also, Instead of looping through every cell in the range and checking if that cell has an error or not, you can directly use SpecialCells. For example (TRIED AND TESTED)
Sub Sample()
Dim Cell As Range, MyPlage As Range, FinalRange As Range
With ThisWorkbook.ActiveSheet
.Unprotect
.Cells.Locked = False
On Error Resume Next
Set MyPlage = .Range("J3:AA1074").SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If Not MyPlage Is Nothing Then
For Each Cell In MyPlage
If Cell.Value > 0 Then Cell.Locked = True
Next
End If
.Protect DrawingObjects:=True, _
Contents:=True, _
Scenarios:=True, _
AllowFiltering:=True, _
AllowSorting:=True
.EnableSelection = xlUnlockedCells
End With
End Sub
To ensure that Autofilter and Sorting works, specify it in .Protect as I have done above.
Before you run the above code, you also need to take one extra step.
Unprotect the worksheet if it is already protected
Under Review Tab, click on "Allow Users to Edit Ranges"
Add "New" range
Select the range you want allow users to sort
Screenshot

You can add following code to the Sheet module (change Range("J1:AA1") to the range with your autofilter):
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Application.Intersect(Target, Range("J1:AA1")) Is Nothing Then
ActiveSheet.Protect
Else
ActiveSheet.Unprotect
End If
End Sub

Related

Error Handling for solution on sorting on protected Worksheets

On a protected user form (table with data) I have found a possibility to allow sorting protected cells by unprotecting the header row when selected (if...then) and protecting the sheet whenever another cell(s) is selected (else). So now, when clicking the header row and clicking the filter symbol, users can sort, because in this moment the file is unprotected.
Now, there is one problem remaining: when users select data in the databodyrange (or any other cell that is not in header row (here: row 11)) and then directly click on the filter symbol in the header row for sorting, they have activated cells that cause the sheet to protect (Else) and to unprotect (If...then) at the same time.
So the code itsself works fine. What I struggle with is writing an error handling, that for example on error selects a cell in the header row and continues to run the macro in all funcionality + doesn't disturb the user.
What is an easy Error Handling for the following code?
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Ws As Worksheet
Set Ws = Target.Worksheet
If (Target.Row = 11) Then 'Row 11 is the tables header's row
With Ws
.Unprotect ""
End With
Else
With Ws
.EnableAutoFilter = True
.EnableOutlining = True
.Protect "", contents:=True, UserInterfaceonly:=True, AllowFormattingRows:=True, AllowFiltering:=True, AllowSorting:=True
End With
End If
End Sub
Thanks - and really just an error handling is looked for. No other workaround!
I solved my own issue using On Error Resume Next. It is not super elegant, but this way users are able to "sort on a protected sheet with locked cells".
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Ws As Worksheet
Set Ws = Target.Worksheet
On Error Resume Next
If Err.Number <> 0 Then
Application.Undo
MsgBox "Please select a cell in the header row, before sorting or filtering."
End If
If (Target.Row = 11) Then
With Ws
.Unprotect ""
End With
Else
With Ws
.EnableAutoFilter = True
.EnableOutlining = True
.Protect "", contents:=True, UserInterfaceonly:=True, AllowFormattingRows:=True, AllowFiltering:=True, AllowSorting:=True
End With
End If
End Sub

Make cells read only

This code makes the entire sheet read only.
I want to make cells which are empty (hold null value) read only. It should work for different Excel files where the used cell range could be different.
Sub proFirst()
Sheets("DCAFTE").UsedRange.Select
ActiveSheet.Unprotect
ActiveWorkbook.Unprotect
Dim myRange As Range
Set myRange = ActiveSheet.UsedRange
myRange.Select
Selection.Locked = True
ActiveSheet.Protect Contents:=True
End Sub
You can replace your code with the below code. This will select only the cells which are empty (blank) and make it read only. The cells which are having values will be editable.
Sub proFirst()
Sheets("DCAFTE").Select
ActiveSheet.Unprotect
ActiveWorkbook.Unprotect
Dim myCell As Range
Set myCell = Selection
Cells.Select
Selection.Locked = False
myCell.Select
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.Locked = True
ActiveSheet.Protect Contents:=True
myCell.Select
End Sub

VB Spell Check Code issue

I have managed to assemble the following code for spell checking a locked document but just cant quit get it to work. I would like it to look at only unlocked cells but still use the 'CommandBars("Tools").Controls("Spelling...").Execute' function. Any ideas would be great. TIA
Sub SelectUnlockedCells_Spellcheck()
ActiveSheet.Unprotect Password:=""
Dim WorkRange As Range
Dim FoundCells As Range
Dim Cell As Range
Set WorkRange = ActiveSheet.UsedRange
For Each Cell In WorkRange
If Cell.Locked = False Then
If FoundCells Is Nothing Then
Set FoundCells = Cell
Else
Set FoundCells = Union(FoundCells, Cell)
End If
End If
Next Cell
If FoundCells Is Nothing Then
MsgBox "All cells are locked."
Else
FoundCells.CheckSpelling CommandBars("Tools").Controls("Spelling...").Execute
End If
ActiveSheet.Protect Password:=""
End Sub
You are using this code
FoundCells.CheckSpelling CommandBars("Tools").Controls("Spelling...").Execute
But the VBA help doesn't show any such parameters. Try using just this:
FoundCells.CheckSpelling

SHEETOFFSET to copy color

I am using the SHEETOFFSET VBA code
Function SHEETOFFSET(offset, Ref)
' Returns cell contents at Ref, in sheet offset
Application.Volatile
With Application.Caller.Parent
SHEETOFFSET = .Parent.Sheets(.Index + offset) _
.Range(Ref.Address).Value
End With
End Function
And then the following code within within my new sheet
=sheetoffset(-1, B2)
to copy the value of cell B2 in the previous sheet to my new sheet.
However, I also need to copy the color of that particular cell. Is there any code that I can enter in the original VBA code above to do this? Or is there another way of achieving this?
Many thanks for your help
Tim
Logic:
Define a Public variable to hold the color of the cell
In Worksheet_Change check if the above variable has any value. If yes then change the color of the target cell.
Once the above is done, reset the variable to 0
Code in Module:
Public cellColor As Double
Function SHEETOFFSET(offset, Ref)
With Application.Caller.Parent
SHEETOFFSET = .Parent.Sheets(.Index + offset) _
.Range(Ref.Address).Value
'~~> Store the color in a variable
cellColor = .Parent.Sheets(.Index + offset) _
.Range(Ref.Address).Interior.ColorIndex
End With
End Function
Code in Sheet Code Area:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim aCell As Range
On Error GoTo Whoa
Application.EnableEvents = False
For Each aCell In Target.Cells
If cellColor <> 0 Then aCell.Interior.ColorIndex = cellColor
Next
Letscontinue:
cellColor = 0
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub
ScreenShot:
My Personal Thoughts:
I am not in favor of the SHEETOFFSET function in the first place because the formula is actually referring a cell in the current sheet. Any changes, for example, deletion of that cell will error out your formula
It is better to link the cells directly
FOLLOWUP (From Comments)
You can run this code in the end to refresh all formulas.
Sub Sample()
Dim ws As Worksheet
Dim rng As Range, aCell As Range
For Each ws In ThisWorkbook.Sheets
Set rng = Nothing
On Error Resume Next
Set rng = ws.Cells.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not rng Is Nothing Then
For Each aCell In rng
aCell.Formula = aCell.Formula
Next
End If
Next
End Sub

Lock certain cells in a range

I'm trying to loop through a range of cells, locking any cell that has content while leaving empty cells unlocked.
When I run the below code the result is the entire sheet is locked. If I add an else statement the sheet is unlocked. Basically whatever the last .locked = (true, false) statement is is how the entire sheet winds up.
Change 1 Is it possible that I have some setting on/off that is interfering since I'm the only one who is unable to get any of this to work?
Sub ProtectTheSheet()
Dim chCell As Range
Dim chRng As Range
'Clear the default status
ActiveSheet.Unprotect
Range("A7:I35").Locked = False
Set chRng = ActiveSheet.Range("A7:I35")
'Check cell value in body and lock cells with content
For Each chCell In chRng.Cells
If chCell.Value <> "" Then Cells.Locked = True
Next chCell
ActiveSheet.Protect
End Sub
Sub ProtectTheSheet()
Dim chCell As Range
Dim chRng As Range
ActiveSheet.Unprotect
Set chRng = ActiveSheet.Range("A7:I35")
'Check cell value in body and lock cells with content
For Each chCell In chRng.Cells
chCell.Locked = (chCell.Value <> "")
Next chCell
ActiveSheet.Protect
End Sub
You can try this.
Public Sub abc()
ActiveSheet.Unprotect Password:="1234"
ActiveSheet.Range("I8:I500, K8:K500, M8:M500, N8:N500").Cells.Locked = False
ActiveSheet.Protect Password:="1234"
End Sub
Check this out: http://www.mrexcel.com/archive/VBA/15950b.html
Sub CellLocker()
Cells.Select
' unlock all the cells
Selection.Locked = false
' next, select the cells (or range) that you want to make read only,
' here I used simply A1
Range("A1").Select
' lock those cells
Selection.Locked = true
' now we need to protect the sheet to restrict access to the cells.
' I protected only the contents you can add whatever you want
ActiveSheet.Protect DrawingObjects:=false, Contents:=true, Scenarios:=false
End Sub
If you say Range("A1").Select, then it locks only A1. You can specify multiple cells to be locked by specifying as follows:
A3:A12,D3:E12,J1:R13,W18
This locks A3 to A12 and D3 to E12 etc.
I may be missing something but...
Cells.Locked = True
...will lock all cells on the active sheet. If you just change it to...
chCell.Locked = True
...then it works; I think?! As the range is very small, you may as well not unlock cells at the start, and instead unlock cells whilst locking them e.g.
For Each chCell In chRng.Cells
If chCell.Value <> "" Then
chCell.Locked = True
Else
chCell.Locked = False
End If
Next chCell
If you are new to VBA, I would recommend cycling through code line-by-line as described in this Excel consultant's video. If you step through code, you can check "has cell A7 behaved as expected?"...instead of just seeing the end product
A quick way to unlock non-blank cells is to use SpecialCells see below.
On my testing this code handles merged cells ok, I think this is what is generating your error on Tim's code when it looks to handle each cell individually (which to be clear is not an issue in Tim's code, it is dealing with an unexpected outcome)
You may also find this article of mine A fast method for determining the unlocked cell range useful
Sub Quicktest()
Dim rng1 As Range
Dim rng2 As Range
On Error Resume Next
Set rng1 = ActiveSheet.Range("A7:I35").Cells.SpecialCells(xlFormulas)
Set rng2 = ActiveSheet.Range("A7:I35").Cells.SpecialCells(xlConstants)
On Error GoTo 0
ActiveSheet.Unprotect
ActiveSheet.Range("A7:I35").Cells.Locked = False
If Not rng1 Is Nothing Then rng1.Cells.Locked = True
If Not rng2 Is Nothing Then rng2.Cells.Locked = True
ActiveSheet.Protect
End Sub
I know this is an old thread, but I've been stuck on this for a while too, and after some testing on Excel 2013 here's what I conclude if your range includes any merged cell
The merged cells must be entirely included within that range (e.g. the merging must be entirely within the range being lock/unlocked
The range being merged can be larger, or at least exactly the range corresponding to the merged cells. If it's a named range that works as well.
Also, you cannot lock/unlock a cell that is already within a protected range. E.g if you run:
public sub test()
Sheet1.range("myNameRange").locked = true
Sheet1.protect
end sub
Twice it will work the first time, and fail the second time around. So you should unprotect the target range (or the sheet) before....
If you want to protect the specific cells of any specific excel without the password protection then here is the solution:
Sub ProtectingSheet()
Workbooks.Open (c\documents\....)
Dim mainworkBook As Workbook
Set mainworkBook = ActiveWorkbook
Worksheets(CellValue).Activate
mainworkBook.Sheets("Sheet1").Range("A1:AA100").Locked = True
Range(Cells(1, 2), Cells(1, 25)).Select
Selection.Locked = False
ActiveSheet.Protect
End Sub