I am attempting to allow a user to enter a value as a either a percentage, or as a number of hours - with the unused option being auto-populated with a macro using what has been input.
Using the below example if a user were to key in 25 hours, the macro would then add a formula to B2 (shown in B3 for reference) to calculate 25% (of the total shown in C2), this would also work if the user added the percentage to cell B2, it would then populate A2 with the number of hours (again using the total shown in C2).
I have got the macro working to achieve this:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Cell As Range
For Each Cell In Target
If Cell.Address = "$A$2" Then
Application.EnableEvents = False
Range("B2").Formula = "=(A2/C2)*100"
Application.EnableEvents = True
End If
Next Cell
For Each Cell In Target
If Cell.Address = "$B$2" Then
Application.EnableEvents = False
Range("A2").Formula = "=(B2*C2)/100"
Application.EnableEvents = True
End If
Next Cell
End Sub
What I am now trying to establish is there a more efficient way of
re-using this on different rows?
The columns would remain the same but ideally it would work on rows 2 through to 100. At the movement the only option I can think of is to copy the macro multiple times and reference the cells used individuall.
Any pointers or suggestions very much appreciated.
To do all the rows Between 2 and 100 then use this:
Use Intersect to detemine if the cell that changed in in a specific range.
Use R1C1 notation on the formula to ensure that the same row is being evaluated.
The code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A2:A100")) Is Nothing Then
Application.EnableEvents = False
Target.Offset(, 1).FormulaR1C1 = "=(RC[-1]/RC[1])*100"
Application.EnableEvents = True
End If
If Not Intersect(Target, Range("B2:B100")) Is Nothing Then
Application.EnableEvents = False
Target.Offset(, -1).FormulaR1C1 = "=(RC[1]*RC[2])/100"
Application.EnableEvents = True
End If
End Sub
Just change your tests to look at the column property instead and use relative references - like so:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Cell As Range
For Each Cell In Target
If Cell.Column = 1 And (Cell.Row >= 2 And Cell.Row <= 100) Then
Application.EnableEvents = False
Cell.Offset(0, 1).FormulaR1C1 = "=(RC[-1]/RC[1])*100"
Application.EnableEvents = True
End If
Next Cell
For Each Cell In Target
If Cell.Column = 2 (Cell.Row >= 2 And Cell.Row <= 100) Then
Application.EnableEvents = False
Cell.Offset(0, -1).FormulaR1C1 = "=(RC[1]*RC[2])/100"
Application.EnableEvents = True
End If
Next Cell
End Sub
Related
I am a novice coder recently getting away from web-based coding and was having an error with my script. I already can tell that this is poorly scripted and was wondering if I could receive any help.
This script is simply supposed to set the equivalent offset cell to the current time and date after any of the cells in that range is changed. I believe my poor scripting is either causing a loop or miss-calculating information as excel crashes after the event fires.
Any help would be greatly appreciated.
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("E5:E100")) Is Nothing Then
Target.Offset(0, 3) = Now()
Target.Offset(0, -1) = Target.Offset(0, -1).Value + 1
Else
If Intersect(Target, Range("F5:F100")) Is Nothing Then Exit Sub
Target.Offset(0, 2) = Now()
Target.Offset(0, -1) = Target.Offset(0, -1).Value + 1
End If
End Sub
Using If Intersect(Target, Range("E5:E100")) Is Nothing as the criteria is checking that the target doesn't intersect your range. I'm going to assume, based on the Offsets you use that you're only actually interested in columns E and F.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False 'prevent event re-firing based on changes made by the event
If Not (Intersect(Target, Range("E5:F100")) Is Nothing) Then
Target.Offset(0, (7 - Target.Column)) = Now()
Target.Offset(0, -(Target.Column - 4)) = Target.Offset(0, -(Target.Column - 4)).Value + 1
End If
Application.EnableEvents = True 'allows event to fire again
End Sub
So to clarify, the above looks for changes in columns E or F (rows 5 to 100) and if there is one writes the date stamp to the same row in column G, and the counter to column D.
You need to temprorarily stop the events from happening as you are changing the value on the sheet which then fires the event again and it continues to loop till excel crashes.
Put
Application.EnableEvents = False
At the beginning and make sure to add
Application.EnableEvents = True
At the end to turn them back on.
So:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("E5:E100")) Is Nothing Then
Application.EnableEvents = False
Target.Offset(0, 3) = Now()
Target.Offset(0, -1) = Target.Offset(0, -1).Value + 1
Application.EnableEvents = True
Else
If Not Intersect(Target, Range("F5:F100")) Is Nothing Then
Application.EnableEvents = False
Target.Offset(0, 2) = Now()
Target.Offset(0, -1) = Target.Offset(0, -1).Value + 1
Application.EnableEvents = True
End If
End Sub
I need to build a linked search function in VBA that also auto-updates after you enter data into the given search fields. I have been able to do this successfully with the following sections of code:
Autofilter search - in a standard module
Code:
Sub FilterTo1Criteria()
With Sheet3
If Range("A3") <> vbNullString Then
.AutoFilterMode = False
.Range("A6:J1015").AutoFilter
.Range("A6:J1015").AutoFilter Field:=1, Criteria1:=Range("A3")
Else
Selection.AutoFilter
End If
End With
End Sub
Sheet change/auto-update - This is in a worksheet module
Code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$3" Then
Application.EnableEvents = False
FilterTo1Criteria
Application.EnableEvents = True
End If
End Sub
However, within the sheet change page, I need cells A3:J3 to be the criteria, but I also need the auto search function to work if only A3 and D3 are filled in, or if just A3 is filled in (D3 is blank), or if just D3 is filled in (A3 is blank), but I'm having issues trying to compound the code to get this effect. How much more complicated will I have to make it? Are there some examples that someone is aware of that I can look at to glean some information from? It's hard to find any...
A slicer with a pivot table is a potential way to go, but I think some people downstream are using Excel 2003 and I don't think the slicer works back that far.
Thanks in advance!
For the function to work if either A3 or D3 are not empty, then you can concatenate the two cells and compare that to vbNullString.
For the multiple filters, you can use a loop to set them all.
eg:
Sub FilterTo1Criteria()
Dim i As Long
With Sheet3
If Range("A3") & Range("D3") <> vbNullString Then
.AutoFilterMode = False
.Range("A6:J1015").AutoFilter
For i = 1 To 10
.Range("A6:J1015").AutoFilter Field:=i, Criteria1:=Cells(3, i)
Next i
Else
Selection.AutoFilter
End If
End With
End Sub
Edit:
It looks like you wanted to set the filters as the criteria cells were filled, rather than all at once. Try this instead:
Sub FilterTo1Criteria()
Dim i As Long
With Sheet3
.AutoFilterMode = False
.Range("A6:J1015").AutoFilter
For i = 1 To 10
If .Cells(3, i) <> vbNullString Then
.Range("A6:J1015").AutoFilter Field:=i, Criteria1:=.Cells(3, i)
End If
Next i
End With
End Sub
and for the new worksheet change sub:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("$A$3:$J$3")) Is Nothing Then
Application.EnableEvents = False
FilterTo1Criteria
Application.EnableEvents = True
End If
End Sub
This will add or remove filters as you add or remove criteria (row 3).
I'm really not fantastic with VBA and have finally come to a halt.
I'm trying to automatically change 2 cell values (in the same row) based on what selection I make from a drop down.
Column L - Drop down consists of Won, Lost, Quote
Column H - GO%
Column I - GET%
What I'm trying to achieve -
If "Won" selected, then GO and GET cells equal 100%
If "Lost selected, then GO and GET cells equal 0%
I can use this formula to achieve the result but I also need users to be able to manually enter data into the GO and GET cells, effectively wiping the formula =IF($L5="Won",1,IF($L5="Lost",0,""))
My data starts in row 5 but I'll need this to loop as I have 500 rows of the same.
Thanks so much in advance if anyone can help :)
screenshot of the spreadsheet
With the code below you can select your drop list and column and automatically the value on col H & I will be compiled, otherwise if guy change the value on cell H or I the Dropdown item (in the same row) change to "Quoted", to immediate see all changing.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim controlRng, nRng As Range
Set controlRng = Range("L2:L500", "H2:I500")
Set nRng = Intersect(controlRng, Target)
Application.EnableEvents = False
If nRng Is Nothing Then Exit Sub
Select Case Target.Column
Case 12
If Target.Value = "Won" Then
Target.Offset(0, -4) = 1
Target.Offset(0, -3) = 1
ElseIf Target.Value = "Lost" Then
Target.Offset(0, -4) = 0
Target.Offset(0, -3) = 0
Else
'Do Something
End If
Case 8
Target.Offset(0, 4) = "Quoted"
Case 9
Target.Offset(0, 3) = "Quoted"
End Select
Application.EnableEvents = True
End Sub
This code will be trigger when the cell's value change, if the target fall in controlRng
Below code cannot add in Module, must be attach with the worksheet you applied Dropdown list.
In my example is Sheet1, as shown below:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim controlRng, nRng As Range
Set controlRng = Range("E2:E500")
Set nRng = Intersect(controlRng, Target)
If nRng Is Nothing Then Exit Sub
If Target.Value = "Won" Then
Target.Offset(0, -4) = 1
Target.Offset(0, -3) = 1
ElseIf Target.Value = "Lost" Then
Target.Offset(0, -4) = 0
Target.Offset(0, -3) = 0
Else
'Do Something
End If
End Sub
The code below makes sure that only one of the cells in the range("D16:E25") can contain any value, when any value/string is entered in one of the other cell's within this range, the code deletes all the others. (This part works fine, thanks to "Macro Man")
Now I'd like the code to copy(and paste to "B5") a value from a certain cell in Column B, this needs to be the the cell in the same row as the value in the range("D16:E16").
Tried the folowing code you can find below... but it didn't work.
Does annyone knows a sollution for this?
I'd prefer the workbook (cell "B5") to auto update, so without having to run macro's or press buttons.
If Not Intersect(Target, Range("D16:E25")) Is Nothing Then
If Target.Cells.Count > 1 Then
MsgBox "Please edit one cell at a time!"
Else
Application.EnableEvents = False
newVal = Target.Value
Range("D16:E25").ClearContents
Target.Value = newVal
a = ActiveCell
Application.EnableEvents = True
End If
End If
If a.Column = 4 Then
Range("B5") = Range(a).Offset(0, -2).Value
Else: Range("B5") = Range(a).Offset(0, -3).Value
End If
End Sub
Setting up a as a Range object may be a little overkill since you already have the row by looking at the single cell target.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D16:E25")) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
If Intersect(Target, Range("D16:E25")).Cells.Count > 1 Then
Application.Undo
MsgBox "Please edit one cell at a time!"
Else
Dim newVal As Variant
newVal = Target.Value
Range("D16:E25").ClearContents
Target.Value = newVal
Cells(5, 2) = Cells(Target.Row, 2).Value
End If
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
3 Issues here:
Firstly if a is set as a Range then the correct way to do it would be
Set a = ActiveCell
Secondly, if a is set as a Range, the correct way to call it in the second if function would be
If a.Column = 4 Then
Range("B5") = a.Offset(0, -2).Value
Else: Range("B5") = a.Offset(0, -3).Value
End If
instead of
If a.Column = 4 Then
Range("B5") = Range(a).Offset(0, -2).Value
Else: Range("B5") = Range(a).Offset(0, -3).Value
End If
and thirdly the above if function should be placed between
Set a = ActiveCell
and
Application.EnableEvents = True
then your program will be run as intended when the intersect is true.
I have two worksheets. On sheet 1, I have set up a macro that changes the color of the row and assigns "TRUE" value by selecting the cell or removes the color and "TRUE" value by selecting the cell again.
Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim i As Integer
Dim kod As Worksheet
Set kod = Worksheets("kodas")
If Target.Column <> 12 Then Exit Sub
If Target.Row = 1 Then Exit Sub
If Target.Cells.Count > 1 Then Exit Sub
Application.EnableEvents = False
If Target.Value <> "" Then
Target.ClearContents
Target.EntireRow.Interior.ColorIndex = 0
Else
Target.Value = "Taip"
Target.EntireRow.Interior.ColorIndex = 4
Target.EntireRow.Range(Cells(1), Cells(12)).Copy
i = kod.Cells(2, 3)
Sheets("Kodas2").Select
ActiveSheet.Paste Destination:=Sheets("Kodas2").Cells(i, 1)
End If
Application.EnableEvents = True
End Sub
*The above edited code worked for me - i = kod.Cells(2, 3) is a cell with formula: count(table4[bla])+2 that gives the first empty row number for pasting.
I now need some additional actions to be completed upon selecting the cell -OR- upon having the "TRUE" value assigned:
(1) Specific cells from the same row to be copied and pasted to sheet 2
(2) This action to be completed only once for each row (regardless of how many times the cell is selected) - perhaps locking the row would work?
The color and "True" shows which rows from sheet1 are suitable for continued work in sheet2, where some more data will be added. I essentially want to funnel only the suitable rows into the next datasheet automatically upon entry - it is important that the values are copied to the new table ByVal and not ByRef.
What about this (not using a For...Next Loop):
Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Column <> 12 Then Exit Sub
If Target.Row = 1 Then Exit Sub
If Target.Cells.Count > 1 Then Exit Sub
Application.EnableEvents = False
If Target.Value <> "" Then
Target.ClearContents
Target.EntireRow.Interior.ColorIndex = 0
Else
Target.Value = "TRUE"
Target.EntireRow.Interior.ColorIndex = 4
Target.EntireRow.Copy
DestLast = Sheets("Dest Sheet Name").Range("A" & Rows.Count).End(xlUp).Row + 1
Sheets("Dest Sheet Name").Range("A" & DestLast).Paste
End If
Application.EnableEvents = True
End Sub
Only problem is when you select the cell again, and "turn off" the row, it will still be on your "further work" sheet.