Allow null input when retrieving data from multiselect listbox - excel

I'm trying to create a simple worksheet-based form that will pull data from the selections into another sheet on the Excel workbook. This is my first time messing with Visual Basic and ActiveX controls and I don't have much programming experience, but with a lot of Googling I've managed to muddle through some so far.
The part in question: I have a couple of multiselect boxes that, with the click of a button, push the data into the spreadsheet, using this code:
Private Sub CommandButton1_Click()
Dim I As Long
Range("A10").Select
Range(Selection, Selection.End(xlToRight)).ClearContents
With Me.ListBox1
For I = 0 To .ListCount - 1
If .Selected(I) Then
Flg= True
txt = txt & "," & .List(I)
End If
Next
End With
If Flg Then
With Sheets("Sheet1")
.Range("A10").Value = Mid$(txt, 2)
End With
End If
txt=""
'Repeat for each listbox'
End Sub
As long as the user has selected at least one item in each listbox, this works fine to pull the data, and from there I can do what I need. But I don't want to require the user to click in each box (that is, I suppose I could force them to click a null selection if they don't want to select something in that box, but it would be easier to just have them not select anything at all). But (understandably) when nothing is selected in a given box, the code I pasted above returns run-time error 1004: No data was selected to parse.
How can I permit the user to make no selection in a box, and have the code just leave the associated cell blank when the data are retrieved?

Wow, after a couple of days of looking I finally found it. This is the code that worked for me:
Private Sub ListBox1_LostFocus()
Dim listItems As String, i As Long
With ListBox1
For i = 0 To .ListCount - 1
If .Selected(i) Then listItems = listItems & .List(i) & ", "
Next i
End With
If Len(listItems) > 0 Then
Range("A2") = Left(listItems, Len(listItems) - 2)
Else
Range("A2") = ""
End If
End Sub
And it came from this page: https://www.mrexcel.com/forum/excel-questions/584437-write-selections-excel-listbox-cell.html ...thanks to 'Marcelo Branco' for providing that answer 7 years ago!
EDIT - This really answers a separate question that I had (about retrieving the data automatically), but it seems to also work for the big question here, since when nothing is selected, the target cell is blank.

Related

Printing from dynamic Excel list box

I have a workbook that is a 'quick print' sheet for my workplace.
I am not very skilled with VBA, but I have found various bits from web searches that have given me mostly desired results.
This is the desired look of the sheet:
The column C and D is a List Box with the VBA code:
Private Sub Worksheet_Activate()
Dim Sh
Me.ListBoxSh.Clear
For Each Sh In ThisWorkbook.Sheets
Me.ListBoxSh.AddItem Sh.Name
Next Sh
End Sub
The print icon in D2 is linked to macro:
Sub Print_Sheets()
Dim i As Long, c As Long
Dim SheetArray() As String
With ActiveSheet.ListBoxSh
For i = 0 To .ListCount - 1
If .Selected(i) Then
ReDim Preserve SheetArray(c)
SheetArray(c) = .List(i)
c = c + 1
End If
Next i
Application.Dialogs(xlDialogPrinterSetup).Show
Worksheets(SheetArray()).PrintOut Copies:=1
End With
End Sub
and finally the sheet has following in ThisWorkbook in order to refresh the List Box and put the user on the correct page:
Private Sub Workbook_Open()
Sheets(2).Select
Sheets(1).Select
End Sub
The final bit of VBA seems to work as intended, but I included it anyway in case it could interfere with something (I don't think it can, but just to be sure).
The List Box populates as intended, but I can't get it to stay the width of the columns C:D, and the height of the populated cells in B, every time the workbook is opened the box will increase in size both to the right and down.
The print button works mostly as intended; when clicked it will prompt with available printers, and then OK to print, but cancelling still causes the document to print. It will also allow the printing of the "Please Select..." page - the name of the sheet this form is on - which I have tried to stop from happening but can't get it to work.
On the point of having the list box resize correctly, I have followed this answer but I can't figure out how to keep the size as the range, rather than an integer.
Edit: I have now figured out that I can use Me.ListBoxSh.Width = Range("C:D").Width to set the width the same as the desired columns, as well as Me.ListBoxSh.Height = Range("3:7").Height for the height in the image shown. However, I will be adding to this list and am not sure how to have the VBA code work as "Start in row 3 and continue until an unpopulated row".
On not being able to print the "Please Select..." sheet, I followed this guide and it didn't seem to do anything at all. I had changed the WsName = "Sheet1" line to read WsName = "Please Select..." also.
Any help would be appreciated.

Clearing a list box and any selected items in list

I have an Excel VBA application that goes through a sheet which contains product orders on a sheet in a workbook and searches the worksheet for orders that match various criteria which is populates in a search worksheet. The contents from this worksheet are then displayed in list box. There are several user forms that allow the user to select an order and then manipulate the order. After doing this the order manipulated may not meet the search criteria so I want to clear the list box contents and the selected row in the list box. I have tried numerous things but nothing seems to work. My latest is something list this:
Private Sub ClearListBox()
UserForm5.lstOpenO.ListIndex = -1
UserForm5.lstOpenO.RowSource = ""
End Sub
But I have tried setting the UserForm5.lstOpenO.Selected to false for all the rows. I have tried clearing the search worksheet and then displaying that which should only show the headers on the columns but the highlight in the selected row remains.
Any help would be greatly appreciated
Bruce
First of all you should not use the default instance of the userform in your code. This will lead to ambigous behaviour
I'd suggest
Private Sub ClearSelectionInListBox()
Dim varItm as variant
With lstOpen0
varItm = .MultiSelect
.MultiSelect = 0
.MultiSelect = 1
.MultiSelect = varItm
End With
End Sub
This will clear the selection within the listbox.
It is not clear if you really want to clear the contents. Because if you want then it does not make sense to think about clearing the selection.
If you want to clear the listbox then it is not neccessary to clear the selection first.
Private ClearListBox()
With lstOpen0
.RowSource = ""
.Clear
End With
End Sub
But after that you need to fill the listbox again.
Further reading
VBA userform
Userform.Show
ListBox

Excel Combo Box Refresh Dropdown?

Is there a way to refresh a combobox?
I have the following VBA code. The dropdown is populated, until the If statement where the list is cleared and populated with the matched items.
At this point, the dropdown list only shows a single item with a scroll bar. But If I close the pulldown and reopen, it's fully populated correctly.
Private Sub ComboBox_SiteName_Change()
ComboBox_SiteName.DropDown
Dim v As Variant, i As Long
With Me.ComboBox_SiteName
.Value = UCase(.Value)
If .Value <> "" And .ListIndex = -1 Then
v = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
.Clear ' Clear all items
' Repopulate with matched items
For i = LBound(v, 1) To UBound(v, 1)
If LCase(v(i, 1)) Like "*" & LCase(.Value) & "*" Then
.AddItem v(i, 1)
End If
Next i
Else
' Repopulate with all items
.List = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
End If
End With
End Sub
The ComboBox_Change function gets called as the user types in the combo box.. the dropdown box turns from a list into a single line with Up/Down arrows after the Clear and Repopulate matched items..
but if I close the dropdown portion and reopen it lists all the items without Up/Down arrows.
The .ListRows value = 8 by the way.
I would like a way for the dropdown potion to either close and reopen.. or a VBA function to refresh the dropdown portion, Without external buttons or controls Please
Getting the list to ONLY show values that matched the text typed by the user so far, was a nightmare. Below is what I wrote which works (but took me a while!)
Note that the MacthEntry Property of the combo box MUST be set to "2 - frmMatchEntryNone" for the code to work. (Other values cause the combo box .value property store the text of the first value that matches what the user typed, and the code relies on it storing what they typed.)
Also note, the trick to get around the behaviour you observed, ie the combo boxes list of values not being sized correctly, was to use the code lines:
LastActiveCell.Activate
ComboBox_SiteName.Activate
Also, the code will pick up any items on the list that have the letters typed by the user ANYWHERE in their text.
Anyway, here's my code:
Private Sub ComboBox_SiteName_GotFocus()
' When it first gets the focus ALWAYS refresh the list
' taking into acocunt what has been typed so far by the user
RePopulateList FilterString:=Me.ComboBox_SiteName.Value
Me.ComboBox_SiteName.DropDown
End Sub
' #4 Private Sub ComboBox_SiteName_Change()
Private Sub ComboBox_SiteName_Enter()
Dim LastActiveCell As Range
On Error GoTo err_Handler
Set LastActiveCell = ActiveCell
Application.ScreenUpdating = False
With Me.ComboBox_SiteName
If .Value = "" Then
' Used cleared the combo
' Repopulate will all values
RePopulateList
.DropDown
Else
' #4 reducdant
' LastActiveCell.Select
' .Activate
' ===========================================
' #4 new code
' CheckBox1 is another control on the form
' which can receive the focus and loose it without event firing
CheckBox1.SetFocus
' This will trigger the GotFocus event handler
' which will do a refresnh of the list
.SetFocus
' ===========================================
End If
End With
Application.ScreenUpdating = True
Exit Sub
err_Handler:
Application.ScreenUpdating = True
Err.Raise Err.Number, "", Err.Description
Exit Sub
Resume
End Sub
Private Sub RePopulateList(Optional FilterString As String = "")
Dim i As Long
Dim ValidValues() As Variant
' #2 range now refers to just the data cells
ValidValues = Worksheets("Address").Range("Table5[SITE NAME]").Value
With Me.ComboBox_SiteName
If FilterString = "" Then
' All all values
.List = ValidValues
Else
' #2: .List cannot be set to have no items.
' so remove all but one
.List = Array("Dummy Value")
' Only add values that match the FilterString parameter
For i = LBound(ValidValues, 1) To UBound(ValidValues, 1)
If LCase(ValidValues(i, 1)) Like "*" & LCase(FilterString) & "*" Then
.AddItem ValidValues(i, 1)
End If
Next i
' #2 add this line to remove the dummy item
.RemoveItem (0)
End If
End With
End Sub
Private Sub ComboBox_SiteName_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Application.ScreenUpdating = False
End Sub
======================================================================
You could: Replace all your code with this which should give acceptable functionality (as long a the data source is in alpha order), and it's easy! However, it doesn't quite do what you wanted.
Private Sub ComboBox_SiteName_GotFocus()
With Me.ComboBox_SiteName
.List = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
End With
ComboBox_SiteName.DropDown
End Sub
Combo boxes can be set up to "filter as the user types" - so long as the data is in alphabetical order.
======================================================================
Note that in your code the following two lines cause the ComboBox_SiteName_Change event to start again. I suspect you need to add break points and debug you code more.
.Value = UCase(.Value)
.Clear ' Clear all items
Anyway, I hope this is job done.
this will be my first bounty if I get it, so please let me know if you need any more help. (I think it may be worth more than 50 points)
Harvey
================================================
PART 2:
To answer you comment issues:
(See the #2 tag in my code above)
To refer to a table column's data, excluding the header use:
=Table5[SITE NAME]
(This will be autogenerated when entering a formula if you click and drag over the data cells in a column).
The code has been altered accordlingly.
I used excel 2013 and 2010 and found that the .Activate event works in both.
See #3 for a minor change.
Please recopy all the code.
note that I introduced code to try and stop flickering using Application.ScreenUpdating, but it didn;t have any effect - I don't know why. I've left the code in so you can do further experiments should you need to.
NOTE the new procedure ComboBox_SiteName_KeyDown
================================================
PART 3:
To answer you comment issues:
It's a combo on a form ! - so make the change tagged with #4 above.
Harvey
Solved!
https://trumpexcel.com/excel-drop-down-list-with-search-suggestions/
You can do what is in the link with some modifications:
"ListFillRange" in combobox properties should be the last column (the one that is changing). If it is a userform the range will go under "RowSource".
And add this code:
Private Sub ComboBox1_Change()
Sheets("Where the data is").Range("B3") = Me.ComboBox1.Value
End Sub
Try changing the command from Change to DropButtonClick
This refreshes the list on a click of the drop down

Excel VBA UserForm Vlookup error

Alright, so here’s the code for my UserForm:
Private Sub CancelButton_Click()
Unload Me
End Sub
Private Sub ClearButton_Click()
Call InventoryEntryBox_Initialize
End Sub
Private Sub SubmitButton_Click()
Dim emptyRow As Long
'Make Inventory Test sheet active
Worksheets("InventoryTest").Activate
'Transfer Information
Worksheets("InventoryTest").Cells(Rows.Count, "B").End(xlUp).Offset(1, 0).Value = PartNumberComboBox.List
Worksheets("InventoryTest").Cells(Rows.Count, "C").End(xlUp).Offset(1, 0).Value = LocationTextBox.Value
Worksheets("InventoryTest").Cells(Rows.Count, "D").End(xlUp).Offset(1, 0).Value = QuantityTextBox.Value
Worksheets("InventoryTest").Cells(Rows.Count, "F").End(xlUp).Offset(1, 0).Value = CommentsTextBox.Value
Call InventoryEntryBox_Initialize
End Sub
Private Sub InventoryEntryBox_Initialize()
'Fill PartNumberComboBox
PartNumberComboBox.List = ActiveWorkbook.Sheets("Test2").Range("B2:B43").Value
'Empty Location Text Box
LocationTextBox.Value = ""
'Empty Quantity Text Box
QuantityTextBox.Value = ""
'Empty Comments Text Box
CommentsTextBox.Value = ""
'Unit Of Measure auto-fill box
'Description auto-fill box
DescriptionFormula.Value = Application.WorksheetFunction.VLookup(PartNumberComboBox.List, ActiveWorkbook.Sheets("Test2").Range("B2:D43"), 3, False)
'Set focus on Empty Part Number text box
PartNumberTextBox.SetFocus
End Sub
Now, the idea with this code is to have User Form so someone can fill it out (the PartNumberComboBox, LocationTextBox, QuantityTextBox, and CommentsTextBox) in order to catalogue inventory on what items are in what places and in what quantity. When someone fills out an item number in the PartNumberComboBox, the DescriptionFormula will auto-fill with data from a list (Noted as PartDescription, which includes D2:D43 in the sheet Test2).
My problem, however, is two-fold: The DescriptionFormula.Value box does not auto-fill with data when someone enters in a part number in the PartNumberComboBox, and when I try to hit the “submit” button to confirm the data entered in the form and put it in the areas specified in the code, I get a dialogue box that pops up and says “Run-time error 70: Permission Denied”, then the "PartNumberComboBox.List = ActiveWorkbook.Sheets("Test2").Range("B2:B43").Value" is highlighted when I go to debug.
I’m not sure if it’s a problem with my code, or if it’s a limitation of Excel or Vlookup based on what I’m doing… or if it’s something else. Any kind of help anyone could offer would be a blessing at this point.
I've actually solved my own question:
So it turns out that I needed to write a new sub for this particular equation, not embed it in my Initialize sub. Here's what I wrote to get it to work:
Private Sub PartNumberComboBox_Change()
Me.UnitOfMeasureFormula.Value = Application.WorksheetFunction.VLookup(Me.PartNumberComboBox.Value, Sheets("sheet2").Range("a2:c43"), 3, False)
Me.DescriptionFormula.Value = Application.WorksheetFunction.VLookup(Me.PartNumberComboBox.Value, Sheets("sheet2").Range("a2:c43"), 2, False)
End Sub
while changing my "Description auto-fill box" to this:
'Empty Description label
DescriptionFormula.Value = ""
What this does is empty out the box that the auto-fill will go in on startup of the Userform, then using a _Change sub with the ComboBox that the formula is referencing so it alters the DescriptionForumula based on what the ComboBox says with a simple VLookup formula. Now it's working smoothly and I'm back on track!

VBA Get Combobox to 'suggest' an option

I am relatively new to VBA and I am trying to solve a problem working with a userform in Excel 2010.
I am writing a pseudo spell checker that validates words against a list. The unknown word is presented in a text box and the list of allowed words is in a combo box below. I would like the combo box to present a 'suggestion' based on the unknown word. i.e. the unknown word is "Excavation" and one of the allowed words in the combo box is "Excavate". I would like the combo box to suggest the term "Excavate". My problem is that autocomplete doesn't offer a suggestion because the unknown word is longer than the allowed word.
My thought on solving the problem is to do the following:
- Parse the unknown word into a character array.
- Add the characters one at a time to the combo box text property and allow autocomplete to run.
- As soon as autocomplete stops working, remove one character and insert the word that autocomplete suggests.
My problem is I cannot find anything to tell me once auto complete has stopped working.
Any thoughts, suggestions, or alternate approaches welcome.
Thanks in advance,
Will
You may want to change 2 properties for the ComboBox to force an entry from a list is selected:
MatchEntry --> 1 - fmMatchEntryComplete
MatchRequired --> True
So when a user try to select a word outside of the list, they get a "Invalid property value.":
This code assumes a TextBox and ComboBox as you described, still with their default names. In addition there's a button, which when pressed prompts you for a word. This word is then pasted into the textbox, which I think duplicates the behavior you're coding for:
Private Sub UserForm_Activate()
With Me.ComboBox1
.AddItem "bat"
.AddItem "battleship"
.AddItem "battle"
.AddItem "batty"
.AddItem "bathhouse"
End With
End Sub
Private Sub CommandButton1_Click()
Me.TextBox1 = Application.InputBox("Word", , , , , , , 2)
End Sub
Private Sub TextBox1_Change()
Dim WordToMatch As String
Dim AvailableWords() As String
Dim i As Long
Dim MatchedWordPosition As Long
Dim LongestWordLength As Long
With Me.ComboBox1
.ListIndex = -1
WordToMatch = Me.TextBox1.Text
ReDim AvailableWords(0 To .ListCount - 1)
For i = LBound(AvailableWords) To UBound(AvailableWords)
AvailableWords(i) = .List(i)
LongestWordLength = WorksheetFunction.Max(Len(.List(i)), LongestWordLength)
Next i
For i = 0 To Len(WordToMatch) - 1
On Error Resume Next
MatchedWordPosition = WorksheetFunction.Match(WordToMatch & WorksheetFunction.Rept("?", (LongestWordLength - Len(WordToMatch)) - i), AvailableWords(), 0)
If MatchedWordPosition > 0 Then
Exit For
End If
Next i
If MatchedWordPosition > 0 Then
.ListIndex = MatchedWordPosition - 1
End If
End With
End Sub
I imagine there are a few ways to skin this cat, but this is my best effort.

Resources