I am trying to keep track of changes (to be appeared in a chart) upon every changes made in the worksheet using this reference (codes are copied below as example reference).
The changes in the worksheet actually can be made by several List Boxes (form Control Menu) and other cells e.g. Input 3 and 4. Let's say the resulting value caused by any change appears in the cell G14, and as the example code I want to keep them in I14 (as in the example image).
The formula might be e.g. D14 + E14 + K14 + L14 where K14 and L14 are values linked to the ListBoxes.
Selections in Input 3 and 4 trigger Worksheet_Change but selections in List Box apparently don't, shall I add a macro for List Box callback in which Worksheet_Change gets triggered?
Apart from that, if there is any better saving the results method, please mention it.
Many thanks in advance!
Dim xVal As String
Private Sub Worksheet_Change(ByVal Target As Range)
Static xCount As Integer
Application.EnableEvents = False
If Target.Address = Range("G14").Address Then
Range("I14").Offset(xCount, 0).Value = xVal
xCount = xCount + 1
Else
If xVal <> Range("G14").Value Then
Range("I14").Offset(xCount, 0).Value = xVal
xCount = xCount + 1
End If
End If
Application.EnableEvents = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
xVal = Range("G14").Value
End Sub
As you are asking about trigger event to run a macro on selection of listbox value (form control), I believe this could be considered as answer. I am sure someone with better knowledge will improve it.
Worksheet_Change event occurs when a cell or range of cells is changed manually (not by any auto process like calculation or selection of listbox value)
There can be different scenarios
First
There is no link between calculation of cells affected by the listbox change. Say, in First ListBox, you select 10, and cell A2 is updated to 10 and cell A3 is calculated value changed to 30. Then You select in second listbox 15 and cell B2 is changed to 15 and cell B3 is calculated independently if A2 and A3 to 90.In this case these are independent listboxes and their results. So, in this case, you can assign macro to each listbox which will run every time you change value in each listbox.
Second
Dependent calculations: Say the desired result for tracking is in D3 which will be calculated only on selection of four listbox values in A2, B2, C2 and D2. In this case you will not like to run macro for every list change but only after selecting values in all listboxes and calculation of D3. So in that case, instead of assigning macros to all the listboxes you could assign it only to last listbox.
Third
By now you must have understood there are two events taking place. One is selection of listbox value and second is calculation. In the second scenario, if you want to run macro for every change in calculation, say when you select A2 and when you select B2, etc. then you can simply use calculation event instead of assigning macro to every listbox. It will run everytime when a value is changed causing worksheet to calculate.
For assigning macro to listbox (form control) --- You can directly assign a macro to the list box.. First create a macro in VBA . Then Just right click on the list box and click assign macro. then select a macro to be assigned. .. The macro will be run when you click the listbox to change the value
Also, as you want to track the result calculated with macro, you need the sheet to be calculated first. Start the macro with Worksheet.Calculate method to be safe (in case formula results are not updated for some reason).
Tahnks to #Naresh, solved the problem in the following way, any improvement editis more than welcome since I know the codes might seem inefficient!
Dim xVal As String
Public Function customRecorder(Target As String)
Static xCount As Integer
Application.EnableEvents = False
Range("I14").Offset(xCount, 0).Value = xVal
xCount = xCount + 1
Application.EnableEvents = True
End Function
Private Sub Worksheet_Calculate()
xVal = Range("G14").Value
customRecorder (Range("G14"))
End Sub
Related
I want to hide columns with value 0 in range G4:FC4
The cell can take values 0 (in that case the columns should be hidden) or 1 (in that case they should be visible). The value 0 or 1 is formula based and depends on the drop down input value in cell D2.
When I change the value in D2 manually the macro works fine, but when I use the drop down box it doesn't. Please find below my code. Any advice?
Many thanks
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range
Dim c As Range
For Each c In Sheets("P_MM6").Range("G4:FC4").Cells
c.EntireColumn.Hidden = True
If c.Value = 1 Then
c.EntireColumn.Hidden = False
End If
Next c
End Sub
Changing manually vs drop-down should not matter, except if perhaps somewhere else in your code events are being disabled and not turned back on, or maybe calculations are set to manual and thus do not create a change in the formula value, so, even though the code fires, the column values don't change.
That said, the code below will help you because it will not try to hide/unhide on every cell change, but only when D2 changes.
Private Sub Worksheet_Change(ByVal Target As Range)
If target.address = "$D$2" Then
Dim c As Range
For Each c In Sheets("P_MM6").Range("G4:FC4").Cells
c.EntireColumn.Hidden = c.Value = 0
Next c
End If
End Sub
Also make sure that calculations are set to automatic and they are not being turned off somewhere in your code and also that events are not being disabled and not turned back on somewhere else in the code.
If all that doesn't help, put a break point on the Worksheet_Change line of code and change the cell via drop-down and see what happens.
How can I Lock/Unlock a cell(A1) based on value(yes/no) in another cell(A2) using conditional formatting?
There's lots of resources online showing how to do this. Here's an article that helped explain it to me:
http://database.ittoolbox.com/groups/technical-functional/excel-l/how-to-lockunlock-an-excel-cell-based-on-the-contents-of-another-cell-4625040
In case that link dies, here is the gist of it:
To do what you are describing, you will need to create an event procedure that Excel will call whenever the contents of the worksheet are changed. Start by opening the Visual Basic window (press Alt+F11). You should see s tree view in a pane at the top left; find the name of the worksheet in that view, and double-click the name. This will open the code module associated with that worksheet in the large pane on the right.
At the top of the large pane you will see two drop-down lists. Initially, the one on the left will display (General), while the one on the right will display (Declarations). Click the triangular arrowhead at the right end of the left list, and select Worksheet instead.
Excel will automatically add the "skeleton" of a SelectionChange event procedure. That's not what we want, but it won't hurt anything.
Excel will also change the selection in the right-hand drop-down list to SelectionChange. Open that list and select Change instead. Excel will add a second event procedure, which should look like this:
Private Sub Worksheet_Change(ByVal Target As Range)
End Sub
The blinking cursor will be positioned on the blank line of this skeleton.
You want to add code to the Worksheet_Change procedure to examine the contents of the G2 cell, and change the state of the G3:G66 range. This requires one IF statement, and a couple of assignment statements:
Private Sub Worksheet_Change(ByVal Target As Range)
If ActiveSheet.Cells(2, 7).Text = "X" Then
ActiveSheet.Range(Cells(3, 7), Cells(66, 7)).Locked = True
Else
ActiveSheet.Range(Cells(3, 7), Cells(66, 7)).Locked = False
End If
End Sub
The IF statement tests the current contents of cell G2 (the Cells() method takes a row -- 2 -- and a column number -- 7 -- to identify the cell; column G is the seventh column). The two assignment statements change the Locked property of the range; one locks the cells, the other unlocks them.
Of course, if your code were more complicated, you would want to avoid running it every time anything on the worksheet changes. To avoid executing the code too often, you can use the Target parameter that is passed to the event procedure:
If Intersect(ActiveSheet.Cells(2, 7), Target) _
Is Not Nothing Then
This conditional statement uses the Intersect() function to determine if cell G2 ( ActiveSheet.Cells(2, 7)) is included in Target.
Therefore, the complete event procedure would look like:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(ActiveSheet.Cells(2, 7), Target) Is Not Nothing Then
If ActiveSheet.Cells(2, 7).Text = "X" Then
ActiveSheet.Range(Cells(3, 7), Cells(66, 7)).Locked = True
Else
ActiveSheet.Range(Cells(3, 7), Cells(66, 7)).Locked = False
End If
End If
End Sub
I'm trying execute this code when a button is pressed in the sheet,
but I receive this error :
Call Worksheet_Change -> Compilation error - The argument is not optional
Sub Worksheet_Change(ByVal Target As Range)
Set MyPlage = Range("A1:I1200")
For Each cell In MyPlage
Select Case cell.Value
Case Is = "OK"
cell.EntireRow.Interior.ColorIndex = 43
Case Is = "NOTOK"
cell.EntireRow.Interior.ColorIndex = 3
Case Is = "P"
cell.EntireRow.Interior.ColorIndex = 6
Case Else
cell.EntireRow.Interior.ColorIndex = xlNone
End Select
Next
End Sub
Private Sub CommandButton1_Click()
Call Worksheet_Change
End Sub
Look at the Worksheet_Change sub - it has '(ByVal Target As Range)' as an argument. That means that when the worksheet changes, the sub triggers, and it carries the value of the range which changed. This allows you to manipulate the last edited cell, for example. In your command button, you aren't providing the Worksheet_Change sub with information about what Range you are referring to. As the error states, that argument is not optional.
However in your case, I can't see why you need to use the Worksheet_Change sub at all. I suggest you simply take the code currently within the top sub, and put it fully within the button's sub.
The worksheet_change sub requires a range to be passed to it. Something like this should make it run:
Private Sub CommandButton1_Click()
Call Worksheet_Change(Range("A1"))
End Sub
However putting this in the worksheet change event means that it triggers and runs every time anything in the sheet changes. The range value passed to the change event (A1 in my example above) is always the range of whatever cell/cells changed in the sheet.
If you want it to run ONLY when the button is pressed, name the sub something else and remove the 'byval target as range' argument to avoid having to pass a range to the sub. Something like:
Sub testSub()
Set MyPlage = Range("A1:I1200")
For Each cell In MyPlage
Select Case cell.Value
Case Is = "OK"
cell.EntireRow.Interior.ColorIndex = 43
Case Is = "NOTOK"
cell.EntireRow.Interior.ColorIndex = 3
Case Is = "P"
cell.EntireRow.Interior.ColorIndex = 6
Case Else
cell.EntireRow.Interior.ColorIndex = xlNone
End Select
Next
End Sub
Private Sub CommandButton1_Click()
Call testSub
End Sub
If you want it to run any time the sheet is changed and also when the button is pressed, you're fine as you are, but I can't see that you're doing anything in your change sub that needs it to be in the worksheet change event?
Edit: Your problem is that you're looping through a range and undoing what you previously. Consider that this is your data:
__|_A__|_B_|___C___|__D__|_E_|_F_|_
1_|_OK_|___|_NOTOK_|_FOO_|_P_|___|_
2_|____|___|_______|_____|___|___|_
And for the purposes of this example (to keep it short) your MyPlage range is A1 to F2. Your loop is finding values and taking action like so:
A1 = OK > Colour whole row green
A2 = "" > Clear colour from whole row
B1 = "" > Clear colour from whole row (the row that was previously green)
B2 = "" > Clear colour from whole row
C1 = NOTOK > Colour whole row red (the row that was previously cleared of colour)
C2 = "" > Clear colour from whole row
D1 = "FOO" > Clear colour from whole row (the row that was previously red)
D2 = "" > Clear colour from whole row
E1 = "P" > Colour whole row yellow(the row that was previously cleared of colour)
E2 = "" > Clear colour from whole row
F1 = "" > Clear colour from whole row (the row that was previously yellow)
F2 = "" > Clear colour from whole row
Your end result is that all rows are cleared of colour as you're only taking the value in your last column as the input to determine row colour. So in your example, you'll only see a coloured row if your I column contains any of the values you're looking for.
You can see this in action by hitting F8 to step through the sub, or place a breakpoint on your celk.entirerow... elements so it stops when a case select is found to be true and then hitting F8 from there. I'd recommend trying it on a small data set first to see it in action or you'll have to hit F8 200 times to move across a column.
You don't use Target in Worksheet_Change sub, so you can pass any range to this sub like:
Call Worksheet_Change(Range("A1"))
or
Call Worksheet_Change(Range("B5000"))
I have a spreadsheet with a tab for each month. When a customer account number is entered into column a, I want a vlookup formula to be entered into column b, directly next to the cell in column a where the customer number was entered.
I have already set the sheets up with the vlookup formulas entered into the adjacent cells, but the sheet has become so big that the program has started to lag when the user enters data in column a. Now I am trying to reduce the size of the spreadsheet by setting up a vba code to enter this vlookup only when the cell in column a actually has data in it.
I have even tried creating a macro that will do this, and it works great, except my co-workers who use this sheet are VERY basic computer users, and it complicates things if they have to "do" anything to make the formula run.
You can use the worksheet's _Change event handler to do things, based on changes in the worksheet.
Sub Worksheet_Change(ByVal Target as Range)
'Prevent infinite loops by disabling event procedures
Application.EnableEvents = False
'Make sure that at least one cell in selection is in column A:
If Not Intersect(Target, Range("A:A")) Is Nothing Then Call MyMacro(Target)
'Turn the event procedures back on
Application.EnableEvents = True
End Sub
In any module, put the sub that will actually do the dirty-work. This is a preference of mine, rathr than trying to cram everything in to the _Change event handler, I simply parse the Target and hand it off to the appropriate subroutine.
Sub MyMacro(rng as Range)
Dim cl as Range
For each cl in rng.Cells
'## Make sure we're dealing with column A only:
If cl.Column = 1 Then
'## Insert a formula in the adjacent cell (column B)
cl.Offset(0,1).Formula = "=Vlookup(..."
End If
Next
End Sub
I have 5,000 part numbers contained on one sheet of an Excel workbook (Part Numbers), ranging from cell A1:A5000. I want to find a way to click on any one of those part numbers and have it automatically populate into cell D7 on another sheet of the same workbook (Price Sheet). What is the easiest way to accomplish this task?
To do it that way, you will have to write VBA code to catch every SheetSelectionChange event to see if the new selection range is in your cells A1:A5000. And then if it is, execute the VBA code to fill OtherSheet!D7.
If I recall correctly, the VBA code to do this would look something like this:
Private Sub WorkSheet_SelectionChange(ByVal Target As Range)
'Check if it is in the range A1:A5000
If Target.Column = 1 And Target.Row <= 5000 Then
'get the target worksheet
Dim TargetWS As Worksheet
Set TargetWS = Sheets("OtherSheetsName")
'copy the value of the just selected cell to D7 on the target WS
TargetWS.Cells(7, 4).Value = Target.Value
End If
End Sub
(Oops, forgot about the need for "SET" in VBA.)
You can do this without VBA:
Select the partnumbers A1:A5000 and type PartNumbers in the Name Box (to the left of the formula bar) and press carriage return (OartNumbers should now be visible in the Name Box whenever you select a1:a5000
Now go to cell D7 on Price Sheet, and use Data Validation-->List and enter =PartNumbers in the Source box
Now you can select any of the 5000 part numbers from the dropdown in cell D7