macro: if radio button on then copy formula down a range - vba

My prob is this:
I want to be able to use a macro to copy & calculate formula down a range of cells if radio button is on.
But I don't know how to set the variable inside the formula. The macro below should copy the formula to ranges shown (I12:I252, K12:K252, M12:M252).
The formula itself includes a subtraction of two cells in the range of C12:C252 & B12:B252. I cannot seem to reference those cells. I thinks that's the problem...
Anyway, it doesn't work. Any help would be greatly appreciated.
Thanks!
Dim shp1 As Shape
Dim shp2 As Shape
Dim i As Long
On Error Resume Next
Set shp1 = Worksheets("Worksheet").Shapes("Button 1")
Set shp2 = Worksheets("Worksheet").Shapes("Button 2")
If shp1.ControlFormat.Value = xlOn Then
MsgBox "Auto Calculating"
For i = 12 To 252
Range("I" & i).Formula = "=IFERROR(((C & i)-(B & i))*I6/(E7-E6);"")"
Range("K" & i).Formula = "=IFERROR(((C & i)-(B & i))*J6/(E7-E6);"")"
Range("M" & i).Formula = "=IFERROR(((C & i)-(B & i))*K6/(E7-E6);"")"
Next i
Else
If shp2.ControlFormat.Value = xlOn Then
MsgBox "Manually insert calculation"
End If
End If

Few improvements:
Replace the ; in your formulas with ,. ; is your local
setting, but .Formula uses the English setting!
If you want to refer to each column, you need place the i outside the quoatation marks, i.e. instead of =IFERROR(((C & i)... write =IFERROR(((C" & i & ")...
No need to loop each cell and set the formula. If you use $ in your formula properly, you can replace all with one formula: =IFERROR(($C12-$B12)*I$6/($E$7-$E$6),"")
Better use .FormulaR1C1 - this way, your formula will also work, when you would applied it to some other range. To easily convert a formula, type it normally into a cell and the run ? Selection.FormulaR1C1in the VBA Immediate Window. The above formula translates to =IFERROR((RC3-RC2)*R6C/(R7C5-R6C5),"")
Don't hard code cell references (in your case I12:K252). Better assign this range to a named range and use this as a reference. This way, your code will also work if you later add/remove rows or columns.
Don't use On Error Resume Next! This is a invitation to oversee an error that should be fixed
Optional: Alternatively to accessing the controls directly in VBA, you can also assign each one to a cell, name this cell as in step 4 and refer to in by this name. Makes your code more flexible/less complex!
So all in all, I end up with:
Public Sub YourSub()
If Range("SwitchOne") Then
Range("YourRange").FormulaR1C1 = _
"=IFERROR((RC3-RC2)*R6C/(R7C5-R6C5),"""")"
Else
If Range("SwitchTwo") Then
MsgBox "Manually insert calculation"
End If
End If
End Sub

Related

Formatting a Formula in a String VBA

I have a script that needs to place a formula into a cell but I'm getting a 1004 error from the first part I am sure I formatted something wrong. I had difficulty with the " marks in the string but got those worked out so I'm figuring I'm missing something else. The cells are also unprotected.
Worksheets(CurSheet + 1).Range("D" & Y).Value = "=IF(D52=1,0,IF(C52=" & """Saturday""" & ",0,'" & CurSheet & "!C" & Y & "))"
This is the section that gives the error. If it is removed code works.
"=IF(D52=1,0,IF(C52="
I am not sure what I am doing wrong with this part.
It looks like you're using CurSheet as a sheet index number and as a sheet name.
The index number just returns the relative position of the sheet in the workbook while the name is what you see on the sheet tab (there's also the CodeName but I won't go into that here).
Although I don't fully understand what you're after this code will place a formula on the sheet identified with the sheet index number, so if CurSheet= 1(+1) it will place the formula on the second sheet.
The formula itself will reference the name of the sheet that is before the sheet that the formula appears on (so if the formula is on the second sheet, the formula will reference the first sheet).
Sub Test()
Dim Y As Long
Dim CurSheet As Long
Y = 1
CurSheet = 1
Worksheets(CurSheet + 1).Range("D" & Y).Formula = _
"=IF(D52=1,0,IF(C52=" & """Saturday""" & ",0,'" & Worksheets(CurSheet).Name & "'!C" & Y & "))"
End Sub
Hope I made that clear enough. :)
You need to declare that you are inputting a formula, not a value:
Change:
Worksheets(CurSheet + 1).Range("D" & Y).Value
To:
Worksheets(CurSheet + 1).Range("D" & Y).Formula

Another >> Unable to set the FormulaArray property of the range class

I've researched as many of the "Unable to set the FormulaArray property of the range class" issues here and in other sites to troubleshoot a FormulaArray operation I'm trying to carry out in a table of data.
I've respected the 255 character limit in my formula taking into account R1C1, I've tried to insert the formula as a text string first. I've tried quite a few things.
Now I'm thinking my issue is with the fact that I'm trying to insert my formula only into blank cells because if I simplify my formula to only be =1+1 I still get the error. If I change .FormulaArray to .Formula to simply enter a standard formula I also get the same error. Is this operation not possible with blank cells?
The error occurs at the .FormulaArray = myFormula1 step.
To confirm, the formula by itself works (pasted further below) when entered into cells manually.
Sub ArrayMacro()
Dim myFormula1 As String
Dim myFormula2 As String
Dim myFormula3 As String
Dim myFormula4 As String
myFormula1 = "=IF(COUNTIFS(MLBtransactions!$D:$D,A$1,MLBtransactions!$A:$A,""<=""&$C2)>0,IF(INDEX(MLB," & "X_X_X)"
myFormula2 = "transactions!$A:$E,MATCH(1,(MLBtransactions!$D:$D=A$1)*(MLBtransactions!$A:$A<=$C2),0),," & "Y_Y_Y)"
myFormula3 = "5)=$A2,""DNP/SUS/MIN"",""with "" & INDEX(MLBtransactions!$A:$E,MATCH(A$1,MLBtransactions," & "Z_Z_Z)"
myFormula4 = "!$D:$D,0),5)),IF(COUNTIFS(MLBstats!$B:$B,A$1,MLBstats!$A:$A,$A2)=1,""DNP/SUS/MIN"",""LEAVE BLANK""))"
Sheets("Sheet1").Select
With Range("E2:AZ140").SpecialCells(4)
.FormulaArray = myFormula1
.Replace ",X_X_X)", myFormula2
.Replace ",Y_Y_Y)", myFormula3
.Replace ",Z_Z_Z)", myFormula4
End With
End Sub
Question update. Using With Range("E2:AZ140").SpecialCells(xlCellTypeBlanks) instead of With Range("E2:AZ140").SpecialCells(4) also ends with the same error.
Here is the full formula being used
=IF(COUNTIFS(MLBtransactions!$D:$D,A$1,MLBtransactions!$A:$A,"<="&$C2)>0,IF(INDEX(MLBtransactions!$A:$E,MATCH(1,(MLBtransactions!$D:$D=A$1)*(MLBtransactions!$A:$A<=$C2),0),5)=$A2,"DNP/SUS/MIN","with " & INDEX(MLBtransactions!$A:$E,MATCH(A$1,MLBtransactions!$D:$D,0),5)),IF(COUNTIFS(MLBstats!$B:$B,A$1,MLBstats!$A:$A,$A2)=1,"DNP/SUS/MIN","LEAVE BLANK"))
Testing with a simplified code (example below) led to the realization as YowE3K points out that myFormula1 needs to be valid in order for the procedure to work.
Sub ArrayMacro()
Dim myFormula1 As String
Dim myFormula2 As String
myFormula1 = "=1+1" & "+2+2"
myFormula2 = "+1+1"
Sheets("Sheet1").Select
With Range("h14:h16").SpecialCells(xlCellTypeBlanks)
MsgBox .Address
.FormulaArray = myFormula1
.Replace "+2+2)", myFormula2
End With
End Sub
When you set a formula using FormulaArray = ..., it needs to be a valid formula. (I think after each Replace the formula needs to continue being valid too, but I haven't tested that. Edit: No, if the Replace would create an invalid formula, it just doesn't process it - but it doesn't crash.)
Your problems all seem to stem from the use of invalid formulas in your myFormula1 variable.
I suggest you use the following:
Sub ArrayMacro()
Dim myFormula1 As String
Dim myFormula2 As String
Dim myFormula3 As String
Dim myFormula4 As String
myFormula1 = "=IF(COUNTIFS(MLBtransactions!$D:$D,A$1,MLBtransactions!$A:$A,""<=""&$C2)>0,IF(1232=$A2,""DNP/SUS/MIN"",""with ""&1233),1234)"
myFormula2 = "INDEX(MLBtransactions!$A:$E,MATCH(1,(MLBtransactions!$D:$D=A$1)*(MLBtransactions!$A:$A<=$C2),0),5)"
myFormula3 = "INDEX(MLBtransactions!$A:$E,MATCH(A$1,MLBtransactions!$D:$D,0),5)"
myFormula4 = "IF(COUNTIFS(MLBstats!$B:$B,A$1,MLBstats!$A:$A,$A2)=1,""DNP/SUS/MIN"",""LEAVE BLANK"")"
'Insert the formula
With Sheets("Sheet1").Range("E2:AZ140").SpecialCells(xlCellTypeBlanks)
.FormulaArray = myFormula1
.Replace "1232", myFormula2
.Replace "1233", myFormula3
.Replace "1234", myFormula4
End With
End Sub
Setting .FormulaArray to a range of cells in VBA is the same as pressing CTRL+SHIFT+ENTER while the entire range is selected. This is used when a single formula is returning an array of results and you want to display that array in the range of selected cells. This requires a contiguous range of cells to display the array. Trying to set .FormulaArray on a non-contiguous range of cells will fail, regardless of whether the formula is good or not.
I think you're trying to create an Array Formula that returns a single result after performing analysis on arrays; and you want this formula used in all blank cells.
In Excel, you would need to array-enter the formula into a single cell and then copy the formula into other cells.
Similarly, you need to do it in 2 steps in VBA. You need to first set the .FormulaArray for just one cell. This will also confirm that the formula is being constructed correctly in VBA. You can then copy that cell to all blank cells, using PasteSpecial if you only want to copy the formula.
Alternatively, you could loop through all blank cells setting the .FormulaArray individually, e.g.:
Dim raCell As Range
For Each raCell In Range("E2:AZ140")
If IsEmpty(raCell) Then raCell.FormulaArray = ...
Next
However, as you have dynamic references, you would need to construct the FormulaArray carefully to correctly determine the formula required based on the .Row and .Column of the current raCell.
Copy and paste would be safer if you have an "achor" point. Somewhere you know you can always enter the exact same formula and get the correct result when copied and pasted to all other cells.

How to add a Formula To Cell using VBA [duplicate]

This question already has answers here:
How do I put double quotes in a string in vba?
(5 answers)
Closed 1 year ago.
I am attempting to write some VBA which will add header text to 3 cells then fill a formula all the way down to the last row. I have written the below, which writes the headers no problems, but when it get's to my first .Formula it throws a
Application Defined or Object Defined error
What needs to be altered so that this macro will execute successfully? (The formulas were pulled directly from the formula in the cell, so I know they are valid formulas at least on the "front-end")
Function Gre()
Range("E2").Select
ActiveCell.FormulaR1C1 = "Under"
Range("F2").Select
ActiveCell.FormulaR1C1 = "Over"
Range("G2").Select
ActiveCell.FormulaR1C1 = "Result"
With Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row)
.Formula = "=IF(C2<B2,B2-C2,"")"
End With
With Range("F2:F" & Cells(Rows.Count, "C").End(xlUp).Row)
.Formula = "=IF(C2>B2,C2-B2,0)"
End With
With Range("G2:G" & Cells(Rows.Count, "C").End(xlUp).Row)
.Formula = "=IF(F2>0,'Issue',"")"
End With
End Function
The problem is likely that you are escaping the quotes with the formula.
What you need is:
.Formula = "=IF(C2>B2,B2-C2,"""")"
for the first one, for example. The other quotes need to be doubled as well.
As a side-note, it would also be best to specify the sheet you are working on with something like:
Dim ws as worksheet
Set ws = Sheets("mySheet")
ws.Range("E2").FormulaR1C1 = "Under"
etc.
If you don't do this, you can sometimes have errors happen while running the code.
As suggested by OpiesDad, to minimize ambiguity, avoid ActiveCell and the like.
Using Select will also slow down performance a lot compared to assigning to cells directly.
I'm pretty sure you need to escape quotes in Excel formulas inside of VBA by doubling the quotes, so a normal empty string becomes """". You also have Issue in single quotes in a formula, which I'm pretty sure will error in Excel; that should be in escaped double quotes as well.
I'm having a hard time figuring out what Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row) actually does, but it sounds like you want to select E2 to the last used row of the sheet. Avoid Rows.Count or just generally referring to the rows of a sheet, as that will go to row 10^31. Use Worksheet.UsedRange to get the range from the first row and column with content to the last row and column with content. This also includes empty strings and can be a bit tricky sometimes, but is usually better than dealing with thousands of extra rows.
Also,
You don't need to use With if your only enclosing one statement, although it won't cause any problems.
I would not mix use of Range.Formula and Range.FormulaR1C1 unless you have a reason to.
Function Gre()
Dim ws as Worksheet
Set ws = ActiveSheet
Dim used as Range
Set used = ws.UsedRange
Dim lastRow as Integer
lastRow = used.Row + used.Rows.Count - 1
ws.Range("E2").Formula = "Under"
ws.Range("F2").Formula = "Over"
ws.Range("G2").Formula = "Result"
ws.Range("E2:E" & lastRow).Formula = "IF(C2<B2, C2-B2, """")"
ws.Range("F2:F" & lastRow).Formula = "IF(C2<B2, C2-B2, 0)"
ws.Range("G2:G" & lastRow).Formula = "IF(F2>0, ""Issue"", """")"
End Function
The first issue is the selecting of cells. This requires the macro to select the cell, then determine the cell address. If you need to actually select a cell, use Application.ScreenUpdating = False. Then the macro doesn't have to show the cursor selection of a cell. Dropping the select and incorporating the range into the formula assignment code line like below will gain some speed/efficiency.
Range("E2").FormulaR1C1 = "Under"
Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row) is the code version of selecting the last cell in a blank column (row 1048576), then using the keystroke of ctrl and the up key to determine the lowest/last used cell. This gets you a row count of 1 every time since the column is blank. Since you're looking for the last row. It may be faster to count down from the top. My favorite method for this is a loop. Increment a variable within a loop, while looking for the last row. Then, the variable can be used instead of your bottom up strategy.
t = 0
Do Until Range("C2").Offset(t, 0).Value = ""
t = t + 1
Loop
With Range("E2:E" & t)
.Formula = "=IF(C2<B2,B2-C2,"""")"
End With`
Just like TSQL, quote characters need their own quote characters.
.Formula = "=IF(C2<B2,B2-C2,"""")"
The Range Fillup VBA function can be utilized in this case to fill all cells from the bottom with a common formula, accounting for Excel Formula Reference Relativity. The code below starts with the range that we got from the loop counter. Next, we set a variable equal to the total rows in Excel minus the row corresponding to the counter row. Then, we resize the original region by the necessary rows and use the FillDown function to copy the first formula down.
Here's the resulting code. This will fill the range starting from the last row in Excel.
Sub Gre()
Range("E2").FormulaR1C1 = "Under"
Range("F2").FormulaR1C1 = "Over"
Range("G2").FormulaR1C1 = "Result"
Do While Range("e2").Offset(t, 0).Value <> ""
t = t + 1
Loop
Range("E2").Offset(t, 0).Formula = "=IF(C2<B2,B2-C2,"""")"
r1 = Range("e2").EntireColumn.Rows.Count
r2 = Range("E2").Offset(t, 0).Row
Range("E2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
Range("F2").Offset(t, 0).Formula = "=IF(C2>B2,C2-B2,0)"
Range("F2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
Range("G2").Offset(t, 0).Formula = "=IF(F2>0,""Issue"","""")"
Range("G2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
End Sub
As well as using double quotes you may need to use 0 in the first two formula otherwise they may evaluate to empty strings. This may give unexpected results for the last formula i.e. incorrectly return "Issue".
If you do not have blank columns between your data and the 3 new columns you can use CurrentRegion to determine the number of rows:
Range("E2:E" & Cells.CurrentRegion.Rows.Count).Formula = "=if(C2'<'B2,B2-C2,0)"
Range("F2:F" & Cells.CurrentRegion.Rows.Count).Formula = "=if(C2>B2,C2-B2,0)"
Range("G2:G" & Cells.CurrentRegion.Rows.Count).Formula = if(F2>0,""Issue"","""")"
Please try the following sample hope it will help you to wright formula in VBA
Sub NewEntry()
Dim last_row As Integer
Dim sht1 As Worksheet
Dim StockName As String
Set sht1 = Worksheets("FNO MW")
last_row = Cells.Find(What:="*", After:=Range("A1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'MsgBox last_row
StockName = sht1.Cells(last_row, 1).Value
sht1.Cells(last_row, 1).Formula = "=RTD(""pi.rtdserver"", ,"" " & StockName & " "", ""TradingSymbol"")"
End Sub

Excel VBA - For Each loop is not running through each cell

I am currently facing an issue in which my 'for each' loop is not moving onto subsequent cells for each cell in the range I have defined when I try to execute the script. The context around the data is below:
I have 3 columns of data. Column L contains employees, Column K contains managers, and column J contains VPs. Column K & J containing managers and VPs are not fully populated - therefore, I would like to use a VBA script & Index Match to populate all the cells and match employees to managers to VPs.
I have created a reference table in which I have populated all the employees to managers to directors and have named this table "Table 4". I am then using the VBA code below to try and run through each cell in column K to populate managers:
Sub FillVPs()
Dim FillRng As Range, FillRng1 As Range, cell As Range
Set FillRng = Range("J2:J2000")
Set FillRng1 = Range("K2:K2000")
For Each cell In FillRng1
If cell.Value = "" Then
ActiveCell.Formula = _
"=INDEX(Table4[[#All],[MGRS]], MATCH(L583,Table4[[#All],[EMPS]],0))"
End If
Next cell
End Sub
I feel that something is definitely wrong with the index match formula as the match cell "L583" is not moving to the next cell each time it runs through the loop; however, I am not sure how to fix it. I also do not know what else is potentially missing. The code currently executes, but it stays stuck on one cell.
Any help is greatly appreciated, and I will make sure to clarify if necessary. Thank you in advance.
The problem is that you are only setting the formula for the ActiveCell.
ActiveCell.Formula = _
"=INDEX(Table4[[#All],[MGRS]], MATCH(L583,Table4[[#All],[EMPS]],0))"
This should fix it
cell.Formula = _
"=INDEX(Table4[[#All],[MGRS]], MATCH(L583,Table4[[#All],[EMPS]],0))"
You'll probably need to adjust L583. It will not fill correctly unless you are filling across all cell.
These ranges should probably be changed so that they are dynamic.
Set FillRng = Range("J2:J2000")
Set FillRng1 = Range("K2:K2000")
You should apply the formula to all the cells in the range
Range("K2:K2000").Formula = "=INDEX(Table4[[#All],[MGRS]], MATCH(L2,Table4[[#All],[EMPS]],0))"
UPDATE: Dynamic Range
Every table in Excel should have at least one column that contain an entry for every record in the table. This column should be used to define the height of the Dynamic Range.
For instance if Column A always has entries and you want to create a Dynamic Range for Column K
lastrow = Range("A" & Rows.Count).End(xlUp).Row
Set rng1 = Range("K2:K" & lastrow)
Or
Set rng1 = Range("A2:A" & Rows.Count).End(xlUp).Offset(0, 10)
UPDATE:
Use Range.SpecialCells(xlCellTypeBlanks) to target the blank cells. You'll have to add an Error handler because SpecialCells will throw an Error if no blank cells were found.
On Error Resume Next
Set rng1 = Range("A2:A" & Rows.Count).End(xlUp).Offset(0, 10).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If rng1 Is Nothing Then
MsgBox "There were no Blank Cels Found", vbInformation, "Action Cancelled"
Exit Sub
End If
The "L583" was not changing because you were not telling it to. The code below should change the reference as the cell address changes.
Range.Address Property
Sub FillVPs()
Dim FillRng As Range, FillRng1 As Range, cell As Range
Set FillRng = Range("J2:J2000")
Set FillRng1 = Range("K2:K2000")
For Each cell In FillRng1
If cell.Value = "" Then
cell.Formula = _
"=INDEX(Table4[[#All],[MGRS]], MATCH(" & cell.Offset(0,1).Address() & ",Table4[[#All],[EMPS]],0))"
End If
Next cell
End Sub

Broken VBA Loop

I'm sure this is simple I just can't find anything on the Web.
I'm writing a Macro to format XL spreadsheets that i download from a 3rd party application. They come formatted all wacky so i'm trying to make it easier to get the data we need from them.
This is a simple VBA Do Loop that causes the cells in Column BL to update. The data in these cells contain line breaks which don't show up until you double click in the cell. The VBA below causes an update to the cells which achieves the same effect, just with less work. However it is currently crashing excel and I can't figure out why. It works in a single instance, but when I loop -- BOOM!!! -- frozen. Any help would be gently appreciated.
Sub updateCell()
Dim currentValue As String
ActiveSheet.Range("BL1").Select
Do Until ActiveCell.Value = ""
ActiveCell.Offset(1, 0).Select
currentValue = ActiveCell().Value
ActiveCell().Value = currentValue & ""
Loop
End Sub
Try something a bit more direct:
With ActiveSheet
lrow = .Range("BL" & .Rows.Count).End(xlUp).Row '~~> find last row on BL
With .Range("BL1:BL" & lrow) '~~> work on the target range
.Value = .Value '~~> assign its current value to it
End With
End With
Above code is like manually pressing F2 then pressing Enter.
Edit1: Explanation on getting the last row
ActiveSheet.Rows.Count '~~> Returns the number of rows in a sheet which is 1048576
MsgBox ActiveSheet.Rows.Count '~~> run this to confirm
So this line actually concatenates BL to 1048576.
.Range("BL" & .Rows.Count) '~~> Count is a property of the Rows Collection
Same as:
.Range("BL" & 1048576)
And same as:
.Range("BL1048576")
Then to get to the last row, we use Range Object End Method.
.Range("BL" & .Rows.Count).End(xlUp)
So basically, above code go to Cell BL1048576 then like manually pressing Ctrl+Arrow Up.
To return the actual row number of the range, we use the Range Object Row property.
lrow = .Range("BL" & .Rows.Count).End(xlUp).Row
See here more about With Statement.
It has the same effect (with your code) without the loop. HTH
But if what you want is to remove Line Breaks produced by Alt+Enter on a cell, try below:
Dim lrow As Long, c As Range
With ActiveSheet
lrow = .Range("BL" & .Rows.Count).End(xlUp).Row
For Each c In .Range("BL1:BL" & lrow)
c.Value = Replace(c.Value, Chr(10), "")
Next
End With
Where Chr(10) is the equivalent of Line Break replaced with "" using Replace Function.