Reputation: 907
I have a form that is automatically filled when user chooses job position, however in 3 sections I have drop-down lists (B21:B45, B27:B30, B50:B67) and users will be allowed to change max 2 options from these drop-down lists.
In other words I have a table B21:C45 and if user will modify 2 out of 25 cells in column B then macro will automatically give a message that you've modified the maximum number of cells and then macro will lock cells B21:B45. The same applies to other 2 tables (so for RngTwo and RngThree).
I've tried to use Intersect function but I am not sure how to write a macro that would lock specific range of cells if 2 cells in this range are changed. The biggest challenge for me is that macro needs to take into condsideration all 3 ranges.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim RngOne As Range
Dim RngTwo As Range
Dim RngThree As Range
Set RngOne = Range("B21:B45")
Set RngTwo = Range("B27:B30")
Set RngThree = Range("B50:B67")
If Not Application.Intersect(RngOne, Range(Target.Address)) Is Nothing Then
MsgBox "You changed " & Target.Count & " out of " & RngOne.Count & " cells."
End If
End Sub
Upvotes: 0
Views: 76
Reputation: 574
My solution is that there are two subs working together. The startSelection is storing the status of the ranges into the arrays. It shall be triggered before let the user starting changes. Then the Worksheet_Change compare the values and calculate how many cells has been changed. Calling the startSelection can be re-initiated the process. I have not finalized the sub for all the ranges so it shall be finished if this solution is considered good.
Dim RngOne As Range ' Global variables
Dim RngTwo As Range
Dim RngThree As Range
Dim vOne As Variant
Dim vTwo As Variant
Dim vThree As Variant
Sub startSelection()
Set RngOne = Range("B21:B45")
Set RngTwo = Range("B27:B30")
Set RngThree = Range("B50:B67")
vOne = RngOne.value
vTwo = RngTwo.value
vThree = RngThree.value
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If RngOne Is Nothing Then Call startSelection
If Intersect(Target, Union(RngOne, RngTwo, RngThree)) Is Nothing Then
Exit Sub
End If
Dim i As Integer
Dim rng As Range
Dim iChanged As Integer
iChanged = 0
For Each rng In RngOne
i = i + 1
If vOne(i, 1) <> rng.value Then iChanged = iChanged + 1
Next rng
'should be repeated for the other two ranges
If iChanged > 2 Then
MsgBox "You changed " & iChanged & " out of " & RngOne.Count & " cells."
End If
End Sub
Upvotes: 1
Reputation: 14373
You may like to try this code.
Private Sub Worksheet_Change(ByVal Target As Range)
' 048
Static Count(1 To 3) As Integer
Dim Rng As Range
Dim i As Integer ' array index
If Target.CountLarge > 1 Then Exit Sub
Set Rng = Application.Union(Range("B21:B25"), Range("B27:B30"), Range("B50:B67"))
For i = 1 To 3
If Not Application.Intersect(Rng.Areas(i), Target) Is Nothing Then
If Count(i) < 2 Then
Count(i) = Count(i) + 1
Else
MsgBox "You have exceeded the maximum number (2)" & vbCr & _
"of permissible changes in this section." & vbCr & _
"This change will be rolled back.", _
vbInformation, "Too many changes"
With Application
.EnableEvents = False
.Undo
.EnableEvents = True
End With
End If
Exit For
End If
Next i
End Sub
The three ranges you set are overlapping, and that would require more precise coding once you specify what you really mean. For the moment I have just presumed that there is a type in one of the addresses and set the first range as B21:B25 instead of B21:B45.
Anyway, this is only to show the approach. The solution is only perfunctorily tested. Should errors occur when you test please let me know and I shall fix them.
Upvotes: 3