Auto-populate specific columns on excel based on selected menu using vba - vba

I am trying to auto-populate the next columns based on the selected dropdown option of the 1st column on excel.
Below sample of the initial code that I thought but it appears my approach is incorrect.
Private Sub WorksheetStore_Change(ByVal Target As Range)
Dim i As Integer
Dim intCol As Integer
intCol = shtStoreGroup.Range("A")
If Not IsEmpty(Target.value) And intCol > 1 And Target.Columns.Count = 1 And Target.Column = intCol And Target.Row > Start_Row Then
For i = Target.Row To Target.Row + Target.Rows.Count - 1
If shtStoreGroup.Columns(intCol).Rows(i).value = "Create" Then
shtStoreGroup.Columns(intCol + 2).Rows(i).value = "N/A"
shtStoreGroup.Columns(intCol + 3).Rows(i).value = "Test"
Next i
End If
End Sub

May be you're after this:
Private Sub Worksheet_Change(ByVal target As Range)
If Not ValidateTarget(target, 2) Then Exit Sub '<-- exit if function validating 'Target' returns 'False'
On Error GoTo EXITSUB ' <-- be sure to handle possible errors properly
Application.EnableEvents = False '<--| disable events handling not to run this sub on top of itself
Select Case UCase(target.Value)
Case "CREATE"
target.Offset(, 2).Value = "N/A"
target.Offset(, 3).Value = "Test"
Case "DELETE"
target.Offset(, 2).Value = "???"
target.Offset(, 3).Value = "Test??"
End Select
EXITSUB:
Application.EnableEvents = True '<--| restore events handling
End Sub
Function ValidateTarget(target As Range, Start_Row As Long) As Boolean
With target
If .columns.Count > 1 Then Exit Function
If .Column <> 1 Then Exit Function
If .Row <= Start_Row Then Exit Function
If IsEmpty(.Value) Then Exit Function
ValidateTarget = True
End With
End Function
place the above code in the relevant worksheet ("shtStoreGroup"?) code pane, and NOT in a normal module code pane

I don't think you need worksheet_change() function
with a combobox named cbTest I would do it like
Option Explicit
Sub fill()
cbTest.AddItem ("Value1")
cbTest.AddItem ("Value2")
End Sub
Private Sub cbTest_Change()
Select Case cbTest.Value
Case "Value1"
Cells(1, 1).Value = "Test"
Case "Value2"
Cells(1, 2).Value = "Test2"
End Select
End Sub

Related

Set Variable equal to multiple selected cells

I am attempting to get my code to work when multiple cells are selected/changed. I'm not too sure where to go from here as I'm having trouble setting a variable to a target when the target is a multi-cell selection.
An example of what I need would be: All cells in column 1 are selected and deleted, so subsequently I want all cells in column 2 to also be deleted. Instead the code returns an error and does not delete column 2 for any of the selected rows.
Here is the code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
Application.ScreenUpdating = False
If Target.Column = 1 Then
Application.EnableEvents = False
Dim OldValue As String
Dim NewValue As String
NewValue = Target.Value
Application.Undo
OldValue = Target.Value
Target.Value = NewValue
Application.EnableEvents = True
If OldValue = "" Then
Exit Sub
Else
Application.EnableEvents = False
Target.Offset(0, 1).ClearContents
MsgBox "Contents related to this drop-down have been cleared"
End If
End If
Exithandling:
Application.EnableEvents = True
Exit Sub
Application.ScreenUpdating = True
End Sub
Something like this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range, oldVal, newVal, i As Long, num As Long, c As Range
On Error GoTo haveError:
'only process the part of Target which overlaps with ColA...
Set rng = Application.Intersect(Target, Me.Columns(1))
'run some checks before proceeding...
If rng Is Nothing Then Exit Sub
If rng.Cells.Count = Me.Columns(1).Cells.Count Then Exit Sub 'ignore full-column operations
If rng.Areas.Count > 1 Then Exit Sub 'handling multiple areas will be more complex...
If Application.CountBlank(rng) = 0 Then Exit Sub 'no empty cells: nothing to do here
Application.EnableEvents = False
newVal = GetArray(rng)
Application.Undo
oldVal = GetArray(rng)
rng.Value = newVal
For Each c In rng.Cells
i = i + 1
If newVal(i, 1) = "" And oldVal(i, 1) <> "" Then
c.Offset(0, 1).ClearContents
num = num + 1
End If
Next c
If num > 0 Then MsgBox "Contents related to drop-down(s) have been cleared"
haveError:
If Err <> 0 Then Debug.Print Err.Description
Application.EnableEvents = True
End Sub
'normalizes the array vs. scalar returned when calling .Value
' on a multi- vs. single-cell range
Function GetArray(rng As Range)
Dim arr
If rng.Count > 1 Then
arr = rng.Value
Else
ReDim arr(1 To 1, 1 To 1)
arr(1, 1) = rng.Value
End If
GetArray = arr
End Function

VBA save value from cell before it changes

I have a spreadsheet where i implement a score board.
The behavior i need is when the cell that has the score value rises the cell near it, on column b, changes it's color to green, when the the cell score value goes down the cell near it changes it's color to red.
The cell range where the score is changing is e5:e67
In short:
When the user inputs a number in column f, the score raises in column e, and in column b (on same row) the color must change to green or red
I made this VBA code, but without luck.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("e5:e67")) Is Nothing Then
If Target.Column = 5 Then
thisRow = Target.Row
Dim OldValue As Variant
Application.EnableEvents = False
Application.Undo
OldValue = Target.Value
Application.Undo
Application.EnableEvents = True
If OldValue < Target.Value Then
Range("b" & thisRow).Interior.ColorIndex = 4
ElseIf OldValue > Target.Value Then
Range("b" & thisRow).Interior.ColorIndex = 3
End If
End If
End If
End Sub
Here is a screen capture of my ranking sheet:
Try by intercepting the Worksheet_Calculate event. You need to save the old value in a static local array, that I call oldVal.
Private Sub Worksheet_Calculate()
Static oldVal
If IsEmpty(oldVal) Then
oldVal = Application.Transpose(Range("e5:e67").Value2)
ReDim Preserve oldVal(5 To 67)
Exit Sub
End If
Dim i As Long
For i = LBound(oldVal) To UBound(oldVal)
If oldVal(i) > Cells(i, "E").Value2 Then Cells(i, "B").Interior.ColorIndex = 3
If oldVal(i) < Cells(i, "E").Value2 Then Cells(i, "B").Interior.ColorIndex = 4
oldVal(i) = Cells(i, "E").Value2
Next
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Integer
If Not Intersect(Target, Range("e6:e67")) Is Nothing Then
If Target.Offset(-1) < Target Then
i = 4
Else
i = 3
End If
Range("b" & Target.Row).Interior.ColorIndex = i
End If
End Sub

VBA Change Event Calulation

I am trying to use the Worksheet Change Event in Excel VBA, but it doesn't seem to working how I thought it would.
I basically want to calculate a cells value (Q2) when the value of another cell (R2) is changed or vise versa.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Intersect(Target, Range("O:R")) Is Nothing Then Exit Sub
Application.EnableEvents = False
If Target.Column = 3 Then
'User has changed something in column Q:
Target.Offset(0, 1).Value = Cells(2, 3) * Cells(2, 1)
If Target.Column = 4 Then
'User has changed something in column R:
Target.Offset(0, -1).Value = Cells(2, 3) / Cells(2, 1)
End If
Application.EnableEvents = True
End Sub
Don't avoid working with multiple cells as the Target. Intersect can quickly parse down even deleting several full columns to the appropriate range and further restrict to the worksheet's UsedRange.
Add error control, especially to the division operation. A blank cell in A2 will quickly choke the calculation on a 'divide-by-zero'.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
'deal with multiple cells as bel;ow; don't avoid them
'If Target.Cells.Count > 1 Then Exit Sub
'use the Intersect to determine if relevant cells have been chanmged
'note: columns Q:R, not O:R and restrict to the used range
If Not Intersect(Target, Target.Parent.UsedRange, Range("Q:R")) Is Nothing Then
On Error GoTo Safe_Exit
Application.EnableEvents = False
Dim trgt As Range
For Each trgt In Intersect(Target, Target.Parent.UsedRange, Range("Q:R"))
Select Case trgt.Column
Case 17
'guard against multiplying a number by text
If Not IsError(Cells(2, 3).Value2 * Cells(2, 1).Value2) Then
trgt.Offset(0, 1) = Cells(2, 3).Value2 * Cells(2, 1).Value2
End If
Case 18
'guard against possible #DIV/0! error and divding a number by text
If Not IsError(Cells(2, 3).Value2 / Cells(2, 1).Value2) Then
trgt.Offset(0, -1) = Cells(2, 3).Value2 / Cells(2, 1).Value2
End If
End Select
Next trgt
End If
Safe_Exit:
Application.EnableEvents = True
End Sub
I'm pretty sure that the actual calculation should involve a variable like trgt.Row but your posted calculation only used C2 and A2 as static cell references to divide/multiply against each other.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.CountLarge > 1 Then Exit Sub
If Intersect(Target, Range("O:R")) Is Nothing Then Exit Sub
Application.EnableEvents = False
'If Target.Column = 17 Then 'CHANGED HERE!
'User has changed something in column Q:
'Target.Offset(0, 1).Value = Cells(2, 3) * Cells(2, 1)
'End If
'If Target.Column = 18 Then 'CHANGED HERE!
'User has changed something in column R:
'Target.Offset(0, -1).Value = Cells(2, 3) / Cells(2, 1)
'End If
' I leave the If-versions above for info, but Select Case is better sometimes
Select Case Target.Column
Case 17 ' column Q
Target.Offset(0, 1).Value = Cells(2, 3) * Cells(2, 1)
Case 18 ' column R
Target.Offset(0, -1).Value = Cells(2, 3) / Cells(2, 1)
End Select
Application.EnableEvents = True
End Sub
Q Column is number 17, and Column R is number 18 as shown above.

Getting numbers to automatically move up when inserting lines

Currently working on an excel sheet to rank projects, we would like it to automatically increase the numbers if we insert a new line and input an existing number rank. If we put in a line and type in 9 for its rank we want the pre existing 9 to move to 10 and the old 10 to move to 11 etc. I have kind of worked it out, however my code automatically numbers the first row as 1 and so forth. This is what I have so far.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim I As Integer
I = 1
Application.EnableEvents = False
For I = 1 To 20
Range("A" & I).Value = I
Next
Range("A21").Value = ""
Application.EnableEvents = True
End Sub
You could loop through every cell in column A and, if its value is greater than (or equal to) the one just changed, increment it by one:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim I As Long
Dim v As Long
Dim r As Range
Set r = Application.Intersect(Range("A:A"), Target)
If r Is Nothing Then
Exit Sub
End If
If r.Count > 1 Then
Exit Sub
End If
If IsEmpty(r.Value) Then
Exit Sub
End If
I = 1
v = r.Value
If Application.CountIf(Range("A:A"), v) > 1 Then ' Only change things if this
' value exists elsewhere
Application.EnableEvents = False
For I = 1 To Cells(Rows.Count, "A").End(xlUp).Row
If Cells(I, "A").Address <> r.Address Then
If IsNumeric(Cells(I, "A").Value) Then ' skip cells that aren't numeric
If Cells(I, "A").Value >= v Then
Cells(I, "A").Value = Cells(I, "A").Value + 1
End If
End If
End If
Next
Application.EnableEvents = True
End If
End Sub

Auto Formatting Race Result Times

I have started creating a VBA Macro that helps me add formatting to rows as I add them with a custom NumberFormat. But since My partner and I sometimes Enter item like "ss.00" and this messed up the cell. So I started writing out another Sub where it checks if its missing the semicolon. How can I add "0:" to the front of this value automatically where the cell would show "0:50.20", Everytime I do it, it ends up being a long number.
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Target.Cells.Count = 1 Then
If Target.Column = 1 Then
If Target.Row < 24 And Target.Row > 1 Then
Set FirstRow = Target.Offset(0, 1)
Set LastRow = Target.Offset(0, 11)
If Target.Value <> "" Then
For Each Cel In Range(FirstRow, LastRow)
Cel.NumberFormat = "m:ss.00;#"
Next
Else
If MsgBox("This will erase the row! Are you sure?", vbYesNo) = vbNo Then
Exit Sub
Else
For Each Cel In Range(FirstRow, LastRow)
Cel.ClearContents
Next
End If
End If
End If
End If
Const sCheckAddress As String = "B2:L24"
Dim rngIntersect As Range
On Error Resume Next
Set rngIntersect = Intersect(Me.Range(sCheckAddress), Target)
On Error GoTo 0
If Not (rngIntersect Is Nothing) Then
If Target.Value2 <> "" Then
If InStr(Target.Value2, ":") < 1 Then
End If
End If
End If
End If
End Sub
Maybe this would help you :
If InStr(Target.Value2, ":") < 1 Then
' ":" not found
Target.Value = CStr("0:" & Target.Value)
Else
' ":" found
'Nothing to add
End If