Turn a cell blank if all three adjacent cells become blank - vba

I am very inexperienced with VBA and coding in general.
I am working on a spreadsheet where column A is job numbers.
Column B is Dates.
Columns C, D and E you have to put a mark in E.G Text that has no pattern.
Now I have worked out code to put the date in column B if any mark is put in C, D or E. However if you then delete C, D or E the cell in column B is still populated with the date.
Just to be clear C, D or E could have text in them or on 2 or 1.
Now I know you could just delete the cell but where is the fun in that .
Here is the code I have so far please feel free to suggest way to make it smaller or clear it up, but mainly away to sort out my issue thanks in advance.
Private Sub Worksheet_Change(ByVal Target As Range)
Call Macro1(Target)
Call Macro2(Target)
Call Macro3(Target)
End Sub
Sub Macro1(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Not Intersect(Target, Range("c2:c100")) Is Nothing Then
With Target(1, 0)
.Value = Date
.EntireColumn.AutoFit
End With
End If
End Sub
Sub Macro2(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Not Intersect(Target, Range("d2:d100")) Is Nothing Then
With Target(1, -1)
.Value = Date
.EntireColumn.AutoFit
End With
End If
End Sub
Sub Macro3(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Not Intersect(Target, Range("e2:e100")) Is Nothing Then
With Target(1, -2)
.Value = Date
.EntireColumn.AutoFit
End With
End If
End Sub

This code either inserts a date in Column B when columns C, D or E in that row are changed and at least one of them is non-blank. Conversely, the cell in Column B is cleared if all three are blank:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Not Intersect(Target, Me.Range("c2:E100")) Is Nothing Then
With Intersect(Target.EntireRow, Me.Range("B2:B100"))
If WorksheetFunction.CountBlank(Intersect(Target.EntireRow, Me.Range("C2:E100"))) <> 3 Then
.Value = Date
.EntireColumn.AutoFit
Else
.Value = ""
End If
End With
End If
End Sub

you just add a check
If Target.Value = "" Then dateCell.ClearContents
where dateCell is the cell where the date resides in the current row
but you must also:
disable/enable events
to prevent Worksheet_Change() fire again when changing "date" cell (this occurs also when deleting a cell value
use one sub to handle all three columns
just check if target intersects columns C to E. like
If Not Intersect(.Cells, Range("C:E")) Is Nothing Then
see code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Call Macro1(Target)
End Sub
Sub Macro1(ByVal Target As Range)
Dim dateCell As Range
With Target
If .Cells.Count > 1 Then Exit Sub
Application.EnableEvents = False '<--| disable events to prevent this one fire when changing "date" cell
If Not Intersect(.Cells, Range("C:E")) Is Nothing Then
Set dateCell = Cells(.row, "B") '<--| set the cell where "date" resides
If Application.WorksheetFunction.CountA(.Parent.Cells(.row, "C").Resize(, 3)) = 0 Then '<--| if there are no values in current row columns C to E ...
dateCell.ClearContents '<--|... clear the date
Else
dateCell.Value = Date '<--|... otherwise put the date in column B and ...
dateCell.EntireColumn.AutoFit '<--| ... autofit column B
End If
End If
Application.EnableEvents = True '<--| enable events back on
End With
End Sub

Related

Excel 2016 VBA Runtime error 13

I wrote the code below to clear the cell in column D only if the value of the cell in in the corresponding row of column B changes to a value that is part of a specific list/range (B118:B124). If I change the cell in B to any value that is not part of that list, the cell in the corresponding row in D will not clear (that is what I want).
The code below works fine, except, if for example I want to delete 5 (adjacent) cells in column B at the same time, I get runtime error 13. Same is the case if I enter a new value in the first of the deleted/blank cells and then try to auto fill it down to the rest of deleted/blank cells. Basically, the code below seems to not work if I want to change multiple cells in B at the same time (autofill,...). If I only delete/change one cell (in B) at a time, it works just fine. Any help would be greatly appreciated. Thanks.
Private Sub Worksheet_Change (ByVal Target As Range)
If Not Intersect(Target, Range("B:B")) Is Nothing Then
If Application.WorksheetFunction.CountIf(Range("B118:B124"), Target) Then
Range("D" & Target.Row).ClearContents
End If
End If
End Sub
I think the issue is that COUNTIF is expecting a singular value, not a range containing values. Try this instead:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("B:B")) Is Nothing Then
For Each cell In Range(Target.Address)
If Application.WorksheetFunction.CountIf(Range("B118:B124"), cell) Then
Range("D" & cell.Row).ClearContents
End If
Next cell
End If
End Sub
EDIT: Updated answer with everyone's contributions:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("B:B")) Is Nothing Then
For Each cell In Target
If Not Intersect(cell, Range("B:B")) Is Nothing Then
If Application.WorksheetFunction.CountIf(Range("B118:B124"), cell) Then
Application.EnableEvents = False
Range("D" & cell.Row).ClearContents
Application.EnableEvents = True
End If
End If
Next cell
End If
End Sub
When selecting a range, you must process each individually in this case. Loop the range in target and done.
Private Sub Worksheet_Change(ByVal Target As Range)
For Each cell In Target
If Not Intersect(cell, Range("B:B")) Is Nothing Then
If Application.WorksheetFunction.CountIf(Range("B118:B124"), cell) Then
Range("D" & cell.Row).ClearContents
End If
End If
Next
End Sub

Worksheet_SelectionChange(ByVal Target As Range), Two Cells in Target

I am using the event handler, and I run certain events if either one cell or two cells are selected. The issue I'm having is, when two cells are selected, I don't know how to access the attributes of that 2nd cell (Ie, what it's value is). Any idea how I can access the value of the 2nd cell thats selected (I was hoping Target would be an array object, and I could just select by array index....)
Public Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo disError
If Target.Cells.Count > 2 Or Target.Address = Range("DataHist").Address Then Exit Sub
Dim curve As String
Dim Ticker As String
Dim TickerTwo As String
Dim lastValue As Double
TickerTwo = ""
If Target.Cells.Count = 1 Then
Ticker = Target.Value
lastValue = Round(Target.Offset(0, 1).Value, 3)
curve = CheckLabel(Target)
Else
' This is where the issue is --------------------------------
Ticker = Target.Cells(1, 1).Value
TickerTwo = Target.Next.Value
lastValue = Round(Target.Offset(0, 1).Value, 3)
curve = CheckLabel(Target)
' -----------------------------------------------------------
End If
Select Case curve
Case "na"
Exit Sub
Case "Test1"
Call FillChart("Test1", Ticker, lastValue, TickerTwo)
Case "Test2"
Call FillChart("Test2", Ticker, lastValue, TickerTwo)
End Select
disError:
End Sub
If you don't know if the User is going to select cells in a column or cells in a row, or even a block of cells, use a loop and counter:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim r As Range, i As Long
i = 1
If Target.Count > 1 Then
For Each r In Target
MsgBox r.Address(0, 0) & vbCrLf & i
i = i + 1
Next r
End If
End Sub
Then process when i=2. It will be the cell-to-the-right if a block or row is selected or the cell-below if part of a column is selected.
While this is not pretty code, at least it will work, even if the User selects a disjoint set of cells.
EDIT#1:
You can avoid the ugly loop if you are willing to parse Selection.Address
EDIT#2:
This code (without any loops) will work if the User selects 2 and only 2 cells:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim s As String
If Target.Count = 2 Then
s = Split(Replace(Target.Address(0, 0), ":", ","), ",")(1)
MsgBox "The second cell is: " & s
End If
End Sub

How to restrict user to entering only "Y" or "N" in a single column

I want to restrict user entry in column A and column D.
In column A, the user should enter the values as R00yyyyyy where yyyyyy is a number between 000000 and 999999.
In column D they should only enter y or n.
My code below doesn't seem to work properly. The column A part works fine, just having issues with column D.
Can anyone suggest a way to enable restricting the entry in column D?
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
Dim rngCell As Range
If Intersect(Target, Range("A:A")) Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each rngCell In Target.Cells
rngCell = UCase(rngCell)
If rngCell.Characters.Count > 9 Then
MsgBox ("Student number too long")
rngCell.Clear
End If
If Not IsEmpty(rngCell.Value) Then
Dim s As String
Dim s1 As String
Dim y As String
Dim y1 As String
s = CStr(rngCell.Value)
s1 = Left(s, 3)
y = CStr(rngCell.Value)
y1 = Right(y, 6)
If s1 <> "R00" Or Not IsNumeric(y1) Then
MsgBox ("Must be in the form R00yyyyyy, where yyyyyy is a number between 000000 and 999999")
rngCell.Clear
End If
Else
End If
Next
Application.EnableEvents = True
Dim rngCell2 As Range
If Intersect(Target, Range("D:D")) Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each rngCell2 In Target.Cells
rngCell2 = UCase(rngCell2)
Dim b As String
b = CStr(rngCell2.Value)
If b <> "y" Or b <> "n" Then
MsgBox ("The only allowable entry here is Y or N")
End If
Next
Application.EnableEvents = True
End Sub
Assuming the rest of your code is correct, you need to change your logical test from Or to And
If b <> "y" And b <> "n" Then
MsgBox ("The only allowable entry here is Y or N")
End If
You have this line
If Intersect(Target, Range("A:A")) Is Nothing Then Exit Sub
So when they change anything in column D, it's not in A and the code exits before ever reaching your code for D
You can try this code below. It checks to see if the change was in either column A or column D and exits if neither column was changed.
Then you know that the change was in either column A or column D and check exactly which column. Then you do the appropriate check and show the appropriate message box depending on the input.
To check for a simple pattern like R00yyyyyy where y is a number you can use the Like operator and use # as a placeholder for 'any number'.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngCell As Range
' exit if change was not in column A and not in column D
If Intersect(Target, Range("A:A,D:D")) Is Nothing Then Exit Sub
' get first cell of change
Set rngCell = Target.Cells(1, 1)
' disable events
Application.EnableEvents = False
' now check if change in column A
If rngCell.Column = 1 Then
If Not rngCell.Value Like "R00######" Then
MsgBox "Must be in the form R00yyyyyy, where yyyyyy is a number between 000000 and 999999"
rngCell.Clear
End If
Else 'must have been in column D
If rngCell.Value <> "y" And rngCell.Value <> "n" Then
MsgBox "The only allowable entry here is Y or N"
rngCell.Clear
End If
End If
' re-enable events
Application.EnableEvents = True
End Sub

Cell Interior Color Index Excel VBA

Based on a language table, column A = Language, B = number, C = coloredcell
I would like to know what is the VBA so whenever I type a number on Column B (using Workbook_SheetChange), C is colored with the Colorindex equal to the number typed.
On the other hand, and I am sure is part of the solution to the previous question, on VBA how do I write cell.Interior.ColorIndex = (a specific cell value, If B2=4 -> for the row, whole or until last column has data, cell.Interior.ColorIndex = 4) and color the whole row.
Thank you
The sheetchange function has target as an argument, that's the cell that you changed. You can use it to change the relevant cell:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 2 Then
Target.Offset(0,1).Interior.ColorIndex = Target.Value
'and for the whole row
Target.EntireRow.Interior.Color = Target.Offset(0,1).Interior.Color
Endif
End Sub
The code of Nick Dewitt is OK, but it color only the column C.
If you want to color the entire row, starting from C depending of how much columns are in the row :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim lastcol As Integer, i As Integer
If Target.Column = 2 Then
lastcol = Cells(Target.Row, Columns.Count).End(xlToLeft).Column
For i = 3 To lastcol
Target.Offset(0, i - 2).Interior.ColorIndex = Target.Value
Next i
End If
End Sub
Right click on the sheet's name on which you want this functionality, and click on 'View Code'.
Now you need to write a VBA function that fires on any change to the worksheet. This is an inbuilt function called Worksheet_Change(Range). The range object (it's argument) is the range that had changed when this function fired.
Private Sub Worksheet_Change(ByVal Target As Range)
End Sub
Inside the function you need to check whether the changed cell was in column B. This is done by the Column property of the Target range.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 2 Then
' The changed cell was in column B
End If
End Sub
Now you need to get the cell's value and put it as the row's ColorIndex.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 2 Then
ColorValue = Target.Value
Target.EntireRow.Interior.ColorIndex = ColorValue
End If
End Sub
Edit: To color the cells only till the last value in the row, you need to count the number of filled cells in the row. The following code does that (see the comments to understand it)
Private Sub Worksheet_Change(ByVal Target As Range)
' Check if the edited cell is in column B
If Target.Column = 2 Then
' Get the value of the edited cell
ColorValue = Target.Value
' Get the row number of the edited cell
RowNumber = Target.Row
' Get the number of filled cells in this row
CellsCount = Application.WorksheetFunction.CountA(Range(RowNumber & ":" & RowNumber))
' Apply the color formatting till the last column in this row
Range(Cells(RowNumber, 1), Cells(RowNumber, CellsCount)).Interior.ColorIndex = ColorValue
End If
End Sub

VBA( macros) copy and paste

I am trying to create a macros that will allow me each time it's activated to copy the value of a cell in worksheet 1 (the same cell but which would probably have differrent results after my calculation) and to paste the value of those results in worksheet 2 (maybe in A1;A2;A3;....... each time I make a calcul) this is a sample of a code i have written but which isn'working:
Sub recorder()
If Cells(B, i) <> Empty Then
i = i + 1
Worksheets(1).Select
Cells(A1).Copy
Worksheets(2).Select
Cells(B, i) = Cells(A1)
End If
End Sub
Any help would be appreciated. Thanks
Paste this into ThisWorkbook.
Whatever you change the value in Cell A1 on Sheet1 it will appear on Sheet2 in the nearest blank cell in column A. Note you don't need to run a macro it happens automatically.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not Sh.Index = 1 Then Exit Sub
If Not Target.Address = "$A$1" Then Exit Sub
If Worksheets(2).Range("A65536").End(xlUp).Value = Empty Then
Worksheets(2).Range("A65536").End(xlUp).Value = Target.Value
Else
Worksheets(2).Range("A65536").End(xlUp).Offset(1, 0).Value = Target.Value
End If
End Sub
I think this is what you're looking for:
Sub recorder()
Sheets(2).Cells(Rows.Count, "B").End(xlUp).Offset(1).Value = Sheets(1).Range("A1").Value
End Sub