VBA temporarily create and delete ListBox after processing array - vba

Don't have much experience with forms/listboxes. The following function aims to remove an array element by passing it to ListBox and using ListBox.RemoveItem method. What i am struggling with is creating/deleting ListBox object programmatically. I do know there are ActiveX and Form ListBox types but recording a code by adding both manually looks identical:
ActiveSheet.ListBoxes.Add(273, 289.5, 72, 71.25).Select
Here is the attempted function:
Function ArraylessElement(arrIn As Variant, ElemNo As Integer) As Variant
''''''''''''''''''''''''''''''''
'removes i element from 1D array by assigning to ListBox
'returns 1D array w/ Transpose
''''''''''''''''''
Dim lBox As ListBox
With ActiveSheet
Set lBox = .ListBoxes.Add(261, 279.75, 72, 71.25)
lBox.List = arrIn
lBox.RemoveItem (ElemNo - LBound(arrIn) - 1) '(LBound) of a ComboBox/ ListBox is 0.
ArraylessElement = Application.Transpose(lBox.List)
lBox.Delete
End With
End Function
I'm getting
Unable to set the list property of the ListBox class
error on lBox.List = arrIn line.
PS. I did see a DeleteArrayElement function at http://www.cpearson.com/excel/vbaarrays.htm which i will use if i cannot get mine working.

Related

ShapeSheet cell reference error when using Shape.SetFormulas in Visio

When I try to use .SetFormulas to reference Connector shapes on different page, I keep getting the #Name? error. The error would occur in both Visio 2010 and 2016. The code below works for circles and grouped shapes but not my connectors.
Dim formArray as String() = BuildFormulaArray(PreviousPageShapeIDs)
Dim theStream as Short() = StreamBuilder(CurrentShapeIDs, CustPropSection, Row, Cell)
Dim objArray as Object() = formArray.ConverToObject 'convenience function to convert each item to an object
vPage.SetFormulas(theStream, objArray, VisGetSetArgs.visSetBlasGuards)
However, the code below works with the connectors
For i = 0 to formArray.GetUpperBounds(0)
Dim streamInd as Integer = 4*i
vPage.Shapes(theStream(streamInd)).CellsSRC(theStream(streamInd+1),theStream(streamInd+2),theStream(streamInd+3)).FormulaForce = formArray(i)
Next
My formula is referencing cells using the Pages[PageName]!Sheet.ShapeID!CellName method.
I know I can make this work by using CellsSRC or using the shape name in my formula, but I would rather stick with using SetFormulas and shape IDs for speed reasons. Any ideas on why Visio is behaving inconsistently?

Grouping form controls using dictionary, collection or class

I am trying to categorize/group my form controls in order to be able to apply changes to several of them in one go. For instance, I may want to enable/disable them.
Should I add the form controls to collections, dictionaries or should I create classes?
Ideally I would like to create categories and sub-categories. I would define properties for the categories and the sub-categories. The properties of the categories would be passed to the "child" sub-categories.
For instance, if the font of CategoryA is "arial" the font of subcategories A1, A2 ect would also be "arial".
I would only "store" the objects in the sub-categories. If you have ideas how I could such architecture please make some suggestions.
At this stage I have created a dictionary. I am quite sure that I cannot create the categories/sub-categories I would like to with dictionaries and collections but it's still a first step in the right direction (bulk changes).
The problem I am facing with dictionaries is that the properties/methods specific to the controls do not display in the IntelliSense. How can I make them available?
Public dct As New Dictionary(Of Object, Integer)
Dim ctlr As Control
Dim i As Integer
i = 1
For Each ctlr In Controls
dct.Add(ctlr.Name, i)
i = i + 1
Next
For Each Item In dct
'Enabled is not available
Item.Enabled = False
Next
I would dump the dictionary and use a List(Of T). Add the actual object to the list and the properties should be available. In any case here is the dictionary code. Comments and explanation in-line.
Public dct As New Dictionary(Of String, Integer)
'I changed Object to String because that is what you are
'adding to the dictionary. I don't see where the .Value
'is ever used so I suggest changint to List(Of Button) or List(Of Control)
Private Sub OpCode2()
Dim ctlr As Control
Dim i As Integer
i = 1
'This saves the name of the control to the key of the dictionary
'This is just a string unrelated to a control as far as the dictionary knows
For Each ctlr In Controls
dct.Add(ctlr.Name, i)
i = i + 1
Next
For Each Item As KeyValuePair(Of String, Integer) In dct
'The .Find method returns a control using the control name
Dim ctrl As Control = Controls.Find(Item.Key, True).FirstOrDefault()
'The properties inherited from Control will be available in intellisense
'If you need a property of a particular type of control
'you will need to cast ctrl to the type you need
ctrl.Enabled = False
Next
End Sub
The following code uses List(Of T) and is much shorter and easier to read.
Public lst As New List(Of Control)
Private Sub OpCode2()
Dim ctlr As Control
For Each ctlr In Controls
lst.Add(ctlr)
Next
For Each Item In lst
'The list actually contains a reference to the control
'so properties of Control are available
Item.Enabled = False
Next
End Sub

Create a ComboBox object to pass it into a Sub

I am trying to access a ComboBox on a UserForm from a sub. Therefore I'm trying to pass a Combobox object into it.
However, I don't seem to be able to create a Combobox Object in order to pass it in. They are always empty when entering the sub. This is what I've been trying:
Dim ctl As ComboBox
Set ctl = Me.cb_FcnName 'cb_FcnName is the name of the Combobox I'm trying to access
Call ColumnEntries2Combobox(ctl)
And this is my Sub:
Private Sub ColumnEntries2Combobox(ByRef Combo As ComboBox)
Combo.AddItem = Worksheets(WorksheetName).Cells(currRow, 2)
End Sub
For some reason I can't seem to find any documentation on how to create the necessary combobox object to pass into the sub...
Thanks in advance for any kind of help!
AddItem is a method, not a property. For a method we supply arguments after a space, compared to setting a property equal to something.
So change
Combo.AddItem = Worksheets(WorksheetName).Cells(currRow, 2)
to
Combo.AddItem Worksheets(WorksheetName).Cells(currRow, 2)
This is a common error, so a simple demonstration is:
object.Property = value
object.Method arg1, arg2

Access VBA listing collection items in a class module

Although I'm reasonable experienced VBA developer, I have not had the need to use class modules or collections but thought this may be my opportunity to extend my knowledge.
In an application I have a number of forms which all have the same functionality and I now need to increase that functionality. Towards that, I am trying to reorder a collection in a class module, but get an error 91 - object variable or with block not set. The collection is created when I assign events to controls. The original code I obtained from here (Many thanks mwolfe) VBA - getting name of the label in mousemove event
and has been adapted to Access. The assignments of events works well and all the events work providing I am only doing something with that control such as change a background color, change size or location on the form.
The problem comes when I want to reorder it in the collection - with a view to having an impact on location in the form. However I am unable to access the collection itself in the first place.
The below is my latest attempt and the error occurs in the collcount Get indicated by asterisks (right at the bottom of the code block). I am using Count as a test. Once I understand what I am doing wrong I should be able to manipulate it as required.
mLabelColl returns a correct count before leaving the LabelsToTrack function, but is then not found in any other function.
As you will see from the commented out debug statements, I have tried making mLabelColl Private and Dim in the top declaration, using 'Debug.Print mLabelColl.Count' in the mousedown event and trying to create a different class to store the list of labels.
I feel I am missing something pretty simple but I'm at a loss as to what - can someone please put me out of my misery
Option Compare Database
Option Explicit
'weMouseMove class module:
Private WithEvents mLbl As Access.Label
Public mLabelColl As Collection
'Dim LblList as clLabels
Function LabelsToTrack(ParamArray labels() As Variant)
Set mLabelColl = New Collection 'assign a pointer
Dim i As Integer
For i = LBound(labels) To UBound(labels)
'Set mLabelColl = New Collection events not assigned if set here
Dim LblToTrack As weMouseMove 'needs to be declared here - why?
Set LblToTrack = New weMouseMove 'assign a pointer
Dim lbl As Access.Label
Set lbl = labels(i)
LblToTrack.TrackLabel lbl
mLabelColl.Add LblToTrack 'add to mlabelcoll collection
'Set LblList as New clLabels
'LblList.addLabel lbl
Next i
Debug.Print mLabelColl.Count 'returns correct number
Debug.Print dsform.countcoll '1 - incorrect
End Function
Sub TrackLabel(lbl As Access.Label)
Set mLbl = lbl
End Sub
Private Sub mLbl_MouseDown(Button As Integer, Shift As Integer, x As Single, Y As Single)
Dim tLbl As Access.Label
'Debug.Print LblList.Count 'Compile error - Expected function or variable (Despite Count being an option
'Debug.Print mLabelColl.Count 'error 91
'Debug.Print LblList.CountLbls 'error 91
Debug.Print collCount
End Sub
Property Get collCount() As Integer
*collCount = mLabelColl.Count* 'error 91
End Property
In order to have all the weMouseMove objects reference the same collection in their mLabelColl pointer, a single line can achieve it:
LblToTrack.TrackLabel lbl
mLabelColl.Add LblToTrack
Set LblToTrack.mLabelColl = mLabelColl ' <-- Add this line.
But please be aware that this leads to a circular reference between the collection and its contained objects, a problem that is known to be a source of memory leaks, but this should not be an important issue in this case.

Method or Data Member not found Error

I am trying to filter my combobox on Outlook Macro. But I am getting the error as mentioned on title. Could you please help me to solve this problem?
It works on Visual Studio but doesn't work on Outlook Macro.
Private Sub cmbProjects_Change()
Dim SelectedText As String
SelectedText = cmbProjects.text
Dim Items As Object
Items = CreateObject("System.Collections.ArrayList")
Items = cmbProjects.Items
Dim newList As Object
newList = CreateObject("System.Collections.ArrayList")
For Each Item In Items
If Item.Contains(SelectedText) Then
newList.Add (Item)
End If
Next
cmbProjects.DataSource = newList
End Sub
You need to add set since it's an object reference. And you are trying to access this object's (you assumed as an ArrayList) with its member methods/properties. Which fails. So change to,
Set Items = CreateObject("System.Collections.ArrayList")
Set newList = CreateObject("System.Collections.ArrayList")
Further check if you have the right reference added in your VBA editor for collection library objects.
CreateObject("System.Collections.ArrayList")
As per my comments, Items = cmbProjects.Items also fails with the same error. That's because cmbProjects doesn't have a method called Items. So you need to use List instead.. List returns a variant object.
Since you can't cast a variant into an ArrayList. You have to iterate through the variant and add items into the ArrayList. Note I am writing on the fly, the code is not tested. You may test it out and comment, should you need further assistance. I strongly recommend you to validate this pseudo-code against the accurate syntax.
Dim vr as Variant
Dim i as Integer
vr = cmbProject.List
'--add error handling to check if vr is empty or if cmbProject is empty.
For i = 0 to UpperBound(vr)
Items.Add (vr(i))
Next i