How to reference an element in a class collection - vba

I have a collection of Toggle Buttons along with the object name of the toggle button, as is shown in the watch screen shot
I have tried to reference the sName for the second item in the collection with this line itbcollection.Item(2).sName but it gives me Object does not support this property or method error. What is the appropriate code to get to the sName?
There is a class that is used to capture Mouse Down events, assigned to several ToggleButtons.
Option Explicit
Private WithEvents cTB As MSForms.ToggleButton
Private sName As String
Public Property Let aTB(iTB As ToggleButton)
Set cTB = iTB
sName = cTB.Name
End Property
Private Sub cTB_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal Y As Single)
If Button = 1 Then Exit Sub
Module1.RightClickDay cTB.Caption
End Sub
and at form load a loop finds all ToggleButtons and loads the collection
Dim tbEvent As cObjectArray
Dim TB(42) As Object
x = 0
For Each o In UFShows.Controls
If o.Tag = "T" Then
Set TB(x) = o
x = x + 1
o.Visible = False
Set tbEvent = New cObjectArray
tbEvent.aTB = o
iTBcollection.Add tbEvent
End If
Next o

Please, use the next adapted class code and name it "TGButClass":
Option Explicit
Public WithEvents cTB As MSForms.ToggleButton 'if not Public, it will not be exposed!
Public sName As String 'if not Public, it will not be exposed!
Public Property Set aTB(iTB As MSForms.ToggleButton)'you need Set here (nothing to be extracted, you need to Set)
'and As TooggleButtin means a sheet control
Set cTB = iTB
sName = cTB.Name
End Property
Private Sub cTB_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal Y As Single)
If Button = 1 Then Exit Sub
Module1.RightClickDay cTB.Caption
End Sub
A testing called sub RightClickDay should look like:
Sub RightClickDay(strName As String)
MsgBox strName
End Sub
Then, in the form code module you should paste the next declarations and UserForm_Initializeevent:
Option Explicit
Private objMyEventClass As New Collection
Public tbEvents As TGButClass
Private Sub UserForm_Initialize()
Dim o As Control, x As Long
For Each o In Me.Controls
If o.Tag = "T" Then
x = x + 1
Set tbEvents = New TGButClass
Set tbEvents.aTB = o
objMyEventClass.Add tbEvents
Debug.Print objMyEventClass(x).sName 'to see the (now) exposed sName
End If
Next o
End Sub
Please, send some feedback after testing it.
If something not clear enough, do not hesitate to ask for clarifications.
A similar result can be obtained using an array instead of a collection, too.

Related

One event sub for multiple textboxes instead of declaring it multiple time?

Is it possible to have one change event procedure for multiple textboxes in the same workbook?
If for example, I have a textbox named "textbox3" in the 1st, 2nd, and 3rd sheet of the workbook and I would like this single code below to work for all of them (the textboxes) rather than having to declare it on each sheet. Right now, I have to declare the same procedure on all the sheets but I only want to declare it once since it does the same thing on all of them.
'my procedure
Sub testObj()
Dim i As Integer, obj As oleobject
Set ac = ThisWorkbook.ActiveSheet
For Each obj In ac.oleobjects
If TypeName(obj.Object) = "TextBox" And obj.name = "TextBox3" Then
i = i + 1
ReDim Preserve TextArray(1 To i)
Set TextArray(i).TextBoxEvents = obj
End If
Next obj
Set obj = Nothing
End Sub
'My class1
Public WithEvents TextBoxEvents As MSForms.TextBox
'Public WithEvents TextBoxEvents As OLEObject
Private Sub TextBoxEvents_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = vbKeyTab Then
TextBox12.Activate
End If
End Sub
Here's an example
Class module named clsTextBox:
Option Explicit
Public WithEvents TextBoxEvents As MSForms.TextBox
Private Sub TextBoxEvents_Change()
Debug.Print TextBoxEvents.Name & ": " & TextBoxEvents.Text
End Sub
'Private Sub TextBoxEvents_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
' If KeyCode = vbKeyTab Then
' TextBox12.Activate 'unclear what you're aiming for here?
' End If
'End Sub
Regular module:
Dim ColTB As Collection
Sub testObj()
Dim i As Integer, obj As OLEObject, ac As Worksheet
Set ac = ThisWorkbook.ActiveSheet
Set ColTB = New Collection
For Each obj In ac.OLEObjects
If TypeName(obj.Object) = "TextBox" Then
ColTB.Add EventObj(obj.Object)
End If
Next obj
Set obj = Nothing
End Sub
Function EventObj(obj As MSForms.TextBox) As clsTextBox
Dim o As New clsTextBox
Set o.TextBoxEvents = obj
Set EventObj = o
End Function

How to modify the appearance of UserForm Labels using Class Module?

I have this UserForm (Image 1) and I'm trying to apply some customization through Class Module. So, my first goal was to modify the label format when it was clicked (Image 2). So far so good, I've accomplished this through the Class Module "cLabels". Now, my second goal is (this is the one I'm stuck) to apply some other color to the aforementioned Label. The point is, I don't know how to accomplish this.
I tried to create other class module called "cUserForm", but I don't how to pass the label modified to the cUserForm Class Module and use its MouseMove Event. I know I could apply the modification through the standard UserForm Module using the MouseMove Event, but the thing is, I don't want any code like that in my UserForm Module, I want the class module doing the "dirty" work. Do guys have any ideas how can I circumvent the problem?
Additional information (but not important to solve the problem): My final goal is to make "Buttons" like this https://drive.google.com/file/d/1ev_LNgxPqjMv0dtzlF7GSo7SOq0wDbR2/view?usp=sharing with some effects such as MouseHover, TabPress and so on. VBA buttons are very ugly. Just for the record, I've already done all this in a standard UserForm module (If anyone wants the workbook to see what I'm talking about, I have it), but the final result was just a mess, so many code (and It was just the code to modify the appearance of the UserForm, imagine when I put some code to do certain action, omg).
Image 1
Image 2
Here is what I have so far:
UserForm Module
Option Explicit
Private ObjLabel As cLabels
Private ObjUserForm As cUserForm
Private Sub UserForm_Initialize()
Set ObjLabel = New cLabels
ObjLabel.CallClasse Me
Set ObjUserForm = New cUserForm
Set ObjUserForm.UserFormValue = Me
End Sub
cLabels
Option Explicit
'## Events/Variables/Collections
Private WithEvents clsLabel As MSForms.Label
Private ClasseObject As cLabels
Private LabelCollection As New Collection
'## Properties
Public Property Get ActiveLabel() As MSForms.Label
Set ActiveLabel = clsLabel
End Property
Public Property Set ActiveLabel(Value As MSForms.Label)
Set clsLabel = Value
End Property
'## Procedures/Methods
Private Sub clsLabel_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
LabelHovered
End Sub
Public Sub CallClasse(MainObject As MSForms.UserForm)
Dim ctrl As MSForms.Control
For Each ctrl In MainObject.Controls
If TypeOf ctrl Is MSForms.Label Then
Set ClasseObject = New cLabels
Set ClasseObject.ActiveLabel = ctrl
LabelCollection.Add ClasseObject
End If
Next ctrl
End Sub
Private Sub LabelHovered()
ActiveLabel.BackColor = vbYellow
End Sub
cUserForm
Option Explicit
'## Events/Variables/Collections
Private WithEvents clsUserForm As MSForms.UserForm
Private mActiveLabel As MSForms.Label
Private ObjLabel As New cLabels
'## Properties
Public Property Get UserFormValue() As MSForms.UserForm
Set UserFormValue = clsUserForm
End Property
Public Property Set UserFormValue(Value As MSForms.UserForm)
Set clsUserForm = Value
End Property
Public Property Get ActiveLabel() As MSForms.Label
Set ActiveLabel = mActiveLabel
End Property
Public Property Set ActiveLabel(Value As MSForms.Label)
Set mActiveLabel = Value
End Property
'## Procedures
Private Sub clsUserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
'MsgBox ObjLabel.ActiveLabel.BackColor 'Got an error
End Sub
Workbook:
https://drive.google.com/file/d/1cLG4pLmC-jDaysjd_dK0EFuJ_LqYqJ-u/view?usp=sharing
I found your question very interesting and I've got a bit of a different, more object oriented take on how you might do this. I tried implementing an Observer Pattern to get the described effect. (As a side note, normally I would generalize a solution a bit more using Interfaces, but for this quick demo, I will show a couple of tightly coupled classes that get the job done)
Allow me to first introduce all my components:
Classes:
LabelObserver
Option Explicit
Private WithEvents mInteralObj As MSForms.label
Private mBackGroundColor As Long
Private mMouseOverColor As Long
Private Const clGREY As Long = &H8000000F
'// "Constructor"
Public Sub Init(label As MSForms.label, _
Optional mouseOverColor As Long = clGREY, _
Optional backGroundColor As Long = clGREY)
Set mInteralObj = label
mBackGroundColor = backGroundColor
mMouseOverColor = mouseOverColor
End Sub
Private Sub Class_Terminate()
Set mInteralObj = Nothing
End Sub
Public Sub MouseLeft()
'//Remove Highlight
mInteralObj.BackColor = mBackGroundColor
End Sub
Private Sub mInteralObj_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
'//Highlight
mInteralObj.BackColor = mMouseOverColor
End Sub
LabelNotifier
Option Explicit
Private observersCollection As Collection
Private Sub Class_Initialize()
Set observersCollection = New Collection
End Sub
Public Sub AddObserver(observer As LabelObserver)
observersCollection.Add observer
End Sub
Public Sub RemoveObserver(observer As LabelObserver)
Dim i As Long
'// We have to search through the collection to find the observer to remove
For i = 1 To observersCollection.Count
If observersCollection(i) Is observer Then
observersCollection.Remove i
Exit Sub
End If
Next i
End Sub
Public Function ObserverCount() As Integer
ObserverCount = observersCollection.Count
End Function
Public Sub Notify()
Dim obs As LabelObserver
If Me.ObserverCount > 0 Then
For Each obs In observersCollection
'//call each observer's MouseLeft method
obs.MouseLeft
Next obs
End If
End Sub
Private Sub Class_Terminate()
Set observersCollection = Nothing
End Sub
Module:
LabelObserverFactory (this is kinda optional - it simply provides a nice streamlined way of creating valid LabelObservers)
Option Explicit
Public Function NewYellowHighlightCustomLabel(label As MSForms.label) As LabelObserver
Dim product As New LabelObserver
product.Init label, vbYellow
Set NewYellowHighlightCustomLabel = product
End Function
Public Function NewRedHighlightCustomLabel(label As MSForms.label) As LabelObserver
Dim product As New LabelObserver
product.Init label, vbRed
Set NewRedHighlightCustomLabel = product
End Function
UserForm
MyForm (note that this form has three labels with default names placed on it for the purposes of this demo)
Option Explicit
Private notifier As LabelNotifier
Private Sub UserForm_Initialize()
Set notifier = New LabelNotifier
'//add controls to be notified
notifier.AddObserver LabelObserverFactory.NewYellowHighlightCustomLabel(Me.Label1)
notifier.AddObserver LabelObserverFactory.NewRedHighlightCustomLabel(Me.Label2)
notifier.AddObserver LabelObserverFactory.NewYellowHighlightCustomLabel(Me.Label3)
End Sub
Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
'//Notify labels that mouse has left them
notifier.Notify
End Sub
Private Sub UserForm_Terminate()
Set notifier = Nothing
End Sub
Now, to explain what's going on here:
The form has a LabelNotifier object, which gets established when the form initializes, that it will use to notify our labels that the mouse has moved away from them. We do this by listening for the form's MouseMove event. (I know you are trying to avoid using this, but hopefully the fact that ours will just have one line of code, no matter how many labels you are impacting, will satisfy the desire to encapsulate logic elsewhere.) When we get a mouse move, we will have the notifier do its only job, to send a message to all the labels we added to it.
The LabelObserver is the counter part of the LabelNotifier. A label observer is responsible for telling the labels to change color and which colors to use.
Even if you don't like this implementation, I had fun making it. :-)
You don't need to create a separate class module to change things in the form. Just add event-handling methods in the code behind for the form. (In the form editor, right click on the form and select "View code".)
You can use the MouseMove event for the button to change its colour, and then use the MouseMove event for the form to reset the button colour, like so:
Private Sub UserForm_MouseMove(ByVal Button As Integer, _
ByVal Shift As Integer, _
ByVal X As Single, _
ByVal Y As Single)
CommandButton1.BackColor = &H8000000F
End Sub
Private Sub CommandButton1_MouseMove(ByVal Button As Integer, _
ByVal Shift As Integer, _
ByVal X As Single, _
ByVal Y As Single)
CommandButton1.BackColor = vbYellow
End Sub

Drag&drop between listboxes which are classes in a collection

Being a self-taught VBA programmer I usually search the internet until I find a satisfactory solution for the problems (and the limitations of VBA) I stumble upon. I do not simply copy code of others, I really try to understand it as well, so I can learn from it. Long story short: I used code I found for dragging data from one listbox to another. Originally, the code (for 2 listboxes) was simply put in the form's code module but I wanted to use it in a class module so I don't have to copy/paste the same code for each and every d&d listbox I use on a form. The code I use:
(Code module of the form; just the listbox part)
Option Explicit
Private collection_ListBox As New collection
Private collection_ComboBox As New collection
Private collection_Textbox As New collection
Private Sub UserForm_Initialize()
Dim frm_control As Control
Set collection_ListBox = New collection
Set collection_ComboBox = New collection
Set collection_Textbox = New collection
For Each frm_control In Me.Controls
Select Case TypeName(frm_control)
Case "ListBox"
Dim obj As CfrwxDragDropList: Set obj = New CfrwxDragDropList
Set obj.FRWX_Control = frm_control: obj.Initialize
collection_ListBox.Add obj
Case "ComboBox"
Case "TextBox"
End Select
Next frm_control
'***TEMP for testing purposes***
ListBox1.List = Array("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7")
End Sub
(Code module of the class)
Option Explicit
Private WithEvents FRWX_DragDrop As msforms.ListBox
Private Item_Source As msforms.ListBox
Public Property Get FRWX_Control() As msforms.ListBox
Set FRWX_Control = FRWX_DragDrop
End Property
Public Property Set FRWX_Control(reg_Control As msforms.ListBox)
Set FRWX_DragDrop = reg_Control
End Property
Public Sub Initialize()
'Nothing here yet!
End Sub
Private Sub FRWX_DragDrop_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal X As Single, ByVal Y As Single)
If FRWX_Control.ListIndex < 0 Then Exit Sub
If Button = 1 Then
Call SetDraggedItem(FRWX_Control)
End If
End Sub
Private Sub FRWX_DragDrop_BeforeDragOver(ByVal Cancel As msforms.ReturnBoolean, _
ByVal Data As msforms.DataObject, ByVal X As Single, ByVal Y As Single, _
ByVal DragState As Long, ByVal Effect As msforms.ReturnEffect, _
ByVal Shift As Integer)
Cancel = True
Effect = fmDropEffectMove
End Sub
Private Sub FRWX_DragDrop_BeforeDropOrPaste(ByVal Cancel As msforms.ReturnBoolean, _
ByVal Action As msforms.fmAction, _
ByVal Data As msforms.DataObject, ByVal X As Single, ByVal Y As Single, _
ByVal Effect As msforms.ReturnEffect, ByVal Shift As Integer)
Cancel = True
Effect = fmDropEffectMove
Call AddDroppedItem(FRWX_Control, Data, Y)
Call DeleteDraggedItem(Item_Source)
End Sub
Private Sub SetDraggedItem(lb As msforms.ListBox)
Set Item_Source = lb
Dim dataObj As New DataObject
dataObj.SetText lb.Text
Call dataObj.StartDrag(fmDropEffectMove)
End Sub
Private Sub AddDroppedItem(lb As msforms.ListBox, dataObj As DataObject, Y As Single)
lb.AddItem dataObj.GetText, FixDropIndex(lb, Y)
End Sub
Private Sub DeleteDraggedItem(lb As msforms.ListBox)
Dim selIndex As Long
With lb
selIndex = .ListIndex
.Selected(selIndex) = False
.RemoveItem selIndex
End With
Set Item_Source = Nothing
End Sub
Private Function FixDropIndex(lb As msforms.ListBox, Y As Single) As Long
Dim toIndex As Long
With lb
toIndex = .TopIndex + Int(Y * 0.85 / .Font.Size)
If toIndex < 0 Then toIndex = 0
If toIndex >= .ListCount Then toIndex = .ListCount
End With
FixDropIndex = toIndex
End Function
So far so good; everything works fine except for one tiny little thing: I get an error on
Call DeleteDraggedItem(Item_Source)
in the sub FRWX_DragDrop_BeforeDropOrPaste. I know WHY I get this error: when I drop the DataObject in ListBox2, Item_Source in the corresponding instance of the class will be empty for it was filled in the ListBox1 instance of the class. So I need a way to let ListBox2 know the source of the dropped text. I can think of 2 ways of fixing this.
The first one sends shivers down my spine only thinking of it, for it feels almost like blasphemy: I could send it with the DataObject along with the text itself by 'expanding' lb.Text with "|" followed by lb.Name and split the string in the receiving instance. It will work, but I don't like this kind of solutions.
I could pass the name of the source ListBox to the parent (being the form itself) from instance 1, so instance 2 can ask for it there. I haven't tried that solution yet, but I'm sure I'll get it to work.
So now for my questions:
1. is solution 2 a/the right way to go?
2. are there other/better solutions I haven't thought of yet?
Any help will be highly appreciated!
***** UPDATE *****
As mentioned below, I found another (I think better) fix myself. The events are still triggered from the class instances for each listbox, but I used a separate, single instance of a class that performs the actual actions attached to them. Here's the updated code:
(Code module of the form; just the listbox part)
Option Explicit
Private collection_ListBox As New collection
Private collection_ComboBox As New collection
Private collection_Textbox As New collection
Private Sub UserForm_Initialize()
Dim frm_control As Control
Set collection_ListBox = New collection
Set collection_ComboBox = New collection
Set collection_Textbox = New collection
Dim handler As CfrwxDragDropList_EventHandler: Set handler = New CfrwxDragDropList_EventHandler
For Each frm_control In Me.Controls
Select Case TypeName(frm_control)
Case "ListBox"
Dim obj As CfrwxDragDropList: Set obj = New CfrwxDragDropList
Set obj.FRWX_Control = frm_control: obj.Initialize
Set obj.FRWX_EventHandler = handler
collection_ListBox.Add obj
Case "ComboBox"
Case "TextBox"
End Select
Next frm_control
'***TEMP for testing purposes***
ListBox1.List = Array("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7")
End Sub
(Code module of the listbox class "CfrwxDragDropList"
Option Explicit
Private WithEvents FRWX_DragDrop As MSForms.ListBox
Private FRWX_DragDrop_Handler As CfrwxDragDropList_EventHandler
Private Item_Source As MSForms.ListBox
Public Property Get FRWX_Control() As MSForms.ListBox
Set FRWX_Control = FRWX_DragDrop
End Property
Public Property Set FRWX_Control(reg_Control As MSForms.ListBox)
Set FRWX_DragDrop = reg_Control
End Property
Public Property Get FRWX_EventHandler() As CfrwxDragDropList_EventHandler
Set FRWX_EventHandler = FRWX_DragDrop_Handler
End Property
Public Property Set FRWX_EventHandler(handler As CfrwxDragDropList_EventHandler)
Set FRWX_DragDrop_Handler = handler
End Property
Public Sub Initialize()
'Nothing here yet!
End Sub
Private Sub FRWX_DragDrop_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal X As Single, ByVal Y As Single)
If FRWX_Control.ListIndex < 0 Then Exit Sub
If Button = 1 Then
Call FRWX_DragDrop_Handler.SetDraggedItem(FRWX_Control)
End If
End Sub
Private Sub FRWX_DragDrop_BeforeDragOver(ByVal Cancel As MSForms.ReturnBoolean, _
ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, _
ByVal DragState As Long, ByVal Effect As MSForms.ReturnEffect, _
ByVal Shift As Integer)
Cancel = True
Effect = fmDropEffectMove
End Sub
Private Sub FRWX_DragDrop_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, _
ByVal Action As MSForms.fmAction, _
ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, _
ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
Cancel = True
Effect = fmDropEffectMove
Call FRWX_DragDrop_Handler.AddDroppedItem(FRWX_Control, Data, Y)
Call FRWX_DragDrop_Handler.DeleteDraggedItem
End Sub
(Code module of the eventhandler class "CfrwxDragDropList_EventHandler"
Option Explicit
Private Item_Source As MSForms.ListBox
Public Sub SetDraggedItem(lb As MSForms.ListBox)
Set Item_Source = lb
Dim dataObj As New DataObject
dataObj.SetText lb.Text
Call dataObj.StartDrag(fmDropEffectMove)
End Sub
Public Sub AddDroppedItem(lb As MSForms.ListBox, dataObj As DataObject, Y As Single)
lb.AddItem dataObj.GetText, FixDropIndex(lb, Y)
End Sub
Public Sub DeleteDraggedItem()
Dim selIndex As Long
With Item_Source
selIndex = .ListIndex
.Selected(selIndex) = False
.RemoveItem selIndex
End With
Set Item_Source = Nothing
End Sub
Private Function FixDropIndex(lb As MSForms.ListBox, Y As Single) As Long
Dim toIndex As Long
With lb
toIndex = .TopIndex + Int(Y * 0.85 / .Font.Size)
If toIndex < 0 Then toIndex = 0
If toIndex >= .ListCount Then toIndex = .ListCount
End With
FixDropIndex = toIndex
End Function
That's it! It works between 2 listboxes, but if you want to use more it'll work as well. You can move items between listboxes, but also change the order of items within a listbox.

VBA - Apply same MouseMove code to all Labels (Event Handling Collections)

I have a few Labels on my worksheet, and each one has the following code to display on the Status Bar the Range they're currently at (as the mouse moves over them):
Private Sub Label1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
rng = ActiveSheet.Shapes("Label1").TopLeftCell.Address
Application.StatusBar = rng
End Sub
Is there any way I can apply this same code to ALL the labels instead of rewriting it over and over again?
I added a new class called LabelHandler:
Option Explicit
Public WithEvents lbl As msforms.Label
Private Sub lbl_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Dim rng As String
rng = ActiveSheet.Shapes(lbl.Name).TopLeftCell.Address
Application.StatusBar = rng
End Sub
In a New Module I added the following:
Public myLabels As Collection 'Of LabelHandler
Sub init()
Dim ws As Worksheet
Dim myLabel As LabelHandler
Set myLabels = New Collection
For Each l In ActiveSheet.OLEObjects
Set myLabel = New LabelHandler
Set myLabel.lbl = l.Object
myLabels.Add myLabel
Next
End Sub
Now when I run my cursor over the label, I get $F$11 in the status window
EDIT
You will want to edit your For Each loop to only add the label objects you want to the collection. Perhaps by their Name property
For Each l In ActiveSheet.OLEObjects
If Left(l.Name,5)="Label" Then
Set myLabel = New LabelHandler
Set myLabel.lbl = l.Object
myLabels.Add myLabel
End If
Next
Or for all Labels:
For Each l In ActiveSheet.OLEObjects
If l.progID = "Forms.Label.1" Then
Set myLabel = New LabelHandler
Set myLabel.lbl = l.Object
myLabels.Add myLabel
End If
Next

Moving single selected item in 1 of 3 listboxes via a class

Apologies for the awful title, its not the easiest thing to describe. I currently have a form with 3 listbox and adjacent to each 2 command buttons which allows the selected item in the listbox to move up or down. It all works fine but I would like to reduce the number of command buttons to a single pair and operate on the listbox with the currently selected item but I do not know if its possible. The code I have is:
Form declarations(3 instances for each pair of up/down buttons):
Private m_clsListMoveUpDown1 As CListbox_UpDown
Private m_clsListMoveUpDown2 As CListbox_UpDown
Private m_clsListMoveUpDown3 As CListbox_UpDown
and then instantiating the 3 instances of the class (within the form) via:
Set m_clsListMoveUpDown1 = New CListbox_UpDown
With m_clsListMoveUpDown1
Set .MoveDownButton = Me.Btn_MoveDown1
Set .MoveUpButton = Me.Btn_MoveUp1
Set .UpDownList = Me.LB_Sheet1
End With
Set m_clsListMoveUpDown2 = New CListbox_UpDown
With m_clsListMoveUpDown2
Set .MoveDownButton = Me.Btn_MoveDown2
Set .MoveUpButton = Me.Btn_MoveUp2
Set .UpDownList = Me.LB_Sheet2
End With
Set m_clsListMoveUpDown3 = New CListbox_UpDown
With m_clsListMoveUpDown3
Set .MoveDownButton = Me.Btn_MoveDown3
Set .MoveUpButton = Me.Btn_MoveUp3
Set .UpDownList = Me.LB_Sheet3
End With
Finally, some class declarations:
Public WithEvents MoveUpButton As MSForms.CommandButton
Public WithEvents MoveDownButton As MSForms.CommandButton
Public UpDownList As MSForms.ListBox
I haven't included either of the 2No. subroutines (moving the selected item up or down) within the class but can do if it helps. In a nutshell they contain:
With Me.UpDownList
'lines of code using arrays to move items up or down
End With
I completely understand the reason why a single pair of up/down buttons currently only operates on the listbox specified by e.g. Set .UpDownList = Me.LB_Sheet1 but I do not know how to associate the other 2 listboxes so that if either one has a selected item, have the buttons operate on that listbox.
I attempted to use the Set .UpDownList = Me.LB_Sheet1 or Me.LB_Sheet2 or Me.LB_Sheet2 but the gives a type mismatch error and I'm not sure what else to try.
I used a class like so
Private frmParent As MSForms.UserForm
Private lstListBoxUnderControl As MSForms.ListBox
Public WithEvents UP As MSForms.CommandButton
Public WithEvents DOWN As MSForms.CommandButton
Public Property Set PARENT_FORM(frm As MSForms.UserForm)
Set frmParent = frm
End Property
Public Property Set LISTBOX_CONTROLLING(lb As MSForms.ListBox)
Set lstListBoxUnderControl = lb
End Property
Private Sub Class_Initialize()
'
End Sub
Private Sub DOWN_Click()
' Down Code
lstListBoxUnderControl.BackColor = vbRed
End Sub
Private Sub UP_Click()
' Up Code
lstListBoxUnderControl.BackColor = vbGreen
End Sub
Setting it up in the form like so
Dim c As New clsUpdateController
Private Sub ListBox1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Set c.LISTBOX_CONTROLLING = Me.ActiveControl
End Sub
Private Sub ListBox2_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Set c.LISTBOX_CONTROLLING = Me.ActiveControl
End Sub
Private Sub ListBox3_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Set c.LISTBOX_CONTROLLING = Me.ActiveControl
End Sub
Private Sub ListBox4_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Set c.LISTBOX_CONTROLLING = Me.ActiveControl
End Sub
Private Sub ListBox5_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Set c.LISTBOX_CONTROLLING = Me.ActiveControl
End Sub
Private Sub UserForm_Initialize()
Set c.PARENT_FORM = Me
Set c.DOWN = Me.cmdDown
Set c.UP = Me.cmdUP
Me.ListBox1.AddItem "test"
Me.ListBox2.AddItem "test"
Me.ListBox3.AddItem "test"
Me.ListBox4.AddItem "test"
End Sub