Passing 2-dimensional arrays between subroutines Excel VBA - excel

I cannot seem to get this to work.
I want to pass a 2D-array from a subroutine to other subroutines in which a data manipulation should take place.
I am calling below subroutine from a command button on Sheet1. In Module1 I have declared the variables as public. Inside the subroutine ReadData, at the End If statement, InputArray is populated with an array consisting of numbers that the user has marked following the inputbox. After the subroutine ReadData has completed, InputArray is empty.
What is the obvious and blatantly daft thing that am I doing wrong?
** Sheet1**:
Private Sub CommandButton1_Click()
Call ReadData
End Sub
**Module1**:
Option Explicit
Option Base 1
Public MyRange, InputArray As Variant
Sub ReadData()
Set MyRange = Application.InputBox("Mark the data array", Type:=8)
If Not MyRange Is Nothing Then
InputArray = MyRange
End If
End Sub

Populate the array as follows and inspect in the locals window. By using .Value you create a 2D array from the selected sheet range. MyRange I think can be local scope and declared as Range. InputArray should probably be a local scope as well and simply passed as an argument to other subs/functions.
Public InputArray As Variant
Sub ReadData()
Dim MyRange As Range
Set MyRange = Application.InputBox("Mark the data array", Type:=8)
If Not MyRange Is Nothing Then
InputArray = MyRange.Value
Stop '<==Delete me after inspection
End If
End Sub

No need for public variables at all.
option explicit
'** Sheet1**:
Private Sub CommandButton1_Click()
dim InputArray as variant, i as long, j as long
ReadData InputArray
for i = lbound(InputArray, 1) to ubound(InputArray, 1)
for j = lbound(InputArray, 2) to ubound(InputArray, 2)
debug.print InputArray(i, j)
next j
next i
End Sub
'**Module1**:
Option Explicit
Sub ReadData(byref arr as variant)
dim myrange as range
Set MyRange = Application.InputBox("Mark the data array", Type:=8)
If Not MyRange Is Nothing Then
arr = MyRange.value
End If
End Sub
1
4
7
10
2
5
8
11
3
6
9
12

along the lines of #Jeeped 's approach, you could simplify code by turning ReadData() to a Function, as follows:
Sheet1:
Function ReadData() As Variant
On Error Resume Next
ReadData = Application.InputBox("Mark the data array", Type:=8).Value
End Function
Module1:
Option Explicit
Private Sub CommandButton1_Click()
Dim InputArray As Variant
InputArray = ReadData
If IsEmpty(InputArray) Then
MsgBox "not a valid selection", vbCritical
Else
'do your stuff with InputArray
End If
End Sub
or you could have your ReadData() function return a Boolean to flag for a successful range selection :
Sheet1:
Function ReadData(arr As Variant) As Boolean
On Error Resume Next
arr = Application.InputBox("Mark the data array", Type:=8).Value
ReadData = Not IsEmpty(arr)
End Function
Module1:
Option Explicit
Private Sub CommandButton1_Click()
Dim InputArray As Variant
If ReadData(InputArray) Then
'do your stuff with InputArray
Else
MsgBox "not a valid selection", vbCritical
End If
End Sub

Related

Checking for an item in a listbox in a array

Sub PopulatingArray()
'Declare the array as a variant array
Dim groupA() As Variant
'Declare the integer to store the number of rows
Dim iRw As Integer
'Assign range to a the array variable
groupA = Range("AA1:AA132")
'loop through the rows - 1 to 10
For iRw = 1 To UBound(groupA)
'show the result in the immediate window
Debug.Print groupA(iRw, 1)
Next iRw
End Sub
For Each person In ListBox2.Items
If (groupA.Contains(People)) Then
MsgBox ("Lets Go")
End If
Next person
Assuming your code is on the userform that contains the listbox, give this a go. A test procedure will run when you open the form.
Option Explicit' not required, but good practice
'Declare the array as a variant array
Dim groupA() As Variant ' mus be before all subs in module
Sub PopulatingArray()
'Declare the integer to store the number of rows
Dim iRw As Integer
'Assign range to a the array variable
groupA = Range("AA1:AA132")
'loop through the rows - 1 to 10
For iRw = 1 To UBound(groupA)
'show the result in the immediate window
Debug.Print groupA(iRw, 1)
Next iRw
End Sub
Sub check_array()
Dim person As Variant
For Each person In ListBox2.List
If contains(groupA, person) Then
MsgBox ("Lets Go " & person)
End If
Next person
End Sub
Function contains(arr As Variant, value As Variant) As Boolean
Dim x As Integer
For x = LBound(arr, 1) To UBound(arr, 1)
If arr(x, 1) = value Then
contains = True
Exit Function
End If
Next
End Function
Private Sub UserForm_Activate()
PopulatingArray
check_array
End Sub

UserForm to add from a selected cell from a TextBox value

I am trying to have a UserForm GUI so that we can add and subtract from inventory, I have got it so that I can select a worksheet and a row, but I am having trouble adding and subtracting part. Pretty new to VBA and I am not sure how to call that variable and modify it. Any help would be great!! Here is my code in the UserForm:
Option Explicit
Private Sub BTNadd_Click()
End Sub
Private Sub BTNDone_Click()
'This will save and close the GUI'
ThisWorkbook.Save
StgRmGUI.Hide
End Sub
Private Sub BTNrmv_Click()
End Sub
Private Sub ItmNmSlct_Change()
Dim actItm As String
End Sub
Private Sub ItmTypSlct_Change()
'This allows ItmTypSlct to show available wrkshts then will make item show in Item Name box'
With Worksheets(ItmTypSlct.Value)
ItmNmSlct.RowSource = Range(.Cells(2, 1), .Cells(Rows.Count, 1).End(xlUp)).Address(, , , True)
End With
End Sub
Private Sub NumBox_Change()
Dim NewVal As Integer
NewVal = Val(NumBox.Text)
If NewVal >= SpBtnARNum.Min And _
NewVal <= SpBtnARNum.Max Then _
SpBtnARNum.Value = NewVal
End Sub
Private Sub SpBtnARNum_Change()
NumBox.Text = SpBtnARNum.Value
End Sub
Private Sub UserForm_Click()
End Sub
Private Sub UserForm_Initialize()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
If ws.Visible = xlSheetVisible Then
ItmTypSlct.AddItem ws.Name
End If
Next ws
End Sub
An simple example of updating the column B value by the amount in NumBox
Private Sub BTNadd_Click()
Dim r As Long, cell As Range
With ItmNmSlct
r = .ListIndex
If r < 0 Then Exit Sub
' select quatity cell and increment value
Set cell = Range(.RowSource).Cells(r + 1, 2)
cell.Value = cell.Value + NumBox.Value
End With
End Sub

VBA unexpetcted end of sub error

I found the following VBA code to sum coloured cells, however I get an unexpected end of statement error in the penultimate line:
Function SumByColor(CellColor As Range, SumRange As Range)
Application.Volatile
Dim ICol As Integer
Dim TCell As Range
ICol = CellColor.Interior.ColorIndex
For Each TCell In SumRange
If ICol = TCell.Interior.ColorIndex Then
SumByColor = SumByColor + TCell.Value
End If
Next TCell
End Function
Sub Count_red()
=SumByColor(AC4,J2:AK1725)
End Sub
Edit: I adjusted the last bit according to your suggestions
Sub Count_red()
Function Count_red() As Double
Count_red = SumByColor([AC4], [J2:A1725])
End Function
End Sub
The new error message when I try to run the code: "Ambiguous name detected: Count_red()"
Sub Count_red()
=SumByColor(AC4,J2:AK1725)
End Sub
Is an assignment to nothing.
Based on the names, I am guessing it is supposed to be
Function Count_red()
Count_red=SumByColor([AC4],[J2:AK1725])
End Function

VBA, If active cell in range does not equal a String call Macro

I am very new to the World of VBA. I am attempting to add to an existing Private Sub(Change). I am trying to "fire" the Macro "DelRCE" When the Active Cell in Range("K2:K700") Does Not equal the word "Down".
The code below is not working:
Dim txt As String
Dim rng As Range
Dim vec As String
txt = ActiveCell.Value
rng = ("K2:K700")
vec = "Down"
If r_ng.txt <> vec Then
Call Macro
End If
I assume you are looking for something like this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Dim key As String
Dim rng As Range
'Set the word you want to search for. Take capital letters into account
key = "down"
'Set worksheet to the first sheet in your workbook
Set ws = ThisWorkbook.Sheets(1)
'Change this to the range you want to search
Set rng = ws.Range("A1:A100")
'Check if the target is in the range
If Not Intersect(Target, rng) Is Nothing Then
If Target.Value <> key Then
'Change this to you function call
MsgBox "The target is inside the range and the value is different from '" & key & "'"
End If
End If
End Sub
Put the cursor inside the test_Change sub and hit PF5 to run it.
private Sub Change()
Dim txt As String
Dim rng As Range
Dim vec As String
txt = ActiveCell.Value
rng = ("K2:K700")
vec = "Down"
If r_ng.txt <> vec Then
Call DelRCE ' or "Run DelRCE" if it is a function
End If
End Sub
Private Sub test_Change()
call Change
End Sub
Add the code below to the relevent Worksheet module, under the Worksheet_Change event:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim vec As String
vec = "Down"
If Not Intersect(Target, Range("K2:K700")) Is Nothing Then ' check that modifed cell is inside the Range("K2:K700")
If Target.Count > 1 Then Exit Sub ' Optional : if more than 1 cell selected exut the sub
If Not Target.Value Like vec Then ' Also possible to use: If Target.Value <> vec
Call Macro
End If
End If
End Sub

Excel - VBA Removing Duplicates from Comboboxes

I am trying to create a subroutine to delete duplicates out of comboboxes. I input a number in place of X when I called the subroutine. I keep getting an error that tells me "Object Required" when i get to the subroutine. I know that means that something is not being properly initialized, but I cannot figure out how to fix my issue. Any help would be greatly appreciated. Thank you.
Private Sub UserForm_Initialize()
'ComboBox Populate
Dim rngNext As Range
Dim myRange As Range
Dim C As Integer
With Sheets("KEY")
Set rngNext = .Range("B500").End(xlUp).Offset(1, 0)
End With
rngNext.Select
Set myRange = Range("B2", rngNext)
With ComboBox1
For Each rngNext In myRange
If rngNext <> "" Then .AddItem rngNext
Next rngNext
End With
Call RemoveDuplicates(1)
End sub
Private Sub RemoveDuplicates(X)
'Remove Duplicates
Dim i As Long
Dim j As Long
With "ComboBox" & X
For i = 0 To .ListCount + 1 'Getting object required error in this line
For j = .ListCount To (i + 1) Step -1
If .List(j) = .List(i) Then
.RemoveItem j
End If
Next
Next
End With
End Sub
Final Code
Everything works great for removing duplicates.
Public allCBoxes As Collection
Private Sub UserForm_Initialize()
Set allCBoxes = New Collection
allCBoxes.Add ComboBox1
'ComboBox Populate
Dim rngNext As Range
Dim myRange As Range
Dim C As Integer
With Sheets("KEY")
Set rngNext = .Range("B500").End(xlUp).Offset(1, 0)
End With
rngNext.Select
Set myRange = Range("B2", rngNext)
With ComboBox1
For Each rngNext In myRange
If rngNext <> "" Then .AddItem rngNext
Next rngNext
End With
Call RemoveDuplicates(1)
End sub
Private Sub RemoveDuplicates(X)
'Remove Duplicates
Dim i As Long
Dim j As Long
With allCBoxes(X)
For i = 0 To .ListCount + 1
For j = .ListCount -1 To (i + 1) Step -1
If .List(j) = .List(i) Then
.RemoveItem j
End If
Next
Next
End With
End Sub
You get an error because you're passing a string, not an object.
Although intuitively you can think that:
"ComboBox" & X
will become, for example if x = 5,
ComboBox5
you're wrong because you're actually building a string:
"ComboBox5"
And, clearly, if you call a method of a ComboBox object on a String, you will be prompted of "Object Required".
What you want to do is impossible in VBA, where you cannot define variable names at run-time (i.e. ComboBox & X, even if not "as string", will not reference the variable ComboBox5). To reach what you want, I suggest to create a public collection:
Dim allCBoxes As Collection
then to populate it on the main procedure:
Set allCBoxes = New Collection
allCBoxes.Add ComboBox1
allCboxes.Add ComboBox2
'etc.
and finally recovering the "Xth" combobox like this:
With allCBoxes(X)
End With
If you want to reference a control using its string name, use the Controls function.
Such as:
With Controls("Combobox" & X)
Does that resolve the problem?
As mentioned in my comment above, here's a different approach towards solving the underlying problem: needing a combobox without duplicate values. This method uses a Dictionary object.
Let me know if you can adapt it to your needs, and if it works.
Private Sub UserForm_Initialize()
Dim oDictionary As Object
Dim strCellContent As String
Dim rngComboValues As Range
Dim rngCell As Range
Set rngComboValues = Range("A1:A26")
Set oDictionary = CreateObject("Scripting.Dictionary")
For Each rngCell In rngComboValues
strCellContent = rngCell.Value
If Not oDictionary.exists(strCellContent) Then
oDictionary.Add strCellContent, 0
End If
Next rngCell
For Each itm In oDictionary.keys
Me.ComboBox1.AddItem itm
Next itm
Set oDictionary = Nothing
End Sub

Resources