I have a matrix with i.e dimensions 300x300 (x & y,size vary from project to project).
The names/numbers of the individual rows are transposed to the columns.
The matrix is divided diagonally, and I use it to tag relations between different "systems".
The tag have to be a unique number. See image:
I do not want duplicated relations, so I just want to use the white cells to add the tag.
(The black ones are there to show that the system cant have a relation with itself.)
I have tried to make a range, that I apply a Validation to later which shows me the next number in line for the tag:
Public MatrixRange as Range
Private Sub Worksheet_Activate()
Dim n As Integer
Dim NextRange As Range
Dim OldRange As Range
Dim LastRow As Long
With shMatrix
LastRow = .Range("A" & .Rows.Count).End(xlUp).row
Set MatrixRange = .Range("C11")
If LastRow <= 1 Then Exit Sub
For n = 2 To .Range(.Range("A9").Offset(1, 0).Address, "A" & LastRow).Rows.Count
Set OldRange = MatrixRange
Set NextRange = .Range(.Range("B9").Offset(n, 1), .Range("B9").Offset(n, -1 + n))
Set MatrixRange = Union(OldRange, NextRange)
Next n
End With
End Sub
This code give me the correct range that I want, but it sometimes hogs a whole lot of memory when I open the workbook or try to save. The RAM just goes up and up when I start it, before the workbook just crashes without any error message.
Rewriting the code to select the whole matrix, not just the one half, seems to fix the issue.
My question is this: is it possible to rewrite the code so I get the correct range, with a different method or are there any flaws in my code that will create a memory leak?
I call the above sub also when applying the Validation, if MatrixRange is not created:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim ValMax As Integer
If MatrixRange Is Nothing Then
Call CreateMatrixRange
End If
ValMax = Application.WorksheetFunction.Max(MatrixRange)
With MatrixRange.Validation
.Delete
.Add Type:=xlValidateWholeNumber, AlertStyle:=xlValidAlertStop, _
Operator:=xlEqual, Formula1:=ValMax + 1
.IgnoreBlank = True
.InCellDropdown = False
.InputTitle = "Next number"
.ErrorTitle = "Error"
.InputMessage = ValMax + 1
.ErrorMessage = "Next number is: " & ValMax + 1
.ShowInput = True
.ShowError = True
End With
End Sub
Thank you for your answers!
Try the following:
Option Explicit
Private prMatrix As Range
'* plLastRow is used to check if the matrix range changes after it had been set
Private plLastRow As Long
Private Function GetMatrixRange() As Range
Dim lStartCol As Long: lStartCol = 3
Dim lStartRow As Long: lStartRow = 11
Dim lLastRow As Long
Dim i As Long
With shMatrix
lLastRow = .Cells(Rows.Count, "A").End(xlUp).Row
If lLastRow < lStartRow Then lLastRow = lStartRow
If prMatrix Is Nothing Or lLastRow <> plLastRow Then
plLastRow = lLastRow
Set prMatrix = .Cells(lStartRow, lStartCol)
'* Row Number -> Number of Columns mapping
'* Row 11 -> 1 column
'* Row 12 -> 2 columns
'* Row 13 -> 3 columns , ...etc
'* Therefore, Number Of Columns = Row Number - lStartRow + 1
For i = lStartRow + 1 To lLastRow
Set prMatrix = Union(prMatrix, .Cells(i, lStartCol).Resize(1, i - lStartRow + 1))
Next i
End If
End With
Set GetMatrixRange = prMatrix
End Function
Private Function GetNextValue() As Long
GetNextValue = WorksheetFunction.Max(GetMatrixRange) + 1
End Function
'Private Sub SetValidation()
' Dim lNextValue As Long
' lNextValue = GetNextValue
'
' With GetMatrixRange.Validation
' .Delete
' .Add Type:=xlValidateWholeNumber, _
' AlertStyle:=xlValidAlertStop, _
' Operator:=xlEqual, _
' Formula1:=lNextValue
' .IgnoreBlank = True
' .InCellDropdown = False
' .InputTitle = "Next number"
' .ErrorTitle = "Error"
' .InputMessage = lNextValue
' .ErrorMessage = "Next number is: " & lNextValue
' .ShowInput = True
' .ShowError = True
' End With
'End Sub
'
'Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' SetValidation
'End Sub
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
On Error GoTo ErrorHandler
Application.EnableEvents = False
If Not Intersect(Target, GetMatrixRange) Is Nothing Then
If Target = Empty Then Target.Value = GetNextValue
Cancel = True
End If
ErrorHandler:
Application.EnableEvents = True
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ErrorHandler
Application.EnableEvents = False
Dim rWatched As Range: Set rWatched = Intersect(Target, GetMatrixRange)
Dim lNextValue As Long
Dim lEnteredValue As Long
If Not rWatched Is Nothing Then
Target.Select
If rWatched.Cells.Count > 1 Then
rWatched.ClearContents
MsgBox "You cannot change more than 1 matrix cell at a time"
ElseIf Not IsNumeric(rWatched.Value) Then
rWatched.ClearContents
MsgBox "Only numeric values allowed"
Else
If rWatched.Value <> Empty Then
lEnteredValue = rWatched.Value
rWatched.ClearContents
lNextValue = GetNextValue
If lEnteredValue <> lNextValue Then
If MsgBox("The next allowed value is: " & lNextValue & ". Do you want to accept it?", vbYesNo) = vbYes Then
rWatched.Value = lNextValue
End If
Else
rWatched.Value = lEnteredValue
End If
End If
End If
End If
ErrorHandler:
Application.EnableEvents = True
End Sub
I replaced the validation code with double-click and change event handlers. Feel free to remove these handlers and uncomment the validation and selection change code if you need to.
This code will do the following:
If you change any cell in the matrix, it will validate it and give
you the choice to accept the allowed value. Otherwise, it will delete
what you had entered.
If you double-click a cell in the matrix, it will be populated with the next value
Related
I have two codes depend on application events to run.
Code (1) change color of column_A If FilterMode is True on any column of ActiveSheet.
Code (2) Log changes of any cells in ActiveSheet and put in another sheet("Log").
Error raised if : Filtermode = False and any cells changed by fill handle (the small square in the lower-right corner of the selected cell) ,
I got this error
Method 'Undo' of object '_Application' failed
on this line Application.Undo on Code (2).
I tried to use to disable and enable events with code (1) with no luck.
any help will be appreciated.
Option Compare Text
Private Sub worksheet_SelectionChange(ByVal Target As Excel.Range)
'Code (1) change color of column_A If FilterMode is True on any column of active sheet.
Dim Column_A As Range
Set Column_A = ActiveSheet.Range("A3", ActiveSheet.Range("A" & ActiveSheet.Rows.count).End(xlUp))
If ActiveSheet.FilterMode = True Then
Column_A.Interior.Color = RGB(196, 240, 255)
Else 'FilterMode = False
Column_A.Interior.Color = RGB(255, 255, 255)
End If
End Sub
' Code (2) Log Changes of Current Sheet and put in Sheet("Log")
Private Sub Worksheet_Change(ByVal Target As Range)
Dim RangeValues As Variant, r As Long, boolOne As Boolean, TgValue
Dim sh As Worksheet: Set sh = Sheets("Log")
Dim UN As String: UN = Environ$("username")
If Not Intersect(Target, Range("AK:XFD")) Is Nothing Then Exit Sub 'not doing anything if a cell in "AK:XFD" is changed
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
If Target.Cells.count > 1 Then
TgValue = extractData(Target)
Else
TgValue = Array(Array(Target.value, Target.Address(0, 0))) 'put the target range in an array (or as a string for a single cell)
boolOne = True
End If
Application.EnableEvents = False 'Avoide trigger the change event after UnDo
Application.Undo
RangeValues = extractData(Target) 'Define RangeValue
putDataBack TgValue, ActiveSheet 'Reinsert changed data
If boolOne Then Target.Offset(1).Select
Application.EnableEvents = True
Dim columnHeader As String, rowHeader As String
For r = 0 To UBound(RangeValues)
If RangeValues(r)(0) <> TgValue(r)(0) Then
columnHeader = Cells(1, Range(RangeValues(r)(1)).Column).value
rowHeader = Range("B" & Range(RangeValues(r)(1)).Row).value
Sheets("Log").Range("A" & Rows.count).End(xlUp).Offset(1, 0).Resize(1, 6).value = _
Array(UN, Now, rowHeader, columnHeader, TgValue(r)(0), RangeValues(r)(0))
'Array("User Name", "Date,Time", "Work Order", "Column Label", "New Value", "Old Value")
Range(RangeValues(r)(1)).EntireRow.AutoFit
If Range(RangeValues(r)(1)).RowHeight < 53 Then
Range(RangeValues(r)(1)).RowHeight = 53
End If
End If
Next r
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Sub putDataBack(arr, sh As Worksheet)
Dim i As Long, arrInt, El
For Each El In arr
sh.Range(El(1)).value = El(0)
Next
End Sub
Function extractData(rng As Range) As Variant
Dim a As Range, arr, count As Long, i As Long
ReDim arr(rng.Cells.count - 1)
For Each a In rng.Areas 'creating a jagged array containing the values and the cells address
For i = 1 To a.Cells.count
arr(count) = Array(a.Cells(i).value, a.Cells(i).Address(0, 0)): count = count + 1
Next
Next
extractData = arr
End Function
I figured out the issue, although the error rising with code (2) Worksheet_Change event ,
But actually SelectionChange event on code(1) is the real problem.
Apparently, when I drag down, it is sort of like selecting cells individually and all of them at the same time.
To solve this issue, a condition must be added to event SelectionChange to count the target cells:
If Target.Cells.CountLarge = 1 then
So I just modified the code to look like this in the SelectionChange part and it now works perfectly.
'Code (1)
Private Sub worksheet_SelectionChange(ByVal Target As Excel.Range)
If Target.Cells.CountLarge = 1 Then
Dim Column_A As Range
Set Column_A = ActiveSheet.Range("A3", ActiveSheet.Range("A" & ActiveSheet.Rows.count).End(xlUp))
If ActiveSheet.FilterMode = True Then
Column_A.Interior.Color = RGB(255, 0, 0)
Else 'FilterMode = False
Column_A.Interior.Color = RGB(255, 255, 255)
End If
End If
End Sub
In the meantime, I learned that Calculate event would be best choice to trapping a change to a filtered list as described on this link
https://www.experts-exchange.com/articles/2773/Trapping-a-change-to-a-filtered-list-with-VBA.html
I have the following problem. I need to log changes in a spreadsheet. My range goes from A1:M300000.
So far I have managed to log the address of the changed cell, the user, the old value, and the new value.
Now I would like to insert the following functions and need help. It's the first time I come into contact with VBA:
I also want my log file to show the value of a cell in another column. So I know which object it is. Example change cell B26 and now also A26 should be displayed in the log file.
Furthermore, I also want to log when new cells are inserted or existing records are deleted.
Here is my VBA code:
Option Explicit
Dim mvntWert As Variant
Private Sub Worksheet_Change(ByVal Target As Range)
Dim wks As Worksheet
Dim lngLast As Long
Set wks = Worksheets("Protokoll")
lngLast = wks.Range("A65536").End(xlUp).Row + 1
If Target.Count > 1 Then Exit Sub
If Intersect(Range("A1:M65536"), Target) Is Nothing Then Exit Sub
With wks
.Range("A" & lngLast).Value = Target.Address(0, 0)
.Range("B" & lngLast).Value = mvntWert
.Range("C" & lngLast).Value = Target.Value
.Range("D" & lngLast).Value = VBA.Environ("Username")
.Range("E" & lngLast).Value = Now
End With
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub
If Intersect(Range("A1:M65536"), Target) Is Nothing Then Exit Sub
mvntWert = Target.Value
End Sub
I hope someone can help me. Thank you very much in advance.
greeting
ironman
Please, try the next code, I prepared yesterday for somebody else asking for a similar issue. It needs only one event and should do what you require here:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim RangeValues As Variant, r As Long, boolOne As Boolean, TgValue 'the array to keep Target values (before UnDo)
Dim sh As Worksheet: Set sh = Worksheets("Protokoll")
Dim UN As String: UN = Application.userName
'sh.Unprotect "" 'it should be good to protect the sheet
If sh.Range("A1") = "" Then sh.Range("A1").Resize(1, 6) = _
Array("Time", "User Name", "Changed cell", "From", "To", "Sheet Name")
Application.ScreenUpdating = False 'to optimize the code (make it faster)
Application.Calculation = xlCalculationManual
If Target.cells.count > 1 Then
TgValue = extractData(Target)
Else
TgValue = Array(Array(Target.value, Target.Address(0, 0))) 'put the target range in an array (or as a string for a single cell)
boolOne = True
End If
Application.EnableEvents = False 'avoiding to trigger the change event after UnDo
Application.Undo
RangeValues = extractData(Target) 'define the RangeValue
putDataBack TgValue, ActiveSheet 'put back the changed data
If boolOne Then Target.Offset(1).Select
Application.EnableEvents = True
Dim columnHeader As String, rowHeader As String
For r = 0 To UBound(RangeValues)
If RangeValues(r)(0) <> TgValue(r)(0) Then
sh.cells(rows.count, 1).End(xlUp).Offset(1, 0).Resize(1, 6).value = _
Array(Now, UN, RangeValues(r)(1), RangeValues(r)(0), TgValue(r)(0), Target.Parent.Name)
End If
Next r
'sh.Protect ""
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Sub putDataBack(arr, sh As Worksheet)
Dim i As Long, arrInt, El
For Each El In arr
sh.Range(El(1)).value = El(0)
Next
End Sub
Function extractData(rng As Range) As Variant
Dim a As Range, arr, count As Long, i As Long
ReDim arr(rng.cells.count - 1)
For Each a In rng.Areas 'creating a jagged array containing the values and the cells address
For i = 1 To a.cells.count
arr(count) = Array(a.cells(i).value, a.cells(i).Address(0, 0)): count = count + 1
Next
Next
extractData = arr
End Function
Ok i want to make a searchable drop down list data validation without using helper column or combobox control...So how can i accomplish this..Everything is working fine but let say if i put at then click drop down arrow it will not calculate the worksheet change event..I want to run the worksheet change event every time value change in a certain cell..Suppose if i type at then worksheet change event should run 2 times..I mean every time i click in a keyboard alphabet then the worksheet change event need to run.How can i accomplish this...
Here is my code:
Worksheet Change Event:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim DestinationRng As Range, SourceRng As Range
Set SourceRng = Range("A1:A25")
Set DestinationRng = Range("C1:C25")
If Not Application.Intersect(DestinationRng, Range(Target.Address)) Is Nothing Then
'Target.Validation.Delete
If Target.Value = "" Then
DVDL SourceRng, Target, ""
Else
DVDL SourceRng, Target, Range(Target.Address).Value
End If
End If
End Sub
Here is worksheet selection change event
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim DestinationRng As Range, SourceRng As Range
Set SourceRng = Range("A1:A25")
Set DestinationRng = Range("C1:C25")
' 'If Target = ActiveCell Then Debug.Print yes
Debug.Print "Active:" & ActiveCell.Address
Debug.Print Target.Address
If Not Application.Intersect(DestinationRng, Range(Target.Address)) Is Nothing Then
If Target.Value = "" Then
DVDL SourceRng, Target, ""
Else
DVDL SourceRng, Target, Range(Target.Address).Value
End If
End If
End Sub
Here is the data validation sub procedure:
Public Sub DVDL(SourceRng As Range, PlaceRng As Range, SearchTxt As String)
Dim arr As Variant, arr2 As Variant
If SourceRng.Columns.Count > 1 Then
arr = Application.WorksheetFunction.Transpose(Application.WorksheetFunction.Transpose(SourceRng.Value))
ElseIf SourceRng.Rows.Count > 1 Then
arr = Application.WorksheetFunction.Transpose(SourceRng.Value)
End If
arr = RemoveDuplicateS(arr)
If SearchTxt = "" Then
arr2 = arr
Else
arr2 = Filter(arr, SearchTxt, , vbTextCompare)
End If
For Each el In arr2
Debug.Print el
Next el
If LBound(arr2) <> UBound(arr) Then
'PlaceRng.Select
With PlaceRng.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=Join(arr2, ",")
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = False
End With
End If
End Sub
Here is the code for Removing duplicate value from source range:Not required if source contain unique value
Public Function RemoveDuplicateS(arr As Variant) As Variant
'From this function we return an array from an sorted array.
'It doesn't required extra space in memory because we use same array.
Dim i As Long, j As Long
If IsEmpty(arr) Then
RemoveDuplicateS = arr(0) 'If incoming array is empty then return empty one.
Else
j = LBound(arr)
For i = LBound(arr) To UBound(arr) - 1 'Run loop from first one to second last one.
If arr(i) <> arr(i + 1) Then 'if arr(5)<>arr(6) then put put the arr(5) value to the unique list.
arr(j) = arr(i)
j = j + 1 'Increase the j for indexing.
End If
Next i
arr(j) = arr(UBound(arr)) 'Put the last data to unique list.
ReDim Preserve arr(LBound(arr) To j) 'Delete the extra data from the array.
RemoveDuplicateS = arr 'Return the array.
End If
End Function
I'm trying to make a cell value dictate how many copies should be made. I'm trying to make it if the cell value goes down that it will delete the sheets that are higher than the value. I currently have the adding working no problem just can't figure out how to make it delete copies when the value gets smaller. I figure I could make a button do a check just trying to make it more automated.
Sub CreateDistro()
Dim i As Long
Dim Num As Integer
Dim Name As String
Dim xActiveSheet As Worksheet
On Error Resume Next
Application.ScreenUpdating = False
Set ActiveSheet = ActiveSheet
Num = Range("C1")
If Num > 1 Then
For i = 1 To Num
Name = ActiveSheet.Name
xActiveSheet.Copy After:=ActiveWorkbook.Sheets(Name)
ActiveSheet.Name = "Distro-" & i
Next
End If
xActiveSheet.Activate
Application.ScreenUpdating = True
End Sub
Problem of the code below: it reacts on the Range("C1") of all sheets!
You might want to use a named range or limit the number of possible sheets(e.g. minimum number of sheets = 2, template to be copied is sheet 2,only sheet1 has the Worksheet_Change code.
Sheet1:
Option Explicit
Private Sub Worksheet_Change(ByVal target As Range)
Call ChangeSheets(target)
End Sub
Module1:
Option Explicit
Sub ChangeSheets(ByVal target As Range)
Dim iCt As Integer
Dim Num As Integer
Dim maxSh As Integer
'If Not Intersect(Target, Range("C1")) Is Nothing Then
' MsgBox ("C1: " & Target.Value)
'End If
If target.Value <= 0 Then
MsgBox "Minimum worksheet count = 1!" & vbCrLf & "Nothing to do!"
Application.EnableEvents = False
target.Value = 1
Application.EnableEvents = True
Application.DisplayAlerts = False
maxSh = Sheets.Count
For iCt = maxSh To 2 Step -1
Sheets(iCt).Delete
Next iCt
Application.DisplayAlerts = True
Exit Sub
End If
If Worksheets.Count = target.Value Then
MsgBox "Worksheet count = " & target.Value & vbCrLf & "Nothing to do!"
Exit Sub
End If
'add some sheets
If Worksheets.Count < target.Value Then
Num = target.Value - Worksheets.Count
For iCt = 1 To Num
ActiveSheet.Copy After:=Sheets(Sheets.Count)
Next iCt
Exit Sub
End If
'delete some sheets
If Worksheets.Count > target.Value Then
Num = Worksheets.Count - target.Value
Application.DisplayAlerts = False
maxSh = Sheets.Count
For iCt = 0 To Num - 1
Debug.Print maxSh - iCt; ": "; Sheets(maxSh - iCt).Name
Sheets(maxSh - iCt).Delete
Next iCt
Application.DisplayAlerts = True
Exit Sub
End If
End Sub
I am a beginner with VBA and would like to know how loop columns in worksheet event. Below are the scenario.
I want to populate the data validation and "Fill this cell" comment not just in row when I select the trigger cell (target). Below is the code I tried to update but really hopeless on making it work.
Thank you so much for all your help.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Dim cel As Range
Dim myRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
'This subroutine fires when a cell value changes in this worksheet.
Set KeyCells = Range("A5:A8")
'did someone change something specifically in cell A5?
If Not Intersect(Target, KeyCells) Is Nothing Then
For Each cel In Target.Rows ' do the next steps for each cell that was changed
myRow = cel.Row
'Is the value A or C?
If Target.Value = "A" Or Target.Value = "C" Then
For Each col In Target.Columns '---I added this but not working,
myCol = col.Columns.Offset(3)
ws.Range("C" & myCol).Validation.Delete '---I added this but not working
'Remove any data validation for this cell:
ws.Range("C" & myRow).Validation.Delete
'and change the value of C5 to "Fill in this cell"
ws.Range("C" & myRow).Value = "Fill in this cell"
ws.Range("C" & myCol).Value = "Fill in this cell" '---I added this but not working
Next col '---I added this but not working
End If
Application.EnableEvents = True
Next cel
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim ws As Worksheet
Dim cel As Range
Dim myRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
'This subroutine fires when a user selects a different cell or range.
'So... it fires ALL The time so the next line is super important.
Set KeyCells2 = Range("C5:C8")
'Did someone change selection specifically to cell C5?
If Not Intersect(Target, KeyCells2) Is Nothing Then
For Each cel In Target ' do the next steps for each cell that was changed
myRow = cel.Row
'Is the value currently "Fill in this cell"?
If ws.Range("C" & myRow).Value = "Fill in this cell" Then
'Empty the cell
ws.Range("C" & myRow).Value = ""
'Add data validation to some list somewhere
With ws.Range("C" & myRow).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="=$J$1:$J$4" 'This the range that the list exists in
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
Next cel
End If
End Sub
input this to your worksheet module. Note that there are global variables declared
Private previousValue As String
Private previousRange As Range
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyIntersect1 As Range
Dim KeyIntersect2 As Range
Dim eachCell1 As Range
Dim eachCell2 As Range
Dim strHolder As String
Application.EnableEvents = False
Set KeyIntersect1 = Intersect(Target, Range("A5:A8")) '<~ get intersect
If Not KeyIntersect1 Is Nothing Then '<~ check if change happened here
For Each eachCell1 In KeyIntersect1 '<~ loop through. in case copy/pasted
strHolder = eachCell1.Value
eachCell1.Value = strHolder
If eachCell1.Value = "A" Or eachCell1.Value = "C" Then '<~ check the new values
Set KeyIntersect2 = ActiveSheet.Range(eachCell1.Offset(0, 2), eachCell1.Offset(0, 73))
For Each eachCell2 In KeyIntersect2 '<~ loop through columns
eachCell2.Value = "Fill in this cell" '<~ fill them with values
Next
End If
Next
End If
Application.EnableEvents = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim eachCell As Range
Dim KeyIntersect As Range
If previousRange.Value = "" Then '<~checks if the previous range is blank
previousRange.Value = previousValue '<~if so gives previous value
End If
If Target.Value = "Fill in this cell" Then '<~if the target is default value
previousValue = "Fill in this cell" '<~give this to value holder
Set previousRange = Target '<~and set it to previous range
'<~if there is no change it will be checked later
Target.Value = "" '<~cleans this cell.ready for input
End If
Set KeyIntersect = Intersect(Target, Range("C5:C8"))
If Not KeyIntersect Is Nothing Then
For Each eachCell In KeyIntersect
With eachCell
With .Validation
.Delete
.Add Type:=xlValidateList, _
AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, _
Formula1:="=$J$1:$J$4"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End With
Next
End If
End Sub
if there is a valid value in the previous cell. it will not give the "Fill in this cell". i am hoping that this will help.
This will copy the value of the changed cell into C5:BV5 on the Worksheet_change event:
Private Sub Worksheet_Change(ByVal Target As Range)
Target.Copy
Range("C5:BV5").PasteSpecial
Application.CutCopyMode = False
End Sub
I have able to also create some solution for this.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Dim cel As Range
Dim myRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
'This subroutine fires when a cell value changes in this worksheet.
Set KeyCells = Range("A5:A8")
'did someone change something specifically in cell A5?
If Not Intersect(Target, KeyCells) Is Nothing Then
For Each cel In Target.Rows ' do the next steps for each cell that was changed
myRow = cel.Row
For columnid = 4 to 8
'Is the value A or C?
If Target.Value = "A" Or Target.Value = "C" Then
ws.cells(myRow, columnID).Validation.Delete
'and change the value of C5 to "Fill in this cell"
ws.cells(myRow, columnID).Value = "Fill in this cell"
Next columnID
End If
Application.EnableEvents = True
Next cel
End If
End Sub