Merge cells doesn't work after locking and unlocking other cell - excel

I've got a sheet in which I'm trying to merge some cells based on CX cell value. CX cell is also dynamically locked/unlocked based on BX cell value. Although locking/unlocking works fine, I get 1004 error when I'm trying to merge cells with line:
Range(Cells(Target.Row, i), Cells(Target.Row + Target.Value - 1, i)).Merge
While code is below.
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not Intersect(Target, Range("B14:B50")) Is Nothing And Sh.Name <> "Dane" Then
Dim pass As String
pass = "" 'set the password. Otherwise, protection/unprotection is done without a pass
If Target.Cells.Count > 1 Then Exit Sub
ActiveSheet.Unprotect pass
If Target.Value = "Unlocked" Then
Target.Offset(0, 1).Locked = False
Else
Target.Offset(0, 1).Value = 0
Target.Offset(0, 1).Locked = True
End If
ActiveSheet.Protect pass
End If
If Not Intersect(Target, Range("C14:C50")) Is Nothing And Sh.Name <> "Dane" Then
Dim i As Long
Application.DisplayAlerts = False
For i = 1 To 8 Step 1
If i <> 6 And i <> 7 And Cells(Target.Row, i).MergeCells Then
Cells(Target.Row, i).UnMerge
End If
Next i
If Target.Value <> 0 Then
For i = 1 To 8 Step 1
If i <> 6 And i <> 7 Then
Range(Cells(Target.Row, i), Cells(Target.Row + Target.Value - 1, i)).Merge
End If
Next i
End If
Application.DisplayAlerts = True
End If
End Sub

Okay. So with #FaneDuru comments, I've been able to figure out the issue. Sheet protection was causing the problem, so I had to unprotect and reprotect sheet before for loops in second condition. Also, #FaneDuru advised to set EnableEvents = false there, to prevent any infinite loop issue. Below is the fixed code.
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not Intersect(Target, Range("B14:B50")) Is Nothing And Sh.Name <> "Dane" Then
Dim pass As String
pass = "" 'set the password. Otherwise, protection/unprotection is done without a pass
If Target.Cells.Count > 1 Then Exit Sub
ActiveSheet.Unprotect pass
If Target.Value = "Unlocked" Then
Target.Offset(0, 1).Locked = False
Else
Target.Offset(0, 1).Value = 0
Target.Offset(0, 1).Locked = True
End If
ActiveSheet.Protect pass
End If
If Not Intersect(Target, Range("C14:C50")) Is Nothing And Sh.Name <> "Dane" Then
Dim i As Long
Application.DisplayAlerts = False
Application.EnableEvents = False
ActiveSheet.Unprotect pass
For i = 1 To 8 Step 1
If i <> 6 And i <> 7 And Cells(Target.Row, i).MergeCells Then
Cells(Target.Row, i).UnMerge
End If
Next i
If Target.Value <> 0 Then
For i = 1 To 8 Step 1
If i <> 6 And i <> 7 Then
Range(Cells(Target.Row, i), Cells(Target.Row + Target.Value - 1, i)).Merge
End If
Next i
End If
ActiveSheet.Protect pass
Application.EnableEvents = True
Application.DisplayAlerts = True
End If
End Sub
However, I'm still wondering why I need to unprotect the sheet to edit unlocked range.

Related

Delete entire based on another cell value

I need help with Excel VBA code.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 3 And Target.Cells.Count = 1 Then
If LCase(Target.Value) = "-1" Then
With Target.EntireRow.ClearContents
End With
End If
End If
If Target.Column = 3 And Target.Cells.Count = 1 Then
If LCase(Target.Value) = "1000" Then
With Target.EntireRow
.Copy Sheets("Week Schedule").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
.Delete
End With
End If
End If
End Sub
If the third column we enter -1 it will clear the row. If we enter 1000 it will be copied to another sheet and deleted from the current sheet.
The above code is working fine. Instead of clearing row data, I want to delete that row.
So added
Line 4 With Target.EntireRow.ClearContents to With Target.EntireRow.Delete
But it shows an error.
It would help to know what error you get. Assuming the error is caused because the Week Schedule sheet does not exist, you can add a check for that. After that, your code works fine:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 3 And Target.Cells.Count = 1 Then
If LCase(Target.Value) = "-1" Then
With Target.EntireRow.ClearContents
End With
End If
End If
If Target.Column = 3 And Target.Cells.Count = 1 Then
If LCase(Target.Value) = "1000" Then
With Target.EntireRow
SheetExistsOrCreate ("Week Schedule")
.Copy Sheets("Week Schedule").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
.Delete
End With
End If
End If
End Sub
Function SheetExistsOrCreate(name As Variant)
For i = 1 To Worksheets.Count
If Worksheets(i).name = "MySheet" Then
exists = True
End If
Next i
If Not exists Then
Worksheets.Add.name = name
End If
End Function
Please, try the next adapted code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 3 And Target.Cells.Count = 1 Then
Application.EnableEvents = False
If LCase(Target.Value) = -1 Then
Target.EntireRow.Delete
ElseIf Target.Value = 1000 Then
With Target.EntireRow
.Copy Sheets("Week Schedule").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
.Delete
End With
End If
Application.EnableEvents = True
End If
End Sub
The above code assumes that the Target value means a number, not a string looking as a number. If a string, you can place them between double quotes, as in your initial code.
Of course, a sheet named "Week Schedule" must exist in the active workbook and must not be protected.

Macro treats single cell as range

In my code, I get runtime error 1004, "unable to set the Locked property of the Range class" every time if I change BX cell value from unlocked to any other. If I change any other value to unlocked code runs good. However, even if C column cells weren't previously merged the error occurs. Also, even if C cells where previously merged, they should be unmerged by Target.Offset(0, 1).Value = "0" this line, which calls second condition in my function. Why I'm getting this error?
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim pass As String
pass = "" 'set the password. Otherwise, protection/unprotection is done without a pass
If Not Intersect(Target, Range("B14:B50")) Is Nothing And Sh.Name <> "Dane" Then
If Target.Cells.Count > 1 Then Exit Sub
ActiveSheet.Unprotect pass
If Target.Value = "Unlocked" Then
Target.Offset(0, 1).Locked = False
Else
Target.Offset(0, 1).Value = "0"
Target.Offset(0, 1).Locked = True
End If
ActiveSheet.Protect pass
End If
If Not Intersect(Target, Range("C14:C50")) Is Nothing And Sh.Name <> "Dane" Then
Dim i As Long
Dim rng As Range
Application.DisplayAlerts = False
Application.EnableEvents = False
ActiveSheet.Unprotect pass
For i = 1 To 8 Step 1
If i <> 6 And i <> 7 And Cells(Target.Row, i).MergeCells Then
Cells(Target.Row, i).UnMerge
End If
Next i
If Target.Value <> 0 Then
Dim cf As Boolean
If Target.Value > 1 Then
For i = 1 To 8 Step 1
If i <> 6 And i <> 7 Then
Range(Cells(Target.Row, i), Cells(Target.Row + Target.Value - 1, i)).Merge
End If
Next i
End If
For i = 14 To 50 Step 1
If Not cf Then
Set rng = Range("A" & i).MergeArea.Resize(, 8)
With rng
.Borders.LineStyle = xlNone
.Interior.Color = RGB(217, 225, 242)
.BorderAround xlContinuous, xlThin, Color:=RGB(142, 169, 219)
End With
Else
Range("A" & i).MergeArea.Resize(, 8).Interior.Color = xlNone
End If
i = (i + Range("A" & i).MergeArea.Cells.CountLarge) - 1
cf = Not cf
Next i
End If
ActiveSheet.Protect pass
Application.EnableEvents = True
Application.DisplayAlerts = True
End If
End Sub
I think, your code problem is the following:
Any change in "C14:C50" range (even done by first event part, a change in range "B14:B50"), will indeed trigger the second event part, which will merge/unmerge ranges as you want. I did not spend to much time to understand if all logic is OK.
The problem is that this second triggered event ends with ActiveSheet.Protect pass.
The first interrupted event does not start from the beginning. It continues from the line where has been stopped. Meaning that the worksheet will not be unprotected in the moment you try locking a cell in C:C column.
In order to solve the problem, please insert the next line:
If ActiveSheet.ProtectContents Then ActiveSheet.Unprotect pass
just before:
Target.Offset(0, 1).Locked = True
The inserted line, will unprotect the sheet in the situation described above, too.

Get results only when multiple cells are changed VBA

I have a code that fills the date in column 3 when the there is a change in values of a cell Range("E:J"). It works fine, but I would also like to display the values of column 4 (col 4 is hidden) in column 11, only when all the cells in the Range(E:J) are filled.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub
If Intersect(Target, Range("E:J")) Is Nothing Then Exit Sub
Application.EnableEvents = False
If Target.Value <> vbNullString Then
Target.Offset(0, 3 - Target.Column).Value = Date
Target.Offset(0, 3 - Target.Column).NumberFormat = "dd/mmm/yyyy"
Else
Target.Offset(0, 3 - Target.Column).ClearContents
End If
Application.EnableEvents = True
End Sub
Any help on this would be greatly appreciated.
Thanks.
Consider:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim tc As Long, r As Range, tr As Long
Dim wf As WorksheetFunction
Set wf = Application.WorksheetFunction
If Target.Count > 1 Then Exit Sub
tc = Target.Column
tr = Target.Row
If Intersect(Target, Range("E:J")) Is Nothing Then Exit Sub
Set r = Range(Cells(tr, "E"), Cells(tr, "J"))
Application.EnableEvents = False
If Target.Value <> vbNullString Then
Target.Offset(0, 3 - tc).Value = Date
Target.Offset(0, 3 - tc).NumberFormat = "dd/mmm/yyyy"
Else
Target.Offset(0, 3 - tc).ClearContents
End If
If wf.CountA(r) = 6 Then
Cells(tr, 11).Value = Cells(tr, 4).Value
End If
Application.EnableEvents = True
End Sub

How to auto return to original column but next row when # is scanned

I want to continuously scan barcodes into excel. Each scan will go into the same row separate cell until "$" is scanned and return to original column and next row.
I have tried this:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Select Case Target.Column
Case 3 'column c
If Target.Value <> "" Then
Target.Offset(0, 1).Select 'move right
End If
Case 4 'column d
If Target.Value <> "" Then
Target.Offset(0, 1).Select 'move right
End If
Case 5 'column E
If Target.Value <> "" Then
Target.Offset(1, -2).Select 'move down and back to column C
End If
End Select
End Sub
This should work for you.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Scan As Variant
Scan = Trim(Target.Value)
If Len(Scan) And Target.Column > 2 Then
If Left(Scan, 1) = "$" Then
Scan = Mid(Scan, 2)
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
If Target.Column > 3 Then
Target.ClearContents
Set Target = Cells(Target.Row + 1, 3)
End If
Target.Value = Scan
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End If
Target.Offset(0, Sgn(Val(Scan))).Select
End If
End Sub
The code was expanded to include the new requirements as per your comment.

Correcting one code causes another to stop working

I am working on a document in which clickable cells place different values in column M on sheets 1 and 3. On sheet 1 when column M reads COMPLETE it will be cut from sheet 1 and pasted in sheet 2 when column M reads PARTIAL HOLD it will be cut from sheet 1 and pasted into sheet 3. I am having many problems with this but the problem I am asking for help on here is that in the following code the moves will work but i get a "run-time error '424' Object Required" and is not accepting Time as an object in my line of code Target.Offset(, 4).Value = Time but when I fix the issue in the code for the clickable cells the rows will no longer cut and paste.
This first code is the code that allows the rows to move but gets me an error
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngDest As Range, rngDest2 As Range, rngDest3 As Range
If UCase(Target.Value) = "PARTIAL HOLD" Then
Set rngDest = Sheet3.Range("A5:Q5")
If Not Intersect(Target, Sheet1.Range("M5:M290")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
ElseIf UCase(Target.Value) = "PROGRESSING" Then
Set rngDest3 = Sheet1.Range("A5:Q5")
If Not Intersect(Sheet3.Cells(Target.Row, Target.Column), Sheet3.Range("M5:M290")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest3.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
ElseIf UCase(Target.Value) = "COMPLETE" Then
Set rngDest2 = Sheet2.Range("A5:Q5")
If Not Intersect(Target, Sheet1.Range("M5:M290")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest2.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
End If
End Sub
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Target.Column = 11 Then
Cancel = True
Target.Offset(, 2).Value = "IN PROGRESS"
Target.Offset(, 4).Value = Time
ElseIf Target.Column = 12 Then
Cancel = True
Target.Offset(, 1).Value = "COMPLETE"
Target.Offset(, 4).Value = Time
ElseIf Target.Column = 14 Then
Cancel = True
Target.Offset(, -1).Value = "PARTIAL HOLD"
End If
End Sub
The next code is the correction I have made to the clickable cells, but this stops the rows from cutting and pasting
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngDest As Range, rngDest2 As Range, rngDest3 As Range
If UCase(Target.Value) = "PARTIAL HOLD" Then
Set rngDest = Sheet3.Range("A5:Q5")
If Not Intersect(Target, Sheet1.Range("M5:M290")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
ElseIf UCase(Target.Value) = "PROGRESSING" Then
Set rngDest3 = Sheet1.Range("A5:Q5")
If Not Intersect(Sheet3.Cells(Target.Row, Target.Column),
Sheet3.Range("M5:M290")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest3.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
ElseIf UCase(Target.Value) = "COMPLETE" Then
Set rngDest2 = Sheet2.Range("A5:Q5")
If Not Intersect(Target, Sheet1.Range("M5:M290")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest2.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
End If
End Sub
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Application.EnableEvents = False
On Error GoTo Xit:
If Target.Column = 11 Then
Cancel = True
Target.Offset(, 2).Value = "IN PROGRESS"
Target.Offset(, 4).Value = Time
ElseIf Target.Column = 12 Then
Cancel = True
Target.Offset(, 1).Value = "COMPLETE"
Target.Offset(, 4).Value = Time
ElseIf Target.Column = 14 Then
Cancel = True
Target.Offset(, -1).Value = "PARTIAL HOLD"
End If
Xit:
Application.EnableEvents = True
End Sub
What can I do to fix this?

Resources