Passing blank array to a function to and populate it from there - vba

I am trying to pass a blank array to a function that will manipulate the array dependent on certain scenarios. I don't know where I am going wrong with this but I am getting the following error Type mismatch. Below shows how I am creating the blank array:
Dim testArray(0 to 10) as string
Dim ABredu() As String
ABredu = Equipment(testArray)
Below shows the function that I have written to populate the array
Function Equipment(Test() As String)
If standYes = True And .ComboBox2.ListIndex = 0 Then
ReDim ABredu(1 To 3)
ABredu(1) = "Pen"
ABredu(2) = "Ruler"
ABredu(3) = "Monitor"
Else
ReDim ABredu(1 To 3)
ABredu(1) = "17-P2"
ABredu(2) = "17-L73"
ABredu(3) = "16-ENR"
End If
End sub
If someone could help me or give a push in the right direction it would be greatly appreciated!

Pass the array by reference as a variant.
Function Equipment(ByRef Test As Variant)
If standYes = True And .ComboBox2.ListIndex = 0 Then
ReDim Test(1 To 3)
Test(1) = "Pen"
Test(2) = "Ruler"
Test(3) = "Monitor"
Else
ReDim Test(1 To 3)
Test(1) = "17-P2"
Test(2) = "17-L73"
Test(3) = "16-ENR"
End If
End sub

Slightly different approach using variant arrays.
Sub Some_Macro()
Dim ABredu As Variant, i As Long
ABredu = Equipment(True, 0)
For i = LBound(ABredu) To UBound(ABredu)
Debug.Print ABredu(i)
Next i
ABredu = Equipment(False, 0)
For i = LBound(ABredu) To UBound(ABredu)
Debug.Print ABredu(i)
Next i
End Sub
Public Function Equipment(standYes As Boolean, cdLI As Long)
Dim vEQUIP As Variant
If standYes And cdLI = 0 Then
vEQUIP = Array("Pen", "Ruler", "Monitor")
Else
vEQUIP = Array("17-P2", "17-L73", "16-ENR")
End If
Equipment = vEQUIP
End Function
There are several ways to accomplish what you are looking for. Pick the one that makes the most sense to you.

Okay, so I'm going to make a couple of assumptions about your expected logic here, since the code in your question is a bit nonsensical.
You're trying (I think) to:
Create an array of strings called ABredu
Use a function or subroutine to populate that array based on some conditions
With that in mind, you can create the following sub
Sub PopulateEquipment(EquipArr() As String)
ReDim EquipArr(1 To 3)
If <condition> Then '<~~ Insert your own conditions here
EquipArr(1) = "Value 1"
EquipArr(2) = "Value 2"
EquipArr(3) = "Value 3"
Else
EquipArr(1) = "AltVal 1"
EquipArr(2) = "AltVal 2"
EquipArr(3) = "AltVal 3"
End If
End Sub
Then to populate your array using this, you need only Dim it and then call the subroutine, passing the variable as an argument.
Dim ABredu() As String
Call PopulateEquipment(ABredu)

Even simpler, use an ArrayList.
Public arList As Object
Sub PartOne()
Set arList = CreateObject("System.Collections.ArrayList")
Call Equipment
End Sub
Private Sub Equipment() '// No Need to pass argument as arList is of Public scope.
With arList
If standYes And Me.ComboBox2.ListIndex = 0 Then
.Add "Pen"
.Add "Ruler"
.Add "Monitor"
Else
.Add "17-P2"
.Add "17-L73"
.Add "16-ENR"
End If
End With
End Sub

Related

Check if ActiveX label contains part of string

I am using this code to hide a label based on if it contains % sign only and nothing else.
It is this part of the code it is erroring now when running. Error: "OLEFormat.Object: Invalid Request. Command cannot be applied to a shape range with multiple shapes"
What should be the correct code?
If InStr(1, myRange.OLEFormat.Object.Caption, "%", vbTextCompare) > 0 Then
Sub c_Three_RemovePercent()
For slideNumber = 1 To 11
Set mydocument = ActivePresentation.Slides(slideNumber)
mydocument.Select
Dim myArray() As Variant
Dim myRange As Object
myArray = Array("Lbl_V1", "Lbl_V2", "Lbl_V3", "Lbl_V4", "Lbl_V5")
Set myRange = ActivePresentation.Slides(1).Shapes.Range(myArray)
With mydocument.Shapes.Range(myArray)
If InStr(1, myRange.OLEFormat.Object.Caption, "%", vbTextCompare) > 0 Then
mydocument.Shapes(myRange).Visible = False
Else: mydocument.Shapes(myRange).Visible = True
End If
End With
Next slideNumber
End Sub
All these blindfolded late-bound member calls are easily confusing: you don't get IntelliSense to help you navigate the available members.
You're looking for an OLEObject, so declare one; assign it:
Dim oleLabel As Excel.OLEObject
Set oleLabel = ActivePresentation.Slides(1).Shapes("SomeShapeName").OLEFormat.Object
Now you want the control that's in that OLEObject's Object property, and you want to cast that control to its MSForms.Label interface:
Dim labelControl As MSForms.Label
Set labelControl = oleLabel.Object
Now you have an early-bound MSForms.Label interface to query, and IntelliSense guides you all the way:
If Contains(labelControl.Caption, "%") Then
'...
Else
'...
End If
Where Contains could look something like this:
Public Function Contains(ByVal source As String, ByVal substring As String) As Boolean
Contains = InStr(1, source, substring, vbTextCompare) > 0
End Function
You have an array of label control names you want to iterate - just iterate it:
Dim labelNames As Variant
labelNames = Array("label1", "label2", "label3", ...)
Dim i As Long
For i = LBound(labelNames) To UBound(labelNames)
Set oleLabel = currentSlide.Shapes(labelNames(i)).OLEObject
oleLabel.Visible = Not Contains(labelControl.Caption, "%")
Next
Note how this:
If BooleanExpression Then
Thing = True
Else
Thing = False
End If
Can be rewritten as:
Thing = BooleanExpression
For checking if string contains the vba function INSTR is typically best. Basically in the below example... Starting in the first position, check this text, look for "%", case insensative.
If InStr(1, myRange.OLEFormat.Object.Caption, "%", vbTextCompare) > 0 Then
mydocument.Shapes(myRange).Visible = False
Else: mydocument.Shapes(myRange).Visible = True
End If

How to update values in VBA dictionary

StackOverflow,
The below subroutine is intended to:
take a dictionary (ByRef), with value types = double, OR
take a dictionary of dictionaries (ByRef), with sub-dictionary value types = double, and
apply the calculation "ApproximateGeometricReturn" to each value within the dictionary.
While the code successfully runs, it fails to apply the calculation to the each value in the dictionary passed as an argument (ByRef).
Please suggest where I may have gone wrong. I have also attempted to write this as a recursive subroutine without success.
Private Sub ApproxiamteGeometricReturns(ByRef LogReturnDictionary As Variant)
For Each Item In LogReturnDictionary.Items
If TypeName(Item) = "Double()" Then
For Each i In Item
i = ApproximateGeometricReturn(i)
Next
Else
Item = ApproximateGeometricReturn(Item)
End If
Next
End Sub
Any suggestions will be warmly received. Thanks.
Private Sub ApproxiamteGeometricReturns(ByRef LogReturnDictionary As Variant)
For Each keyName In LogReturnDictionary.Keys
If TypeName(LogReturnDictionary(keyName)) = "Double()" Then
Dim arr As Variant: arr = LogReturnDictionary(keyName)
Dim index As Integer
For index = LBound(arr) To UBound(arr)
arr(index) = ApproximateGeometricReturn(arr(index))
Next
LogReturnDictionary(keyName) = arr
Else
LogReturnDictionary(keyName) = ApproximateGeometricReturn(LogReturnDictionary(keyName))
End If
Next
End Sub

Type mismatch error in VBA when adding data to textbox

I have a TextBox and a ListBox with a list of various cities being populated from an Excel file
Now each city has one of two options: either within territory or outside. I want that option to be shown in textBox
I tried something like this :
Private Sub CommandButton1_Click()
TextBox2.Value = Application.VLookup(Me.ListBox1.Text,Sheets("Sheet1").Range("B:C"), 2, False)
End Sub
But am getting error stating that :
Run Time Error 2147352571 (80020005) . Could not set Value property. Type mismatch.
My excel file is something like this :
Let say your data are stored in Sheet1. You want to bind these data to ListBox1 on UserForm. I'd suggest to use custom function to load data instead of binding data via using RowSource property. In this case i'd suggest to use Dictionary to avoid duplicates.
See:
Private Sub UserForm_Initialize()
Dim d As Dictionary
Dim aKey As Variant
Set d = GetDistinctCitiesAndTerritories
For Each aKey In d.Keys
With Me.ListBox1
.AddItem ""
.Column(0, .ListCount - 1) = aKey
.Column(1, .ListCount - 1) = d.Item(aKey)
End With
Next
End Sub
'needs reference to Microsoft Scripting Runtime!
Function GetDistinctCitiesAndTerritories() As Dictionary
Dim wsh As Worksheet
Dim dict As Dictionary
Dim i As Integer
Set wsh = ThisWorkbook.Worksheets("Sheet1")
Set dict = New Dictionary
i = 2
Do While wsh.Range("A" & i) <> ""
If Not dict.Exists(wsh.Range("B" & i)) Then dict.Add wsh.Range("B" & i), wsh.Range("C" & i)
i = i + 1
Loop
Set GetDistinctCitiesAndTerritories = dict
End Function
After that, when user clicks on ListBox, city and territory are displayed in corresponding textboxes.
Private Sub ListBox1_Click()
Me.TextBoxCity = Me.ListBox1.List(Me.ListBox1.ListIndex, 0)
Me.TextBoxTerritory = Me.ListBox1.List(Me.ListBox1.ListIndex, 1)
End Sub
Note: code was written straight from the head, so it can contains errors!
The problem is likely that you aren't checking to see to see if the call to Application.VLookup succeeded. Most values returned can be successfully cast to a String - with one important exception: If the VLookup returns an error, for example it doesn't find Me.ListBox1.Text - it can't cast the Variant returned directly.
This should demonstrate:
Private Sub ReturnsOfVLookup()
Dim works As Variant, doesnt As String
works = Application.VLookup("Something not found", _
Sheets("Sheet1").Range("B:C"), 2, False)
Debug.Print works
On Error Resume Next
doesnt = Application.VLookup("Something not found", _
Sheets("Sheet1").Range("B:C"), 2, False)
If Err.Number <> 0 Then
Debug.Print Err.Description
Else
Debug.Print doesnt 'We won't be going here... ;-)
End If
End Sub

Why ListBox doesn't have a FindString method in Excel-VBA?

Trying to search on a ListBox. Specifically, I want to look at an array of items from the Cell, and for each one that matches an entry in the ListBox, I want it to select that List.
I copy-pasted some code that was supposed to let me find a string, but it keeps telling me:
Compile Error: Method or Data Member not found.
Any suggestions?
Relevant Code:
Public local_Target As Range
' local_Target is assigned in the sheet function to pass it here
Private Sub Network_ListBox_Enter()
' Get data in cell (if any)
Dim current_data As String
Dim entries() As String
current_data = local_Target.Value
If current_data = "" Then
Exit Sub
Else
entries = Split(current_data, vbNewLine)
End If
For Each Item In entries
FindMyString Item
Next Item
End Sub
Private Sub UserForm_Terminate()
Dim index As Integer
Dim result As String
' Iterate through the listbox and create the result, then assign to
' Target.value
For index = 0 To Network_ListBox.ListCount - 1
If Network_ListBox.Selected(index) Then
' stuff
If result = "" Then
result = Network_ListBox.List(index)
' ElseIf index = Network_ListBox.ListCount - 1 Then
' result = result + Network_ListBox.List(index)
Else
result = result + vbNewLine + Network_ListBox.List(index)
End If
End If
Next index
local_Target.Value = result
End Sub
Sub FindMyString(ByVal searchString As String)
' Ensure we have a proper string to search for.
If searchString <> "" Then
' Find the item in the list and store the index to the item.
Dim index As Integer
index = Me.Network_ListBox.FindString(searchString)
' Determine if a valid index is returned. Select the item if it is valid.
If index <> -1 Then
Network_ListBox.SetSelected index, True
'Else
' MessageBox.Show ("The search string did not match any items in the ListBox")
End If
End If
End Sub
I checked Intellisense and I don't think that Method is supported in VBA. Other documentations I've found refers to .Net Framework only as well. So maybe, it is not really supported in VBA, but regardless, you can create a function to do just that. Something like below.
Private Function SearchString(mysearch As String, mylist As Variant) As Long
Dim itm As Variant, idx As Long: idx = 0
If IsArray(mylist) Then
For Each itm In mylist
If mysearch = itm Then
SearchString = idx: Exit Function
End If
idx = idx + 1
Next
End If
SearchString = -1
End Function
And you can use it like this:
Private Sub CommandButton1_Click()
Dim i As Long
'do the search
i = SearchString("WhatImSearching", Me.ListBox1.List)
'select the item that match your search
If i <> -1 Then Me.ListBox1.Selected(i) = True
End Sub
I'm not saying that the function I created above is the most efficient way.
That is just an example to give you an idea for a workaround. HTH.
Important: This works in single column ListBox which have a 1D array list. If you need to work on multi-column ListBox, you'll have to tweak the function a little.

FILTER Function for integers - VBA

I searched the website but was not succesfful and tried doing some research on this but facing with " Type Mismatch" error.
I declared an array as integer type but the FILTER function seems to work only with STRING's. Can you please let me know how I can use the FILTER function for integers?
If UBound(Filter(CntArr(), count)) > 0 Then
msgbox "found"
End If
as i understand you need to know if specified count present in array. You can use for loop for it:
Dim found as Boolean
found = False
For i = 0 To UBound (CntArr())
If CntArr(i) = count Then
found = True
Exit For
End If
Next i
If found Then msgbox "found" End If
Below I have created IsIntegerInArray() function that returns boolean. Follow the two Subs for an example of integer array declaration. Declaring array as Integer should also prevent some unnecessary bugs caused by implicit data conversion.
Sub test_int_array()
Dim a() As Integer
ReDim a(3)
a(0) = 2
a(1) = 15
a(2) = 16
a(3) = 8
''' expected result: 1 row for each integer in the array
Call test_printing_array(a)
End Sub
Sub test_printing_array(arr() As Integer)
Dim i As Integer
For i = 1 To 20
If IsIntegerInArray(i, arr) Then
Debug.Print i & " is in array."
End If
Next i
End Sub
Function IsIntegerInArray(integerToBeFound As Integer, arr() As Integer) As Boolean
Dim i As Integer
''' incorrect approach:
''' IsIntegerInArray = (UBound(Filter(arr, integerToBeFound)) > -1) ' this approach searches for string, e.g. it matches "1" in "12"
''' correct approach:
IsIntegerInArray = False
For i = LBound(arr) To UBound(arr)
If arr(i) = integerToBeFound Then
IsIntegerInArray = True
Exit Function
End If
Next i
End Function