Listbox Selected property causes problems - excel

I have a listbox in a Diagram, when calling the function "drawDiagram" I want to get the selected Items of the listbox. Here is my code to do that:
Function DrawDiagram()
Dim x As Integer
Dim diaLst As ListBox
Set diaLst = ActiveSheet.ListBoxes("DiaList")
' find selected trends in List Box
For x = 0 To diaLst.ListCount - 1
If diaLst.Selected(x) = True Then
MsgBox x
End If
Next x
End Function
diaLst.ListCount correctly returns the number of Items in the list. But diaLst.Selected(x) does not work at all.
The Error message is:
German: "Die Selected-Eigenschaft des ListBox-Objektes kann nicht zugeordent werden"
English: "The Selected Property of the ListBox Object cannot be assigned" (or similar)
Does anyone know, what I did wrong?
thanks
natasia

By the way, this is the code I used to generate the list box in a chart sheet, in a separate function. At the moment when a button is clicked, the DrawDiagram function is called. The aim of the "DrawDiagram" function is to plot the selected items of the listbox in the diagram.
Set diaLst = ActiveSheet.ListBoxes.Add(ActiveChart.ChartArea.Width - 110, 5, 105, 150)
With diaLst
.Name = "DiaList"
.PrintObject = False
.MultiSelect = xlSimple
i = 2
While wTD.Cells(rowVarNames, i) <> ""
.AddItem wTD.Cells(rowVarNames, i)
i = i + 1
Wend
.Selected(3) = True
End With

first off, you must be dealing with a "Form" control (not an "ActiveX" one) otherwise you couldn't get it via .ListBoxes property of Worksheet class
I tested it in my environment (W7-Pro and Excel 2013) and found that (quite strangely to me) the Selected() property array is 1-based.
This remained even with Option Base 0 at the beginning of the module
Make sure Microsoft Forms 2.0 Object Library reference is added to your project
Function DrawDiagram()
Dim x As Long
Dim diaLst As MSForms.ListBox
Set diaLst = ActiveSheet.ListBoxes("DiaList")
' find selected trends in List Box
For x = 1 To diaLst.ListCount
If diaLst.Selected(x) = True Then
MsgBox x
End If
Next x
End Function

use Sheets("Sheet1").Shapes("List Box 1").OLEFormat.Object instead

I stumbled upon the same problem. The solution turned out to be simple, just had to tweak the code a litte bit and play around with the ListBox properites:
Function GetSelectedRowsFromListBox(lstbox As ListBox) As Collection
Create the collection
Dim coll As New Collection
Dim lst_cnt As Variant
lst_cnt = lstbox.ListCount
Dim arr_selectedVal As Variant
arr_selectedVal = lstbox.Selected
' Read through each item in the listbox
Dim i As Long
For i = 1 To lstbox.ListCount
' Check if item at position i is selected
If arr_selectedVal(i) Then
coll.Add i
End If
Next i
Set GetSelectedRowsFromListBox = coll
End Function
.Selected property returns a 1-based array with True/False values coresponding to rows in your multiple choice Form Control ListBox.
From that you can get the list of each value.
This solution is an expanded version of what is mentioned here, however this also complies with Form Control ListBox, no just ActiveX ListBox (which are 2 same but different things ;) ):
https://excelmacromastery.com/vba-listbox/
Hope that helps in the future!

Related

Changing Combobox variable on "For Loop"

im trying to optimize my code by adding item on multiples comboboxes depending on a previoues variable.
Quick explanation:
I will ask the user for a number (1-5) and after i receive this variable i want to set how many itens will be add on more than one comboboxes, i've tried two different ways, none has worked.
Dim CB as Combobox
Variable_From_User = TextBox1.value
For I = Variable_From_User to 5
*CB = "ComboBox" & I*
CB.AddItem (Value_From_Sheet)
Next
It keeps returning the error:
Object variable or With block variable not set
Second Way:
Variable = 2
For n = 0 To 5
With ComboBox & Variable
.AddItem (n)
End With
Next
(Note: I assume that you are talking about a userform)
A combobox is a control on a Userform. You can access a control within the code of the Userform by its name, eg Me.Combobox1 (Me represents the form itself).
What doesn't work is to write ComboBox & Variable. This is a string concatenation and results in a string. You can't expect that VBA will magically figure out that this string is meant to be a variable (a member of the form class, to be precise) and use that.
If you know the the name of a control, you can access it via the Controls-Collection of the form. Note that you need to use Set as you are assigning an object.
Dim CB as Combobox
Variable_From_User = TextBox1.value
For I = Variable_From_User to 5
Set CB = Me.Controls("ComboBox" & I)
CB.AddItem Value_From_Sheet ' <-- Don't use parentheses here
Next

How to reduce IF statements for multiple option buttons

I have a UserForm which lets the user input a count of product defects into a textbox. This is done as part of monthly reporting, so I have option buttons to select the Month (12 options). There are also option buttons for selecting Product Type. The code basically evaluates what options are selected and copies the textbox values (defect counts) into specific cells in another spreadsheet (for reporting purposes). Not all TextBoxes are required to have values entered by the User.
You can check out a screenshot of the UserForm https://imgur.com/a/6QefjCp.
As you can see from the code, I'm using a bunch of IF statements to perform the decision making - I would like to reduce the length of this code, but I don't know where to start.
I have never really used VBA prior to this, so haven't really attempted a solution. In its current state, the code works flawlessly. Just looking to reduce and clean-up.
Private Sub OKButton_Click() 'This is the button the user clicks to finalize
'the data entry
'Calling the Product type modules
Call Product1Module
Call Product2Module
Call Product3Module
End Sub
Sub Product1Module() 'All product modules will look almost exactly like this
'except the cell ranges will be different
If UserForm.Product1Button.Value = True Then 'Checking for Product1 Option button
If UserForm.JANButton.Value = True Then
'Record value to textbox if JAN is selected
Sheets("Sheet1").Range("B1107").Value = UserForm.TextBox1.Value
Sheets("Sheet1").Range("B1115").Value = UserForm.TextBox2.Value
Sheets("Sheet1").Range("B1108").Value = UserForm.TextBox3.Value
Sheets("Sheet1").Range("B1116").Value = UserForm.TextBox4.Value
Sheets("Sheet1").Range("B1109").Value = UserForm.TextBox5.Value
Sheets("Sheet1").Range("B1117").Value = UserForm.TextBox6.Value
Sheets("Sheet1").Range("B1111").Value = UserForm.TextBox7.Value
ElseIf UserForm.FEBButton.Value = True Then
Sheets("Sheet1").Range("C1107").Value = UserForm.TextBox1.Value
Sheets("Sheet1").Range("C1115").Value = UserForm.TextBox2.Value
Sheets("Sheet1").Range("C1108").Value = UserForm.TextBox3.Value
Sheets("Sheet1").Range("C1116").Value = UserForm.TextBox4.Value
Sheets("Sheet1").Range("C1109").Value = UserForm.TextBox5.Value
Sheets("Sheet1").Range("C1117").Value = UserForm.TextBox6.Value
Sheets("Sheet1").Range("C1111").Value = UserForm.TextBox7.Value
...
End If
End If
End Sub
Give each of your option buttons a Tag property value - e.g. make JANButton.Tag be "B", then make FeBButton.Tag be "C", etc.
Then you can do this:
Dim targetColumn As String
Select Case True
Case UserForm.JANButton
targetColumn = UserForm.JANButton.Tag
Case UserForm.FEBButton
targetColumn = UserForm.FEBButton.Tag
'...
End Select
With Worksheets("Sheet1") '<~ which workbook is that in? whatever is active?
.Range(targetColumn & "1107").Value = UserForm.TextBox1.Value
.Range(targetColumn & "1115").Value = UserForm.TextBox2.Value
'...
End With

Searching in listview while typing in textbox using vba

I used OnKeyUp so while user is typing, it is searching in the list view. I am getting an error with my code.
"Wrong number of arguments or invalid property assignment"
Here is my code below:
Private Sub txtEmailGenSearch_KeyUp(ByVal KeyCode As
MSForms.ReturnInteger, ByVal Shift As Integer)
Dim strText As String
Dim i As Long
strText = LCase(txtSearch.value)
With MainForm.lstMailGen
For i = 0 To .ListItems.count - 1
If LCase(Left(.ListItems(i, 0), Len(strText))) = strText Then
Exit For
Next i
If i = .ListItems.count Then
' No matching item was found, select nothing
.ListIndex = -1
Else
' A match was found, select it
.ListIndex = i
End If
End With
End Sub
A ListView is quite different from a ListBox. Each row in a ListView is a ListItem. If the ListView has multiple columns then each ListItem will contain ListSubItems. This applies to a Microsoft Windows Common Controls 6.0 Listview, 5.0 works a little different. ListViews do not return a 2D array like a ListBox does have have a ListIndex property.
Recommended Reading: Excel VBA ListView Control Examples
Use ListItem.Find() to locate a matching ListItem
With MainForm.lstMailGen
Dim item As ListItem
Set item = .FindItem(sz:=txtSearch.value, fPartial:=lvwPartial)
If Not item Is Nothing Then
item.Selected = True
End If
End With
In for the ListItem to be hightlighted make sure that HideSelection = False
MainForm.lstMailGen.HideSelection = False
The Listitems first index is 1 not 0.
For i = 1 To .ListItems.Count
If LCase(Left(.ListItems(i), Len(strText))) = strText Then
Exit For
Next i
If the last item contained the string than If i = .ListItems.count Then would skip the selection. If i > .ListItems.count Then is the right way to do this. If the For loop completes then i will be incremented an extra time. In the above case i would = .ListItems.Count + 1` if the loop completed.

Spinbar / Input Button Visibility

So I've been working on a spreadsheet that I'm going to use as a template for several more spreadsheets and I've gotten most of the template finished but I would like to add a feature involving the spinbar.
Currently I have 100 input buttons displayed and I know that I will not need 100 buttons for all the possible uses of the template, I just included 100 as a max.
I am looking to add a 1 - 100 spinbar so that it will automatically show/hide buttons depending on the number associated with the spinbar.
I should have no issues figuring out how to hide the buttons or show the buttons, but I cannot figure out the proper code to have buttons visible between 1 - 100.
Sub LocNum ()
Dim i As Integer
Dim n As Integer
n = Worksheets(1).Cell
For i = 1 To n
That's about as far as I can get, so if n is equal to 37 it should only have 37 buttons visible.
I'm getting my code from something I typed up previous before I took a break from it for quite awhile, here is the code.
Sub Populate()
Dim t As Integer
Dim i As Integer
Dim a As String
t = ActiveWorkbook.Sheets.Count - 1
i = 0
For i = 2 To t
a = i - 1
If (ActiveSheet.Shapes("" + "btn.index" & i).Visible = True) Then
ActiveSheet.Shapes("" + "btn.index" & i).Select
Selection.OnAction = "" + "Location" & a + ""
Selection.Characters.Text = ActiveWorkbook.Worksheets(i).Name
Else
Exit Sub
End If
Next i
End Sub
Any help would be appreciated.
Not entirely sure your workflow, but this can help you show/hide the buttons either based on the index (I don't recommend) or the name of the button. You just call this Sub providing the number of buttons to show, rest (index/name higher than the number) will be hidden.
I will let you play with the OnAction.
Option Explicit
Sub ShowButtonsUpTo(ByVal ButtonCount As Long)
Dim oButton As Button ' or Object
For Each oButton In Worksheets(1).Buttons
With oButton
' Based on Index (not recommend):
.Visible = (.Index <= ButtonCount)
' Based on Name (button name):
If InStr(1, .Name, "btn.index", vbTextCompare) = 1 Then
.Visible = (CLng(Replace(.Name, "btn.index", "")) <= ButtonCount)
End If
End With
Next oButton
End Sub

How to target a specific shape in excel sheet

Program: Excel 2016.
I have a sheet with a lot of shapes. Each of them has its own specific name and most of them are label. I want to change their caption property, but i can't find a way but calling them one by one like this:
LblLabel_1.Caption = ...
LblLabel_2.Caption = ...
LblLabel_3.Caption = ...
Instead i was looking for something like this:
For BytCounter01 = 1 to 255
Shapes("LblLabel_" & BytCounter01).Caption = ...
Next
This one will result in error 438, basically saying Caption is not avaiable for this object. It still target the object, since this code:
Debug.print Shapes("LblLabel_" & BytCounter01).Name
will return me its name.
Looking for a solution:
-i've tried Controls("LblLabel_" & BytCounter01) instead of Shapes("LblLabel_" & BytCounter01) but it won't work since Controls is only for userforms, not for sheets;
-i've tried Shapes("LblLabel_" & BytCounter01).TextFrame.Characters.Text but it returns error 438 again;
-since the label is a part of a group, i've tried both
Shapes("ShpGroupOfShapes01").GroupItems(ShpShapeIndex).Caption
and
Shapes("ShpGroupOfShapes01").GroupItems(ShpShapeIndex).TextFrame.Characters.Text
but got 438 again.
Is there really no way to easily target a specific label on a sheet and change his caption?
Thank you.
EDIT: thanks to Excelosaurus, the problem is solved. Since my labels are ActiveX Controls i have to use something like this:
For BytCounter01 = 1 to 255
Shapes("LblLabel_" & BytCounter01)OLEFormat.Object.Object.Capti‌​on = ...
Next
You can check his response and comments for more details. Thanks again Excelosaurus!
To change the textual content of a shape, use .TextFrame2.TextRange.Text as shown below:
shtShapes.Shapes(sShapeName).TextFrame2.TextRange.Text = sShapeCaption
where shtShapes is the name of your worksheet's object as seen from the Visual Basic Editor in the Project Explorer,
sShapeName is a string variable containing the name of the target shape, and
sShapeCaptionis a string variable containing the desired caption.
A code example follows. I've thrown in a function to check for a shape's existence on a worksheet, by name.
Option Explicit
Public Sub SetLabelCaptions()
Dim bCounter As Byte
Dim sShapeName As String
Dim sShapeCaption As String
For bCounter = 1 To 255
sShapeName = "LblLabel_" & CStr(bCounter)
If ShapeExists(shtMyShapes, sShapeName) Then
sShapeCaption = "Hello World " & CStr(bCounter)
shtMyShapes.Shapes(sShapeName).TextFrame2.TextRange.Text = sShapeCaption
Else
Exit For
End If
Next
End Sub
Public Function ShapeExists(ByVal pshtHost As Excel.Worksheet, ByVal psShapeName As String) As Boolean
Dim boolResult As Boolean
Dim shpTest As Excel.Shape
On Error Resume Next
Set shpTest = pshtHost.Shapes(psShapeName)
boolResult = (Not shpTest Is Nothing)
Set shpTest = Nothing
ShapeExists = boolResult
End Function
The result should look like this:
You can't assign a Caption to a Shape. (Shapes don't have Captions). One approach is to loop over the Shapes and build a little table to tell you what to loop over next:
Sub WhatDoIHave()
Dim kolumn As String, s As Shape
Dim i As Long, r As Range
kolumn = "Z"
i = 1
For Each s In ActiveSheet.Shapes
Set r = Cells(i, kolumn)
r.Value = i
r.Offset(, 1).Value = s.Name
r.Offset(, 2).Value = s.Type
r.Offset(, 3).Value = s.TopLeftCell.Address(0, 0)
i = i + 1
Next s
End Sub
Which for my sample produced:
Seeing that I have both Forms and ActiveX (OLE) Controls, I know what to loop over next. I then refer to the Control by number and assign a Caption if appropriate.

Resources