VBA Code. Trying to fix the "IF" PARTS - vba

So I have this written in my VBA:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("G9:G28")) Is Nothing Then
Application.EnableEvents = False
With Target
If IsNumeric(.Value) Then .Value = .Value / 100
End With
Application.EnableEvents = True
End If
End Sub
When I try to erase the data in the "G" Cells a 0% stays locked in. I think bc ".Value/100" is the 0% that my code says must go inside that cell. The above code is suppose to turn any number into a percentage but I think I wrote it and when its suppose to be blank it shows a "0%" but I want it to be blank.

I would use a loop:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range
If Not Intersect(Target, Range("G9:G28")) Is Nothing Then
Application.EnableEvents = False
For Each r In Intersect(Target, Range("G9:G28"))
If IsNumeric(r.Value) Then r.Value = r.Value / 100
Next r
Application.EnableEvents = True
End If
End Sub
This code will allow more than one cell to be changed.

Try the code below:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("G9:G28")) Is Nothing Then
If Target.Count <= 1 Then ' make sure not more than 1 cell is changed
Application.EnableEvents = False
With Target
If IsNumeric(.Value) Then
If .Value = 0 Then
.Value = ""
Else
.Value = .Value / 100
End If
End If
End With
Application.EnableEvents = True
End If
End If
End Sub

Target can be SEVERAL cells.
And an array divided by 100 makes no sense.

Just test if the cell in question is empty with IsEmpty(Target.Value) before performing the conversion to percent, like this:
If Not IsEmpty(.Value) And IsNumeric(.Value) Then .Value = .Value / 100

Related

VBA - Change cell value when clicked from/to yes/no for multiple merged cells

I have created a form that will give the user the choice to pick from 7 different options which will all be default blank. When they click the cell next to the option it will change from blank to "yes" and when clicked again it will remove the text and so on. Cells R33 and S33 are merged and the code works fine there but i need the code to run across multipe cells that are also merged such as (R35-S35, R37-S37, R39-S39 & R41-S41.
Can you help me out with this please?
Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
Application.EnableEvents = False
If Not Intersect(Target, Range("R33").MergeArea) Is Nothing Then
Select Case True
Case Target.Cells(1) = "yes"
Target.Cells(1) = ""
Case Target.Cells(1) = ""
Target.Cells(1) = "yes"
End Select
Range("A1").Select
End If
Application.EnableEvents = True
End Sub
You can select multiple cells and that should be accounted for. A static union of the merge areas will not have to be redefined on every selection.
Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
static mrng as range
if mrng is nothing then
set mrng = union(cells(33, "R").mergearea, cells(35, "R").mergearea, _
cells(37, "R").mergearea, cells(39, "R").mergearea, _
cells(41, "R").mergearea)
end if
If Not Intersect(Target, mrng) Is Nothing Then
Application.EnableEvents = False
dim t as range
for each t in Intersect(Target, mrng)
select case lcase(t.value2)
case "yes"
t = vbnullstring
case else
t = "Yes"
end select
next t
Range("A1").Select
End If
Application.EnableEvents = True
End Sub

Writing to multiple cells using If Target.Address = " " Then

I have basic code that allows the values written to this cell to be summed while maintaining the cumulative value. So if I were to type "4" into the cell, and then type "10" into the cell, the result would be "14" (not just the second value entered of "10"). Here is what I have and I must say that it works.
#
Option Explicit
Dim oldvalue As Double
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Target.Address = "$J$5" Then
On Error GoTo fixit
Application.EnableEvents = False
If Target.Value = 0 Then oldvalue = 0
Target.Value = 1 * Target.Value + oldvalue
oldvalue = Target.Value
fixit:
Application.EnableEvents = True
End If
End Sub
#
However, I want to apply this treatment to more than just cell J5. Say for example, I want the same code logic applied to cell R5 as well.
Thur far I have tried using
OR
and I have also tried using
If Not Intersect (Target, Range("J5:R5")) Is Nothing Then
But each of these approaches ties the two cells together (so that what I enter into one gets summed into both - each cell is summing values added to the other). I can't figure it out to save my life, so took to this forum in the hopes of finding someone smarter than me.
Maybe (this is assuming existing logic is correct....not sure why you set old value to 0 if Target = 0 and what value the *1 adds?)
Option Explicit
Dim oldvalueJ As Double
Dim oldValueR As Double
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
On Error GoTo fixit
Application.EnableEvents = False
Select Case Target.Address
Case "$J$5"
If Target = 0 Then oldvalueJ = 0
Target = Target + oldvalueJ
oldvalueJ = Target
Case "$R$5"
If Target = 0 Then oldValueR = 0
Target = Target + oldValueR
oldValueR = Target
End Select
fixit:
Application.EnableEvents = True
End Sub
This is a bit more dynamic by allowing you to add unlimited cells; it also validates user input
Standard Module
Option Explicit 'Generic Module
Public Const WS1_MEM_RNG = "C5,J5,R5" 'Sheet1 memory cells
Public prevWs1Vals As Object
Public Sub SetPreviousWS1Vals()
Dim c As Range
For Each c In Sheet1.Range(WS1_MEM_RNG).Cells
If Len(c.Value2) > 0 Then prevWs1Vals(c.Address) = c.Value2
Next
End Sub
Sheet1 Module
Option Explicit 'Sheet1 Module
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Target.CountLarge = 1 Then
If Not Intersect(Target, Me.Range(WS1_MEM_RNG)) Is Nothing Then GetPrevious Target
End If
End Sub
Private Sub GetPrevious(ByVal cel As Range)
Dim adr As String: adr = cel.Address
Application.EnableEvents = False
If Not IsError(cel.Value) And IsNumeric(cel.Value2) And Not IsNull(cel.Value) Then
If IsDate(cel.Value) Then
cel.NumberFormat = "General"
cel.Value2 = prevWs1Vals(adr)
Else
If cel.Value2 = 0 Then prevWs1Vals(adr) = 0
cel.Value2 = cel.Value2 + prevWs1Vals(adr)
prevWs1Vals(adr) = cel.Value2
End If
Else
cel.Value2 = prevWs1Vals(adr)
End If
Application.EnableEvents = True
End Sub
ThisWorkbook Module
Option Explicit 'ThisWorkbook Module
Private Sub Workbook_Open()
If prevWs1Vals Is Nothing Then Set prevWs1Vals = CreateObject("Scripting.Dictionary")
SetPreviousWS1Vals
End Sub
It can also enforce positives only
use commas to separate ranges, and add a Worksheet_SelectionChange() event to record the last user selected cell
Option Explicit
Dim oldvalue As String
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Intersect(Target, Range("J5,R5")) Is Nothing Then Exit Sub
If Target.Value = 0 Then Exit Sub
On Error GoTo fixit
Application.EnableEvents = False
Target.Value = Target.Value + oldvalue
fixit:
Application.EnableEvents = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.CountLarge = 1 Then oldvalue = Target.Value
End Sub

Excel VBA changing value of cell with one click - assign this to multiple ranges independently

I am trying to setup a vba code so I will be able to click on a specific number of cells and have these cells switch between "nothing", "cr" & "cv". So far I have this in my code but I need to assign it to multiple targets but I can't seem to get them to work independently.
Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
Application.EnableEvents = False
With Target
If .Address = Range("A1").Address Then
Select Case .Value
Case ""
.Value = "CR"
Case "CR"
.Value = "CV"
Case "CV"
.Value = ""
Case Else
.Value = "CR"
End Select
End If
End With
Range("A2").Select
Application.EnableEvents = True
End Sub
This would be one way of achieving what you want.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' 07 May 2017
Dim Rng As Range
Set Rng = Range("A1,B2:B4,C3,D4")
If Not Application.Intersect(Target, Rng) Is Nothing Then
MsgBox "Cell " & Target.Address(False, False) & " was clicked."
End If
End Sub
I observed that your first Select statement is superfluous because it is identical with the last. :-)
Mapleleaf,
I'm not altogether sure that I understand completely what you're after, but this worked for me:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.EnableEvents = False
For Each T In Target
With T
'If .Address = Range("A1").Address Then
Select Case .Value
Case ""
.Value = "CR"
Case "CR"
.Value = "CV"
Case "CV"
.Value = ""
Case Else
.Value = "CR"
End Select
'End If
End With
Next
Range("A2").Select
Application.EnableEvents = True
End Sub
If this turns out not to be what you were trying to accomplish, I suspect you'll be able to easily adapt it to do what you need. Hope this helps. If you have any questions, don't hesitate.
This is what I came up with and it works great. Thank you for your help.
Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
Application.EnableEvents = False
If Target.Cells.Count = 1 Then
If Not Intersect(Target, Range("C8:C10:C12:C14:C16:I8:I10:I12:I14:I16:O8:O10:O1:O14:O16:U8:U10:U12:U14:U16:AA8:AA10:AA12:AA14:AA16:AG8:AG10:AG12:AG14:AG16:AM8:AM10:AM12:AM14:AM16")) Is Nothing Then
Select Case Target.Value
Case ""
Target.Value = "CR"
Case "CR"
Target.Value = "CV"
Case "CV"
Target.Value = ""
Case Else
Target.Value = "CR"
End Select
Range("B2").Select
End If
End If
Application.EnableEvents = True
End Sub

How to end infinite "change" loop in VBA

I have a problem with visual basic. I want to make a macro/function that will multiply a number I enter by 3 and give a result in the same cell. I tried something like this:
Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$Q$21" Then
Target.Value = Target.Value * 3
End If
End Sub
but it doesn't work - I'm getting results like "xE25" because it keeps multiplying.
I'd like it to stop after first iteration or work only when I press "enter" not with every change in the cell.
It's quite easy to put a result in different cell, but it's not my point.-----Edit:
I edited "If" line to :
If (Target.Column = 5 Or Target.Column = 11 Or Target.Column = 17 Or Target.Column = 23) And (Target.Row >= 19 And Target.Row <= 24) And Target.Value <> "" Then so it would work on all cells that I need. After that, the best solution is the way given by #Chrismas007, because it doesn't prompt an error when trying to delete data in few cells at once.
With error handling to ensure .EnableEvents goes back to True:
Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo CleanExit
If Target.Address = "$Q$21" Then
Application.EnableEvents = False
Target.Value = Target.Value * 3
End If
CleanExit:
Application.EnableEvents = True
On Error GoTo 0
End Sub
When a Worksheet_Change event macro changes a value, you need to set Application.EnableEvents to false or risk triggering another event and having the macro run on top of itself.
Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$Q$21" Then
Application.EnableEvents = False
Target.Value = Target.Value * 3
Application.EnableEvents = True
End If
End Sub
While I would usually involve some error control in order that the .EnableEvents was always reset to true, the above should get you started.
You need to disable events to prevent recursion:
Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$Q$21" Then
application.enableevents = false
Target.Value = Target.Value * 3
application.enableevents = true
End If
End Sub
Just as an alternative, you can also use your own variable rather than tinkering with EnableEvents, though it will mean your code responds twice even though it doesn't actually do anything the second time round:
Dim bSkipEvents as Boolean
Sub Worksheet_Change(ByVal Target As Range)
If bSkipEvents then exit sub
If Target.Address = "$Q$21" Then
bSkipEvents = True
Target.Value = Target.Value * 3
bSkipEvents = False
End If
End Sub
This is also the sort of approach you need with userforms and most events for activex controls on worksheets.

macros still running even if the cell/ range value changed

I want to select a range (B2) resulting from the dropdown referring from another range (source from F2: F5). I mean I do not need to change the values in the macro code if one day I had to change the data in the reference range (F2: F5). If the value in the range B2 is equal to the value of the text on one of the list range F2: F5 then the macro will run.
I want something like this:
Private Sub Worksheet_Calculate(ByVal Target As Range)
If Target.Address = "$B$2" Then
If Range("B2").Value = Range("F3").Value Then
Rows("10:20").EntireRow.Hidden = False
Rows("11:21").EntireRow.Hidden = True
ElseIf Range("B2").Value = Range("F4").Value Then
Rows("10:20").EntireRow.Hidden = True
Rows("11:21").EntireRow.Hidden = False
..............
..............
..............
End If
End If
End Sub
How can I re-write this logic in a way that is VBA friendly? Thanks for your help
You'll want to use a Worksheet_Change... This activates on any changes to the sheet. (Put this code in the SHEET's CODE). First it checks to make sure the cell is B2 then it checks to make sure B2's Value is found in your reference cells. Then it does a Select Case for each possible option.
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("B2")) is Nothing Then
Exit Sub
End If
Select Case Range("B2").Value
Case Range("F2").Value
'Do Something
Case Range("F3").Value
'Do Something
Case Range("F4").Value
'Do Something
Case Range("F5").Value
'Do Something
Case Else
Exit Sub
End Select
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
With Target
If .Address = "$B$2" Then
Application.EnableEvents = False
Select Case .Value
Case Range("F3").Value
Rows("10:20").EntireRow.Hidden = False
Rows("11:21").EntireRow.Hidden = True
Case Range("F4").Value
Rows("10:20").EntireRow.Hidden = True
Rows("11:21").EntireRow.Hidden = False
End Select
Application.EnableEvents = True
End If
End With
End Sub
Why do you not use the Select case structure:
Private Sub Worksheet_Calculate(ByVal Target As Range)
If Target.Address = "$B$2" Then
Select Case Range("B2").Value
case Range("F3").Value
Rows("10:20").EntireRow.Hidden = False
Rows("11:21").EntireRow.Hidden = True
case Range("B2").Value = Range("F4").Value Then
Rows("10:20").EntireRow.Hidden = True
Rows("11:21").EntireRow.Hidden = False
..............
..............
..............
End Select
End If
End Sub