Get Elements of an array in Excel-Vba - excel

I have been trying to get the elements of an array in my following code.
Public SetDeviceInfo(ByVal TLPTestVoltage As String, ByVal rng As Range = Nothing)
TLPTestVoltage = rng.Cells(7) 'Value passed is 7-50-21
Dim TLPTV As String
Dim LArray() As String 'Dim for output array
LArray = Split(TLPTestVoltage, "-") 'split on basis of ":" char
If Application.WorksheetFunction.IsNumber(TLPTestVoltage) = True Then
TLPTV = LArray(1)
End If
LogInfo "Set TLPTestVoltage: " & TLPTestVoltage
LogInfo "TLPTV:" & TLPTV
End Sub
The o/p for the above code is:
Set TLPTestVoltage: 7-50-21
TLPTV:
Can anyone explain what's wrong in getting the elements of the array from the above code. The output is nil. I din't error from my Vba too.

The problem is that Application.WorksheetFunction.IsNumber(TLPTestVoltage) will always be false, because TLPTestVoltage is a string. If you set a breakpoint on the line inside that if statement, you'll see that the breakpoint is never reached. You'll have to rethink what you're trying to do with that if statement. Since I don't know what your application's needs are, I'm not sure what specifically to suggest.

Related

How to read the filter settings from an Excel table using VBA [duplicate]

I have a Client class. Inside that class there is an array losses. First I create and populate with clients a clientsColl array. Then for each client in that array I populate its losses array.
Then I try to print into debug a first element of losses for each client. However, it doesnt work and Property let procedure not defined and property get procedure did not return an object error appears.
And the same time if I just try to display a first element of losses for the first client, without any cycle, it works fine:
Dim clientsColl() As Client
clientsColl = getClients(dataWorkbook)
Dim clientCopy As Variant
Debug.Print "first: " & clientsColl(1).getLosses(1) 'works fine
For Each clientCopy In clientsColl
Debug.Print "in for each: " & clientCopy.getLosses(1) 'error here
Next
In Client class:
Public Property Get getLosses()
getLosses = losses
End Property
Private losses() As Double
How the losses array is populated:
Public Sub calculateFinancialResult()
ReDim losses(1 To simulationCount)
ReDim profits(1 To simulationCount)
Dim i As Long
For i = 1 To simulationCount
If outcomes(i) = 1 Then
losses(i) = totalLoss
...
Else
...
End If
Next
End Sub
Why does this happen and how to fix it?
EDIT: more of the main sub:
For Each clientCopy In clientsColl
clientCopy.setSimulationCount = globals("SIMULATION_COUNT")
...
clientCopy.calculateFinancialResult
...
Next
EDIT:
At the same time a simple for cycle works fine:
Debug.Print "first: " & clientsColl(1).getLosses(1)
For tempCount = LBound(clientsColl) To UBound(clientsColl)
Debug.Print "in for each: " & _
clientsColl(tempCount).getLosses(1)
Next
To conclude what was said in comments:
Your problem (error 451) often occures when you trying to compound properties.
To represent this case we can use any structure of any object with properties.
Let's emulate it with array of collections:
Option Explicit
Sub Test()
Dim Arr As Variant
Dim Col As Collection
Dim i As Long
Dim j As Long
ReDim Arr(1 To 10)
For i = 1 To 10
Set Col = New Collection
For j = 1 To 10
Call Col.Add(j)
Next
Set Arr(i) = Col
Next
On Error Resume Next
Debug.Print Arr(1).Item(1)
Debug.Print Arr(1).Item()(1)
On Error GoTo 0
End Sub
Your problem stems from the fact that you're treating your properties as attributes. On not-so-compounded (or when your array is declared explicitly as array of class instances) level it works due to early binding. But when things start to get more complex - it's fail, since your property just another function.
Hence, to achieve what you want, you should call it explicitly with another pair of parentheses.
Your getLosses property doesn't take an argument so your syntax is actually wrong, even though VBA can cope with it when early bound. You should be using:
Debug.Print "first: " & clientsColl(1).getLosses()(1) 'works fine
For Each clientCopy In clientsColl
Debug.Print "in for each: " & clientCopy.getLosses()(1) 'error here
Next
I also meet this problem when I create my customize array class using compound properties.
I solved it by adding class statment for return value in Property Get code. Just as what #Rory said.
You could try Public Property Get getLosses() As Double in the Client class.

Finding and adding code into a module via a macro

I am trying to create code in VBA that will search thru a module, find specific text, then add a string BEFORE that text in the same line. For example, every time it says "yo" in the module, I want it changed to say "Add This yo".
The code below successfully finds instances where it says "yo" in the module, but it doesn't add the text where I want it to. Instead, text is added at the very top of the module (not even inside a sub). How do I get this text to be added before "yo"?
Public Sub Edit()
Dim vb As VBComponent
Dim i As Long
Dim intFoundLine As Integer
Dim strSearchPhrase As String
Set vb = ThisWorkbook.VBProject.VBComponents("Module2")
strSearchPhrase = "yo"
intLinesNr = vb.CodeModule.CountOfLines
For i = 1 To intLinesNr
If vb.CodeModule.Find(strSearchPhrase, i, 1, -1, -1) Then
intFoundLine = i
MsgBox "Found at " & intFoundLine
vb.CodeModule.AddFromString ("Add This")
End If
Next
End Sub
Replace the line with a the new text:
vb.CodeModule.ReplaceLine i, "Add This" & vb.CodeModule.Lines(i, 1)
Based on Mathieu Guindon's answer, here is how I would handle all the instances of the search phrase:
Do While vb.CodeModule.Find(strSearchPhrase, i, 1, -1, -1)
vb.CodeModule.ReplaceLine i, "Add This" & vb.CodeModule.Lines(i, 1)
i = i + 1
Loop
'
Iterating all lines of a module seems a poor use of the Find method, which is capable of finding text anywhere in a module and takes ByRef arguments that, if the function returns True, will contain the exact location of the found text - that's a great use case for a user-defined Type:
Option Explicit
Private Type CodeStringLocation
StartLine As Long
EndLine As Long
StartColumn As Long
EndColumn As Long
End Type
Sub test()
Dim module As CodeModule
Set module = ThisWorkbook.VBProject.VBComponents("Module1").CodeModule
Dim foundAt As CodeStringLocation
If module.Find("test", foundAt.StartLine, foundAt.StartColumn, foundAt.EndLine, foundAt.EndColumn) Then
'L9C5-L9C9
Debug.Print "L" & foundAt.StartLine & "C" & foundAt.StartColumn & "-L" & foundAt.EndLine & "C" & foundAt.EndColumn
End If
End Sub
Now that you have the in-editor line number you want to rewrite, use CodeModule.ReplaceLine to rewrite it - for example by replacing the Debug.Print statement above with this:
Dim newLine As String
newLine = Replace(module.Lines(foundAt.StartLine, 1), "test", "Renamed")
module.ReplaceLine foundAt.StartLine, newLine
If you need to replace all occurrences of the search text in the module, simply run the search until CodeModule.Find returns False - like this:
Dim foundAt As CodeStringLocation
Do While module.Find("test", foundAt.StartLine, foundAt.StartColumn, foundAt.EndLine, foundAt.EndColumn)
Dim newLine As String
newLine = Replace(module.Lines(foundAt.StartLine, 1), "test", "Renamed")
module.ReplaceLine foundAt.StartLine, newLine
Loop
Key point being that everything but the search text is an output parameter; by hard-coding any of these arguments, you lose the reference to the value they return. If you want to limit the search to a specific scope or range of lines, the right way to do it would be to configure the foundAt values before running the search.
Dim foundAt As CodeStringLocation
foundAt.StartLine = 10
Do While module.Find("test", foundAt.StartLine, foundAt.StartColumn, ...
That way you leverage the actual bidirectional nature of the arguments, without losing the reference to the output values - and without iterating up to 10K lines of code when you don't need to.
Note that this is purely text-based search and takes absolutely zero syntactical considerations: the API will not care if the search string is found in an identifier, a comment, a string literal, or a keyword.

Getting Object required error on .Find method

I am getting a Compile Object Required when running a .Find on the following.
Data has been generated from a form and the code is within the form.
I have highlighted in blue where I get the error.
Dim MODATT As String
Dim SearchRange As Range
Dim searchcell As String
Dim NewModShort As String
Dim MakeVal As String
Dim ModVal As String
Dim mdAtt As String
Private Sub ADDPROD_Click()
Worksheets("SKU List").Activate
SKUNUMBER = Range("A1").End(xlDown).Value + 1
Range("A1").End(xlDown).Offset(1).Value = SKUNUMBER
MODATT = Make.Value & " " & Model.Value & " " & PS.Value & "PS"
With Worksheets("Model Att").Range("A1", Range("A1").End(xlDown))
Set mdAtt = .Find(What:=MODATT, LookIn:=xlValues)
If mdAtt Is Nothing Then
Range("A1").End(xlDown).Offset(1).Value = MODATT
MODATT.PutInClipboard
MsgBox "Please add " & MODATT & "to the Model Attributes (This has been copied, ready to paste)", , "Add Attribute"
ModShort
Else
ModShort
End If
End Sub
Set mdAtt = gets the error:
Compile Error: Object Required
A few notes:
As #Dean stated, you have mdAtt declared as a String. Declare is as a Range. Then using the set statement will work as Range is an object.
Try to declare variables where they are used and indent your code. This would make your code easier to follow and debug.
SKUNUMBER is never declared (at least in the code you provided). Use Option Explicit to help prevent this.
Your With block is missing an End With which will give you a compile error.
Your call to ModShort is at the end of your If as well as in your Else statement. Why not just removed the Else and run this after your If statement is complete?
If mdAtt Is Nothing Then
' ...
End If
ModShort

Passing nested array as parameter for function in VBA results in compile error "Expected: ="

I am attempting to Construct an array (testSheets) that holds a file name and a file path as strings. I then wish to contain this array inside of another array (shtsTmpl). Then, I want to pass the strings within the nested array into a function's parameters (copySheets) to simply return the combined file path in a msgbox.
This first bit of code successfully returns "TSTSheets.xlsx" in a msg box.
Sub prepSheets()
Dim testSheets() As Variant
ReDim testSheets(0)
testSheets(0) = "TSTSheets.xlsx"
Dim shtsTmpl() As Variant
shtsTmpl = Array(testSheets)
copySheets (shtsTmpl(0)(0))
End Sub
Function copySheets(srcName As String)
MsgBox (srcName)
End Function
This second bit of code returns a compile error that says "Expected: =" at the line that calls the copySheets function and I do not understand why.
Sub testSheets()
Dim testSheets() As Variant
ReDim testSheets(1)
testSheets(0) = "TSTSheets.xlsx"
testSheets(1) = "C:\"
Dim shtsTmpl() As Variant
shtsTmpl = Array(testSheets)
copySheets (shtsTmpl(0)(0),shtsTmpl(0)(1))
End Sub
Function copySheets(srcName As String, srcPath As String)
MsgBox (srcPath & srcName)
End Function
Can someone please explain to me why the code compiles correctly when the function has one parameter and incorrectly when the function has two parameters?
Please let me know if you need further explanation.
Thank you.

VBA FileFolderExists pass variable

I found this function on a web
Private Function FileFolderExists(strFullPath As String) As Boolean
On Error GoTo EarlyExit
If Not Dir(strFullPath, vbDirectory) = vbNullString then
FileFolderExists = True
End If
EarlyExit:
On Error GoTo 0
End Function
And I want to pass string variable like this
Dim lineText As String
...
ElseIf FileFolderExists(lineText) = False Then
I am getting compile error "byref argument type mismatch"
When I put byval before strFullPath, it doesn't seem to work properly.
I also tried playing with Dir function, it works if I pass literal like "C:\test", but it doesn't work if I pass the variable.
Does anyone have function that check for folder existence and accepts the string variable as parameter ?
Thanks in advance
The problem seems to be that Word adds CR character to every paragraph, or, to be more exact, that the Text property of the Paragraph object returns the paragraph text plus the CR character.
AFAIK, this is the Word's behaviour for every paragraph, even for the last one.
How can this cause a compile error, I do not have a clue. If I take Milan's example:
Private Sub FirstLineFolder()
Dim lineText As String
lineText = ActiveDocument.Paragraphs(1).Range.Text
lineText = Left(lineText, Len(lineText) - 1) 'see below
MsgBox DoesFolderExist("C:\")
MsgBox DoesFolderExist(lineText)
End Sub
it returns true, true if the first line of the document is a valid folder. If I comment the marked line, the program still compiles and runs and returns true, false (with the same document).
There is some info about it on MSDN website
Try this:
Function FolderExists(folderPath As String) As Boolean
Dim f As Object
Set f = CreateObject("Scripting.FileSystemObject")
On Error GoTo NotFound
Dim ff As Object
Set ff = f.GetFolder(folderPath)
FolderExists = True
Exit Function
NotFound:
FolderExists = False
On Error GoTo 0
End Function
I used the following to test it:
Sub Tst()
Dim b As Boolean
Dim s As String
s = "c:\temp"
b = FolderExists(s)
End Sub
And it works as expected.
Generally, I used Scripting.FileSystemObject for all file-related operation in VBA, the native functions are too cumbersome.
It should be also noted that my function all checks for folders, while the original function -- judging by its name -- perhaps also tried to check for existence of files.
New code, it explains exactly what I need, it should be easier for you to try.
I am expecting folder in first line of the Word document, then I have to check if it exists.
Private Sub FirstLineFolder()
Dim lineText As String
lineText = ActiveDocument.Paragraphs(1).range.Text
MsgBox DoesFolderExists("C:\") ' this works
MsgBox DoesFolderExists(lineText) ' this doesnt work, when same folder passed
End Sub
Both my and Martin's function are throwing compiling error I wrote in my first post.
If it matters : Word is 2010, "option explicit" isn't written (I inherited the code, I can't change that)

Resources