I have previously used this method within my program to insert a formula which was a lot larger however I am receiving "run-time error code 1004 unable to set the FormulaArray property of the range class" with this one:
Sub TEST()
Dim QFormula As String
Dim QCountF As String
Dim QCountF2 As String
Dim WStart As String
Dim MoreDash As String
Dim ValueF As String
QFormula = "=IF($K3=4,IF(_Q_>0,1,_M_),IF($K3=2,IF(_Q_>0,1,IF(COLUMN(P3)-MATCH(_S_,$A$1:P$1,0)>=8,IF(_Q2_>0,1,_M_),_M_)),IF(_Q_>0,1,IFERROR(IF((COLUMN(P3)-MATCH(_S_,$A$1:P$1,0)+1)-_V_<=13,1,_M_),_M_))))"
QCountF = "COUNTA(OFFSET(INDIRECT(ADDRESS(ROW(P3),COLUMN(P3)-4)),0,1,1,3))"
QCountF2 = "COUNTA(OFFSET(INDIRECT(ADDRESS(ROW(P3),COLUMN(P3)-8)),0,1,1,3))"
WStart = """START"""
MoreDash = """-"""
ValueF = "VALUE(MATCH(1,INDIRECT(ADDRESS(ROW(P3),MATCH(_S_,$A$1:P$1,0))):O3,0))"
With ActiveCell
.FormulaArray = QFormula
.Replace "_Q_", QCountF
.Replace "_Q2_", QCountF2
.Replace "_S_", WStart
.Replace "_M_", MoreDash
.Replace "_V_", ValueF
End With
End Sub
I am at a loss as to where I have gone wrong this time and am hoping you can help.
Thanks in advance
Taken straight from msdn site:
If you use this property to enter an array formula, the formula must use the R1C1 reference style, not the A1 reference style (see the example).
Worksheets("Sheet1").Range("E1:E3").FormulaArray = "=Sum(R1C1:R3C3)"
Update edit:
As you stated in comments even though msdn states you have to use R1C1 reference the A1 reference works too.
The actual issue in your code is:
ValueF = "VALUE(MATCH(1,INDIRECT(ADDRESS(ROW(P3),MATCH(_S_,$A$1:P$1,0))):O3,0))"
you have another _S_ within the replacement code this never gets changed as its already past the _S_ .Replace.
Fix:
ValueF = "VALUE(MATCH(1,INDIRECT(ADDRESS(ROW(P3),MATCH(""START"",$A$1:P$1,0))):O3,0))"
Related
I'm trying to use Application.Caller inside a Function (code below), but Excel returns a #VALUE and the background color is not set.
The personal function is called from an Excel cell. The idea is to map RGB values to color display in a "synchronous" fashion (i.e. without having to press a button).
When I run the following function through the debugger and step just before the instruction vCaller.Interior.Color = RGB(rlev, glev, blev), I can manually set the background color to green by pasting the exact same instruction in the execution console. So I'm puzzled as to why Excel is failing but VBA isn't.
Any clue ?
Public Function RGB_print(rlev As Integer, glev As Integer, blev As Integer)
As String
Dim vCaller As Variant
Set vCaller = Application.Caller
If TypeName(vCaller) = "Range" Then
vCaller.Interior.Color = RGB(rlev, glev, blev)
End If
RGB_print = ""
End Function
I completely agree with the comment from #Rory - I'd never use this code in my own projects, but I wanted to see anyway....
If in a normal module you create this function:
Public Function RGB_print(rlev As Integer, glev As Integer, blev As Integer)
Application.Volatile
End Function
Then in your sheet add this code:
Private Sub Worksheet_Calculate()
Dim rFormula As Range
Dim vForm As Variant
Dim sArguments As String
Dim sFormula As String
Dim rgblev As Variant
Set rFormula = Sheet1.Cells.SpecialCells(xlCellTypeFormulas)
For Each vForm In rFormula
If InStr(vForm.FormulaLocal, "RGB_print") <> 0 Then
sFormula = vForm.FormulaLocal
sArguments = Mid(sFormula, InStr(sFormula, "(") + 1, InStr(sFormula, ")") - InStr(sFormula, "(") - 1)
rgblev = Split(sArguments, ",")
vForm.Interior.Color = RGB(Evaluate(rgblev(0)), Evaluate(rgblev(1)), Evaluate(rgblev(2)))
End If
Next vForm
End Sub
This worked for formula such as:
=RGB_print(255,0,255) and =RGB_print(A5,B5,C5)
But again, find another way - this code has so many pitfalls I'll probably lose 100 reputation just for posting it.
Ok, as an alternative to Darrent's very precise reply, I'm reposting Tim Williwam's comment : whether one may/should mix functions and macros is an important question and it has been discussed here. Bottom line is : you can but don't do it unless you know what you are doing and are prepared to face the consequences.
I have spent a long time trying to figure this out ! I would appreciate it if someone could give it a second glance to see where is my mistake ! The formula does not seem to do the replacement
Here is my code
Sub remove()
Dim theFormulaPart1 As String
Dim theFormulaPart2 As String
theFormulaPart1 = "=IFERROR(INDEX(Curve!D:D,MATCH(1,(DATE(RIGHT(Census!$BY2,4),LEFT(Census!$BY2,2),MID(Census!$BY2,4,2))-DATE(RIGHT(Census!$BM2,4),LEFT(Census!$BM2,2),MID(Census!$BM2,4,2))=Curve!$A:$A)*(Census!$T2=Curve!$C:$C),0)),""X()"")"
theFormulaPart2 = "IFERROR(INDEX(Curve!D:D,MATCH(1,(DATE(Year(Census!$BY2),Month(Census!$BY2),Day(Census!$BY2))-DATE(Year(Census!$BM2),Month(Census!$BM2),Day(Census!$BM2))=Curve!$A:$A)*(Census!$T2=Curve!$C:$C),0)),"""")"
With ActiveSheet.Range("CD2")
.FormulaArray = theFormulaPart1
.Replace """X()"")", theFormulaPart2
End With
the error is simple:
.Replace """X()"")", theFormulaPart2
will not work cus the formula after will not be valid. you need:
.Replace """X()""", theFormulaPart2
;)
OK, thanks #Dirk its turn out 255 character not the issue
Second glances:
Formula too long, spit it to make it readable in the future
Use Replace function that directly process a string
No need to use FormulaArray if just one cell
Replaced string should be "X()" not "X()")
Here is the second glance code:
Sub remove()
Dim theFormulaPart1 As String
Dim theFormulaPart2 As String
theFormulaPart1 = "=IFERROR(INDEX(Curve!D:D,MATCH(1,(DATE(RIGHT(Census!$BY2,4),LEFT(Census!$BY2,2),MID(Census!$BY2,4,2))-DATE(RIGHT(Census!$BM2,4),LEFT(Census!$BM2,2),MID(Census!$BM2,4,2))=Curve!$A:$A)*(Census!$T2=Curve!$C:$C),0)),""X()"")"
theFormulaPart2 = "IFERROR(INDEX(Curve!D:D,MATCH(1,(DATE(Year(Census!$BY2),Month(Census!$BY2),Day(Census!$BY2))-DATE(Year(Census!$BM2),Month(Census!$BM2),Day(Census!$BM2))=Curve!$A:$A)*(Census!$T2=Curve!$C:$C),0)),"""")"
theFormulaPart1 = Replace(theFormulaPart1, """X()""", theFormulaPart2)
ActiveSheet.Range("CD2") = theFormulaPart1
End Sub
Another tips:
Avoid using ActiveSheet, how?
This may seem like a simple question but Im very new to VBA and Im not sure why I'm receiving the error.
Dim c As String
c = Sheet2.Range("B3:B54").Find("NLwk01")
Error code is 91: Object variable or With block variable not set.
I thought I should've maybe used cells instead of range, but that gives another error with
Error code 5: Invalid procedure call or argument.
As it was mentioned in comment thread, Excel VBA Find() function returns the Range object. Therefore, pertinent to you particular example, it could be coded as in the following sample snippet:
Sub FindRowIndex()
Dim c
Dim rowIdx As Integer
Dim cellValue As String
'return Range object if found
Set c = Sheet2.Range("B3:B54").Find("NLwk01")
If Not c Is Nothing Then
'return the row index (shown as an example)
rowIdx = c.Row
'return the same string used as search criterion "NLwk01"
cellValue = c.Value
End If
End Sub
Pertinent to your case search area ("B3:B54") the rowIdx can be declared As Integer; for extended area you may use Long.
Also, as mentioned in comments thread, you may declare: Dim c As Range.
Hope this may help.
I can't reference a range with a sheet for my function like I can with =vlookup.
This works: =MVLOOKUP(a2,B:C,2,",",", ")
This isn't: =MVLOOKUP(a2,Sheet3!B:C,2,",",", ")
The code:
Public Function MVLookup(Lookup_Values, Table_Array As Range, Col_Index_Num As Long, Input_Separator As String, Output_Separator As String) As String
Dim in0, out0, i
in0 = Split(Lookup_Values, Input_Separator)
ReDim out0(UBound(in0, 1))
For i = LBound(in0, 1) To UBound(in0, 1)
out0(i) = Application.WorksheetFunction.VLookup(in0(i), Table_Array, Col_Index_Num, False)
Next i
MVLookup = Join(out0, Output_Separator)
End Function
I don't know basic and I'm not planning to learn it, I rarely even use excel, so sorry for the lame question. I guess basic is really "basic" it took me 30 minutes to get to this point from the reference(reading included), but other 60 minutes in frustration because the above problem.
Help me so I can go back to my vba free life!
EDIT: Although the code above worked after an excel restart, Jeeped gave me a safer solution and more universal functionality. Thanks for that.
I was not planning to use it on other than strings but thanks for the addition, I wrongly assumed there is a check for data type every time and type passed along in the background and vlookup acting accordingly. I have also learned how to set default values to function input variables.
See solution.
Thanks again, Jeeped!
You are confusing 1 with "1" and regardless of your personal distaste for VBA, I really don't know of any programming language that treats them as identical values (with the possible exception of a worksheet's COUNTIF function).
Public Function MVLookup(Lookup_Values, table_Array As Range, col_Index_Num As Long, _
Optional Input_Separator As String = ",", _
Optional output_Separator As String = ", ") As String
Dim in0 As Variant, out0 As Variant, i As Long
in0 = Split(Lookup_Values, Input_Separator)
ReDim out0(UBound(in0))
For i = LBound(in0) To UBound(in0)
If IsNumeric(in0(i)) Then
If Not IsError(Application.Match(Val(in0(i)), Application.Index(table_Array, 0, 1), 0)) Then _
out0(i) = Application.VLookup(Val(in0(i)), table_Array, col_Index_Num, False)
Else
If Not IsError(Application.Match(in0(i), Application.Index(table_Array, 0, 1), 0)) Then _
out0(i) = Application.VLookup(in0(i), table_Array, col_Index_Num, False)
End If
Next i
MVLookup = Join(out0, output_Separator)
End Function
When you Split a string into a variant array, you end up with an array of string elements. Granted, they look like numbers but they are not true numbers; merely textual representational facsimiles of true numbers. The VLOOKUP function does not treat them as numbers when the first column in your table_array parameter is filled with true numbers.
The IsNumeric function can reconize a string that looks like a number and then the Val function can convert that text-that-looks-like-a-number into a true number.
I've also added a quick check to ensure what you are looking for is actually there before you attempt to stuff the return value into an array.
Your split strings are one-dimensioned variant arrays. There is no need to supply the rank in the LBound / UBound functions.
Sample data on Sheet3 Results from MVLOOKUP
This is not a valid range reference ANYWHERE in Excel B:Sheet3!C.
Either use B:C or Sheet3!B:C
Edit. Corrected as per Jeeped's comment.
I have an excel sheet with values in a range which I want to perform some calculations on in vb.net. I pass that range to vb.net using COM. When I try editing the values of the range, nothing happens.
My question seems to be very similar to these questions, but I can't quite figure out what step I am missing.
How to edit cell value in VB.net - Using .Interop.Excel
VB.net Office Solution - Accessing value in named Range in a Worksheet
VBA CODE:
Function MyTestRange (Byref myrng as range)
Set classLib = New VBProject.CClass
MyTestRange = classLib.MyTestRange(myrng)
End Function
VB.NET code
Imports Microsoft.Office.Interop.Excel
Public Class CClass
Function MyTestRange(ByRef myrng As Range) As Double
Dim newrng As Range
Dim b As Integer = myrng.Rows.Count
Dim i As Integer
newrng = myrng
For i = 1 To b
newrng.Value2(i, 1) = myrng.Value2(i, 1) + 1
Next i
MyTestRange = newrng.Value2(1, 1)
End Function
End class
While this code doesn't generate an error, it doesn't change the values in newrng.
Edit:
I have tried many iterations based on the link provide, but always get the same error :
An exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll but was not handled in user code
Additional information: Exception from HRESULT: 0x800A03EC
This is the simplest way to generate the error:
Dim c As Object
c = myrng.Value
myrng.Value = c
Hence amending the values to something new, seems out of reach!
Edit 2:
After chatting with user Mat's Mug, I tried to edit a value in a range, purely in VBA.
This sub works perfectly:
Sub rangesub()
Dim example As Range
Set example = Range("A1:A4")
example.Value = Application.Transpose(Array(1, 2, 3, 4))
End Sub
Excel functions also seem able to handle passing ranges:
Function SimpleCopyRange(myrng)
SimpleCopyRange = myrng
End Function
A very simple combination of this code works:
Function EditRange(myrng)
Dim example As Range
Set example = Range("A1:A4")
EditRange = example
End Function
However there is an unspecified error if I try to edit the range:
Function EditRange(myrng)
Dim example As Range
Set example = Range("A1:A4")
example.Value = Application.Transpose(Array(1, 2, 3, 4))
EditRange = example
End Function
The application.transpose part obviously adds a layer of complexity, and can be replaced with example.Value = 8 without any changes in results.
Looking at this question/answer:
Excel VBA: Iterating over range parameter and change cell values
It appears that a UDF can only change the calling cell.
I think therefore this method is impossible.
The workaround is to to rewrite the code to work with an array, assign the range to an array, edit the array and pass it to the new function.