Populating Multi-Column ListBox/ComboBox

In a previous post, I discussed populating one-column ActiveX controls with the RowSource property and the AddItem method. This post will discuss populating these controls when you want more than one column. Here’s the range that I am using

listbox1

To get all three columns in my listbox, I can set the RowSource property to

Sheet1!A2:C8

and be sure to set the ColumnCount property to 3.

To populate multi-column controls with the AddItem method, I use a procedure like this

Private Sub UserForm_Initialize()
    Dim cell As Range
    Dim Rng As Range
    
    With ThisWorkbook.Sheets(”Sheet1″)
        Set Rng = .Range(”A2″, .Range(”A2″).End(xlDown))
    End With
    
    For Each cell In Rng.Cells
        With Me.ListBox1
            .AddItem cell.Value
            .List(.ListCount - 1, 1) = cell.Offset(0, 1).Value
            .List(.ListCount - 1, 2) = cell.Offset(0, 2).Value
        End With
    Next cell
    
End Sub

This procedure loops through the cells in column A. It uses AddItem to add the column A value to the ListBox. Then it uses the List property to access the other columns. List takes a row and a column argument. The row argument is computed with the ListCount property. Because the rows and columns start at 0, but ListCount doesn’t, I have to subract one to get the right row. Also note that the second column is 1 and the third is 2.

With multi-column controls, the RowSource property starts looking pretty nice. It’s a heck of a lot easier than all this List and ListCount nonsense. Nevertheless, I still use AddItem exclusively, even for multi-column controls.

22 Comments

  1. Kevin Trasler:

    I have created a listbox on a form and have assigned a rowsource(A2:C10), but I am trying to create a rowsource that will find specific data from the spreadsheet. For example if I had a spreadsheet with Name, Gender, Age as the headings in row A1, on my form I would be able to create a listbox that showed all the Names for people who were 26.

    Can anyone help?

  2. gonetribal:

    For your criteria I had a similar problem, and here is my solution:

    For Each cell In Rng.Cells
    If cell.Offset(0, 3).Value = intAge Then
    With Me.ListBox1
    .AddItem cell.Value
    .List(.ListCount - 1, 1) = cell.Offset(0, 1).Value
    .List(.ListCount - 1, 2) = cell.Offset(0, 2).Value
    End With
    End If
    Next cell

    Good luck.

  3. selvavinayagam:

    Hi all

    I need to get the value of an m*n array from a combobox. I need to get a particular cell value say i and manipulate the value of i in some other formulae / case. For that case, to get the value of say second column fifth row how do i do that. Kindly help

    With regards

    Selva

  4. Graham:

    Hi,

    This doesn’t seem to work with a ComboBox…?

  5. Jon Peltier:

    I don’t find RowSource too attractive. To populate my list boxes and combo boxes, single or multiple column, I usually use something like this:

    Dim vList as Variant

    With ThisWorkbook.Sheets(”Sheet1″)
      vList = .Range(”A2″, _
    .Range(”A2″).End(xlDown).End(xlToRight))
    End With

    Me.ListBox1.List = vList

    Easier than AddItem, and I can use a VB array for vList which I’ve manipulated independent of the worksheet.

  6. LEO:

    Please , im portguese a dont speek good english, but i would like ask for you a code that allowes to copy cells from list according the start cell, like this

    if cell starts from 11* in list column A , copy range A to C on that area and create sheet named A

    I would apreciat to listen same from you

  7. Rob van Gelder:

    I was going to post about mutlicolumn combos, but I see it has been done.

    The following is the code I wrote:

    Create a new UserForm and drop a ComboBox and a Command Button onto it:

    Then use this code.

    Private Sub UserForm_Initialize()
        Init_ComboBox1
    End Sub

    Sub Init_ComboBox1()
        Dim rng As Range

        With ComboBox1
            .Clear
            .ColumnWidths = ";0"
            .ColumnCount = 2
            For Each rng In Range("A2:A10")
                .AddItem rng.Value
                .List(.ListCount - 1, 1) = rng.Offset(, 1).Value
            Next
        End With
    End Sub

    Private Sub CommandButton1_Click()
        With ComboBox1
            If .ListIndex > -1 Then
            MsgBox "You selected " & .List(.ListIndex, 0) & " " & .List(.ListIndex, 1)
            End If
        End With
    End Sub

    Cheers,
    Rob

  8. Jon Peltier:

    Rob -

    Instead of this:

    For Each rng In Range(”A2:A10″)
    .AddItem rng.Value
    .List(.ListCount - 1, 1) = rng.Offset(, 1).Value
    Next

    How about this:

    .List = Range(”A2:B10″).Value

  9. Jon Peltier:

    Hmm, I see that’s what I said a few months ago in comment 5.

  10. Rob van Gelder:

    Jon,

    Very smart and elegant - just what I like :)

    Cheers

  11. Jon Peltier:

    Rob -

    It doesn’t matter so much now, but back when I was learning Excel VBA in Excel 97 on a rather slow Windows 95 laptop, I learned that looping cell-by-cell can seriously impact the speed of a procedure; this is even more pronounced when writing to the sheet than reading from it. Your snippet takes 18 trips from VBA to the worksheet to gather data, mine takes only one.

    - Jon

  12. Rob van Gelder:

    Jon:

    My code was originally for looping a recordset. I just converted it to use ranges, for the sake of a reproducible, easy to follow, post.
    It never occurred to me that there might be a more elegant way with ranges.

    Indeed, I’ve noticed the “cell-by-cell” slowdown when writing - sometimes it seems slow even when calculations are set to manual.

    Rob

  13. TRex2006:

    Thanks - fixed my issue! Genius!

  14. Kobie:

    Can you provide me the code that when I select a combo which list each sheets in a file will produce result containing the items in column a of the sheet selected into a listbox and when you select an item in that listbox, it will produce items into another listbox.

  15. John Walkenbach:

    Kobie, just a tip: Try reading your text before you post — from the perspective of someone who has no idea what you’re talking about. Try it with what you just posted, and you’ll realize why you will never get an answer.

  16. Emily Wong:

    These code fragments are very helpful.
    thank you

  17. Jep:

    @Kobie

    Check this out: http://www.vbexplorer.com/VBExplorer/vb_feature/june2000/june2000.asp
    This will do most of the job. You will need to introduce the looping through sheets to add to the listbox.

    @rest
    I am looking for three columns in a listbox, but as far as I can tell the maximum is two. Is this correct? How do I introduce more columns?

  18. Jon Peltier:

    You can get any number of columns in a listbox or combobox (well, there must be a limit, but I’ve never exceeded it). Check the ColumnCount property. Note that the first column is column 0. Sometimes I’ll use extra columns to hold extra information, and give the column a width of zero so only I and my code know it’s there.

  19. Philippe Petrov:

    Hello,
    I have a problem with listbox and combobox. I select an empty cell in excel sheet. I have form with listbox and comcobox. In other sheet I have a database - 16 colomn, or 8 pairs - caption of material and value for it. The caption in the first row define the sort of materials in the colomn situated in listbox. When some record is selected from the listbox, in the neighbour combobox, we have to show the other records from the choiced colomn. When we choice a record from the combobox, in the selected cell have to be placed the record from the combobox, and in the neighbour cell from the selected, we have to place the value of this record toward the combobox. Example:

    1 row: circle / value / squade/ value
    2 row: radius 20 / 20/ squade 20 / 400
    3 row: radius 30 / 30/ rectangle / 30

    listbox: circle, squade
    combobox1: radius 20, radius 30 (compared circle)
    comcobox2: squade 20, rectangle (compared squade)

    expected value for selected cell: combobox value
    next to selected cell: the value for selected combobox (400 for selected squade 20)

    I hope somebody to write the code that can relate the combobox value with some value from the excel table. 10x in advance

  20. Pam:

    Thanks Jon for the code below:
    Dim vList as Variant

    With ThisWorkbook.Sheets(”Sheet1″)
    vList = .Range(”A2″, _
    .Range(”A2″).End(xlDown).End(xlToRight))
    End With

    Me.ListBox1.List = vList

    It worked great for my project ( with minor changes, of course).

    Pam

  21. Big Rick:

    I am hoping you can help as I am not finding the direction I need.
    In the code below I do not understand how to seperate the information being retreived from the registry into seprate columns, hence I get a list that is twice as long (duplicates). In this case the registry values being retreived are “Key” and “Setting” which share the same values, IE, Key = Setting and Setting = Key.
    How can I get this list to be either two columns or a single column with no duplicates?

    ‘===========
    With ListBox1
    Dim c As Variant
    Dim sCustomer As Variant, iSettings As Integer
    sCustomer = GetAllSettings(appname:=”ADMCustomerList”, section:=”Customers”)
    For iSettings = LBound(sCustomer, 1) To UBound(sCustomer, 1)
    Debug.Print sCustomer(iSettings, 0), sCustomer(iSettings, 1)
    Next iSettings
    For Each c In sCustomer
    .AddItem c
    Next
    End With
    ‘=============

    Best Regards

    Rick
    XP Pro, XL2007

  22. Big Rick:

    I think I stumbled, and I don’t use that word lightly, on to an answer.

    [code]
    ‘===========
    With ListBox1
    .Clear
    Dim c As Variant
    Dim x As String ‘add this variable 10.26.07

Leave a comment