How to make a Search Filter in Excel VBA that displays search result in the ListBox while typing a word?

穿精又带淫゛_ 提交于 2019-12-08 11:03:50

问题


I'm trying to make an Advanced Search now for weeks in my Userform where it will filter and display the result on the ListBox while typing a value. But somehow my ComboBox that serves as a filter has a dropdown function already.

I have no idea how can I make it like the way I wanted it.

My UserForm contains 8 columns.

Here is the existing code for the ComboBox filter

Private Sub cmbSearch_Change()

    'The function of this code below is for the user to click a value from the ComboBox and then the result will be displayed on the TextBoxes and ListBox.
    x = Sheets("DATA STOCK").Range("A" & Rows.Count).End(xlUp).Row
        For y = 2 To x
            If Sheets("DATA STOCK").Cells(y, 1).Text = cmbSearch.Value Then
                cmbSchema.Text = Sheets("DATA STOCK").Cells(y, 1)
                cmbEnvironment.Text = Sheets("DATA STOCK").Cells(y, 2)
                cmbHost.Text = Sheets("DATA STOCK").Cells(y, 3)
                cmbIP.Text = Sheets("DATA STOCK").Cells(y, 4)
                cmbAccessible.Text = Sheets("DATA STOCK").Cells(y, 5)
                cmbLast.Text = Sheets("DATA STOCK").Cells(y, 6)
                cmbConfirmation.Text = Sheets("DATA STOCK").Cells(y, 7)
                cmbProjects.Text = Sheets("DATA STOCK").Cells(y, 8)

                UserForm1.listHeader.RowSource = "A" + CStr(y) + ": H" + CStr(y)
                Exit For
            End If
        Next y

End Sub

Expected Result:

  1. User types word in the ComboBox (I have selected ComboBox as a filter because of its dropdown function)
  2. While the user is typing, it will show the result to the ListBox.

The problem is I don't know how to create that kind of search filter and if it is possible even though I already have a dropdown function in my ComboBox


回答1:


Saw that you've been working for weeks on this.

I have refactored your form's code and implemented the functionality you've been looking for.

As my other answer to your other question, in my opinion it's easier to work adding and removing items to the listbox, rather than working with excel ranges. (How to fix this bug in my code that doesn't allow me to update other columns in excel userform?)

Important remarks: - I've converted the data inside the sheet to an Excel Structured Table (Ctrl + T) - I took one of your previous files, so the information you have inside the table may be out of date - Testing I also modified some of the data - I suggest you copy and paste your most recent data and replace it inside the table

Here you can download the file based on your data: https://github.com/rdiazjimenez/excel-vba-userform-basic-listbox-demo/blob/master/MDM_DB_Checking_09122018_RD.xlsm



I covered basic operations (Create, Read, Update, Delete and Search/Filter) with Excel Data loaded into a Listbox inside a Userform.


This is the code behind the form:

Option Explicit

    ' Code updated
    Private Sub btnDelete_Click()

        Application.EnableEvents = False

        Call mCode.Delete

        Application.EnableEvents = True

    End Sub

    ' Code updated
    Private Sub btnView_Click()

        Application.EnableEvents = False
        Call mCode.Read
        Application.EnableEvents = True

    End Sub

    ' Code updated
    Private Sub cmbAdd_Click()

        Application.EnableEvents = False

        Call mCode.Create

        Application.EnableEvents = True

    End Sub

    ' Code updated
    Private Sub cmbClearFields_Click()

        Application.EnableEvents = False

        Call mCode.ClearControls

        Application.EnableEvents = True

    End Sub

    ' Code updated
    Private Sub cmbSearch_Change()

        Application.EnableEvents = False

        Call FilterList(Me.listHeader, Me.cmbSearch.Text)

        Application.EnableEvents = True

    End Sub

    ' Code updated
    Private Sub cmbUpdate_Click()

        Application.EnableEvents = False

        Call mCode.Update

        Application.EnableEvents = True

    End Sub

    ' Code updated
    Private Sub CommandButton5_Click()

        Application.EnableEvents = False
        Call mCode.ClearList
        Application.EnableEvents = True

    End Sub

    ' Code from this event was removed
        Private Sub listHeader_Click()

        End Sub

    ' Code added
    Private Sub listHeader_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
        Application.EnableEvents = False

        Call mCode.LoadControls

        Application.EnableEvents = True

    End Sub

    ' Code partially updated
        Private Sub UserForm_Initialize()

            Me.cmbSearch.List = ThisWorkbook.Sheets("PRESTAGE DB").ListObjects("TableData").ListColumns(1).DataBodyRange.Value

            Me.cmbEnvironment.AddItem "DEV"
            Me.cmbEnvironment.AddItem "UAT"
            Me.cmbEnvironment.AddItem "SIT"
            Me.cmbEnvironment.AddItem "QA"
            Me.cmbEnvironment.AddItem "PROD"

            Me.cmbAccessible.AddItem "Y"
            Me.cmbAccessible.AddItem "N"

            Me.cmbIP.AddItem "1521"

            Me.cmbProjects.AddItem "DP - proposed for DEV/SIT"
            Me.cmbProjects.AddItem "PH EFUSE SIT"
            Me.cmbProjects.AddItem "MyAXA SG DEV/DIT"


        End Sub

And this is the code inside a module called mCode:

Option Explicit

    ' Global variables
    Const sheetName As String = "PRESTAGE DB"
    Const tableName As String = "TableData"

    Public Sub ShowUserForm()

        oUserForm.Show

    End Sub


    Public Sub Read()
        ' Comments: Loads the data from an excel table (listobject) into a listbox located inside a userform
        ' Params  :
        ' Notes   : Adapt the initialize variables section
        ' Created : 2019/01/25 RD www.ricardodiaz.co
        ' Modified:


        ' Define objects variables
        Dim myUserForm As oUserForm ' Note: you're defining the variable as the class of the userform. This gives you access to the userform's controls later
        Dim myListObject As Excel.listObject
        Dim myRange As Excel.Range

        ' Define other variables
        Dim columnCount As Integer

        Dim selectedItem As Integer
        Dim rowCounter As Long
        Dim columnCounter As Integer

        '''''''' Initialize objects ''''''''

        ' Init the userform
        ' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
        Set myUserForm = oUserForm

        ' Load the data from the Excel table into a range variable
        ' Note: It's safer to refer to thisworkbook
        Set myListObject = ThisWorkbook.Worksheets(sheetName).ListObjects(tableName)




        '''''''' Initialize variables ''''''''
        myUserForm.listHeader.ColumnWidths = "130 pt;60 pt;82 pt;55 pt;70 pt;195 pt;170 pt;130 pt"

        ' Set the number of columns to the same of the table in the Excel sheet
        columnCount = myListObject.ListColumns.Count

        ' Get the current selected item
        selectedItem = myUserForm.listHeader.ListIndex ' this returns -1 if none is selected

        ' Clear the listbox contents
        Call mCode.ClearList

        ' Set the number of columns to load into the listbox
        myUserForm.listHeader.columnCount = columnCount

        ' Loop through each row and load it into the listbox
        ' Note: begins with 2 because the first row are the table headers
        For rowCounter = 2 To myListObject.Range.Rows.Count
            With myUserForm.listHeader

                .AddItem

                ' Load value of each column in the table row
                For columnCounter = 0 To columnCount

                    .List(rowCounter - 2, columnCounter) = myListObject.Range.Cells(rowCounter, columnCounter + 1).Value

                Next columnCounter

            End With
        Next

        ' Select previously selected row
        If selectedItem < myUserForm.listHeader.ListCount Then
            myUserForm.listHeader.ListIndex = selectedItem
        End If


        ' Clean up objects
        Set myListObject = Nothing
        Set myUserForm = Nothing

    End Sub

    Public Sub Create()
        ' Comments: Adds a new row with the data entered by the user and reloads the listbox inside the userform
        ' Params  :
        ' Notes   : Adapt the initialize variables section
        ' Created : 2019/01/25 RD www.ricardodiaz.co
        ' Modified:

        ' Define objects variables
        Dim myUserForm As oUserForm ' Note: you're defining the variable as the class of the userform. This gives you access to the userform's controls later
        Dim myListObject As Excel.listObject
        Dim myListRow As Excel.listRow


        '''''''' Initialize objects ''''''''

        ' Init the userform
        ' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
        Set myUserForm = oUserForm

        ' Add the information to the Excel table
        Set myListObject = ThisWorkbook.Worksheets(sheetName).ListObjects(tableName)

        ' Validate if all the information is correct
        If myUserForm.cmbEnvironment.Text = vbNullString _
            Or myUserForm.cmbHost.Text = vbNullString _
            Or myUserForm.cmbIP.Text = vbNullString _
            Or myUserForm.cmbAccessible.Text = vbNullString _
            Or myUserForm.cmbLast.Text = vbNullString Then

            MsgBox "Some fields cannot be blank!", vbCritical, "Data Missing"

            Exit Sub

        End If

        ' Add a blank row at the end of the Excel table
        Set myListRow = myListObject.ListRows.Add

        ' Set the information into de excel table
        With myListRow
            .Range(1) = myUserForm.cmbSchema.Text
            .Range(2) = myUserForm.cmbEnvironment.Text
            .Range(3) = myUserForm.cmbHost.Text
            .Range(4) = myUserForm.cmbIP.Text
            .Range(5) = myUserForm.cmbAccessible.Text
            .Range(6) = myUserForm.cmbLast.Text
            .Range(7) = myUserForm.cmbConfirmation.Text
            .Range(8) = myUserForm.cmbProjects.Text
        End With

        MsgBox "Data Added!"

        ' Reload the data into the listbox
        Call mCode.Read

        ' Select the last item in the listbox
        myUserForm.listHeader.ListIndex = myUserForm.listHeader.ListCount - 1

        ' Clear control's contents
        Call ClearControls ' Note that this is a private procedure inside the mCode module

        ' Clean up objects
        Set myListRow = Nothing
        Set myListObject = Nothing
        Set myUserForm = Nothing

    End Sub

    Public Sub Update()
        ' Comments: Updates a row with the data entered by the user and reloads the listbox inside the userform
        ' Params  :
        ' Notes   : Adapt the initialize variables section
        ' Created : 2019/01/25 RD www.ricardodiaz.co
        ' Modified:

        ' Define objects variables
        Dim myUserForm As oUserForm ' Note: you're defining the variable as the class of the userform. This gives you access to the userform's controls later
        Dim myListObject As Excel.listObject
        Dim myListRow As Excel.listRow

        ' Define variables
        Dim selectedItem As Integer



        '''''''' Initialize objects ''''''''

        ' Init the userform
        ' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
        Set myUserForm = oUserForm

        ' Add the information to the Excel table
        Set myListObject = ThisWorkbook.Worksheets(sheetName).ListObjects(tableName)



        ' Define selected row number
        selectedItem = myUserForm.listHeader.ListIndex + 1

        ' Exit if there are no other rows
        If selectedItem = 0 Then
            MsgBox "There are no rows left!"
            Exit Sub
        End If

        ' Initialize the row at the end of the Excel table
        Set myListRow = myListObject.ListRows(selectedItem)


        ' the following section is exactly as the Create procedure, so you theorically could make just one procedure for Create and Update

        ' Set the information into de excel table
        With myListRow
            .Range(2) = myUserForm.cmbEnvironment.Text
            .Range(3) = myUserForm.cmbHost.Text
            .Range(4) = myUserForm.cmbIP.Text
            .Range(5) = myUserForm.cmbAccessible.Text
            .Range(6) = myUserForm.cmbLast.Text
            .Range(7) = myUserForm.cmbConfirmation.Text
            .Range(8) = myUserForm.cmbProjects.Text
        End With

        ' Reload the data into the listbox
        Call mCode.Read

        ' Select the updated item in the listbox
        myUserForm.listHeader.ListIndex = selectedItem - 1

        MsgBox "Data Updated!"

        ' Clear control's contents
        Call ClearControls ' Note that this is a private procedure inside the mCode module

        ' Clean up objects
        Set myListRow = Nothing
        Set myListObject = Nothing
        Set myUserForm = Nothing

    End Sub

    Public Sub Delete()
        ' Comments: Deletes a row with the data entered by the user and reloads the listbox inside the userform
        ' Params  :
        ' Notes   : Adapt the initialize variables section
        ' Created : 2019/01/25 RD www.ricardodiaz.co
        ' Modified:

        ' Define objects variables
        Dim myUserForm As oUserForm ' Note: you're defining the variable as the class of the userform. This gives you access to the userform's controls later
        Dim myListObject As Excel.listObject
        Dim myListRow As Excel.listRow

        ' Define variables
        Dim selectedItem As Integer

        '''''''' Initialize objects ''''''''

        ' Init the userform
        ' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
        Set myUserForm = oUserForm

        ' Add the information to the Excel table
        Set myListObject = ThisWorkbook.Worksheets(sheetName).ListObjects(tableName)

        ' Define selected row number
        selectedItem = myUserForm.listHeader.ListIndex + 1

        ' Exit if there are no other rows
        If selectedItem = 0 Then
            MsgBox "There are no rows left or you didn't select a valid row!"
            Exit Sub
        End If

        If MsgBox("Are you sure you want to delete this row?", vbYesNo + vbQuestion, "Yes") = vbNo Then

            Exit Sub

        End If

        ' Initialize the row at the end of the Excel table
        Set myListRow = myListObject.ListRows(selectedItem)

        ' Delete the row
        myListRow.Delete

        ' Reload the data into the listbox
        Call mCode.Read

        ' Select the next item in the listbox
        myUserForm.listHeader.ListIndex = WorksheetFunction.Min(selectedItem - 1, myUserForm.listHeader.ListCount) - 1

        ' Clean up objects
        Set myListRow = Nothing
        Set myListObject = Nothing
        Set myUserForm = Nothing

    End Sub
    Public Sub ClearList()
        ' Comments: Clear the listbox

        ' Define objects variables
        Dim myUserForm As oUserForm

        ' Init the userform
        ' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
        Set myUserForm = oUserForm


        myUserForm.listHeader.Clear

    End Sub
    Public Sub LoadControls()
        ' Comments: Loads the selected row's data into the controls

        ' Define objects variables
        Dim myUserForm As oUserForm

        Dim selectedItem As Integer

        ' Init the userform
        ' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
        Set myUserForm = oUserForm

        ' Get the row of the selected item in the listbox
        selectedItem = myUserForm.listHeader.ListIndex

        ' Set the control's text to each column of the selected item
        myUserForm.cmbSchema.Value = myUserForm.listHeader.List(selectedItem, 0)
        myUserForm.cmbEnvironment.Value = myUserForm.listHeader.List(selectedItem, 1)
        myUserForm.cmbHost.Value = myUserForm.listHeader.List(selectedItem, 2)
        myUserForm.cmbIP.Value = myUserForm.listHeader.List(selectedItem, 3)
        myUserForm.cmbAccessible.Value = myUserForm.listHeader.List(selectedItem, 4)
        myUserForm.cmbLast.Value = myUserForm.listHeader.List(selectedItem, 5)
        myUserForm.cmbConfirmation.Value = myUserForm.listHeader.List(selectedItem, 6)
        myUserForm.cmbProjects.Value = myUserForm.listHeader.List(selectedItem, 7)

        ' Clean up objects
        Set myUserForm = Nothing

    End Sub

    Public Sub ClearControls()
        ' Comments: Reset controls to empty strings

        ' Define objects variables
        Dim myUserForm As oUserForm

        ' Init the userform
        ' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
        Set myUserForm = oUserForm

        ' Clear the controls
        myUserForm.cmbSchema.Text = vbNullString
        myUserForm.cmbEnvironment.Text = vbNullString
        myUserForm.cmbHost.Text = vbNullString
        myUserForm.cmbIP.Text = vbNullString
        myUserForm.cmbAccessible.Text = vbNullString
        myUserForm.cmbLast.Text = vbNullString
        myUserForm.cmbConfirmation.Text = vbNullString
        myUserForm.cmbProjects.Text = vbNullString

        ' Clean up objects
        Set myUserForm = Nothing

    End Sub

    Public Sub FilterList(oLb As MSForms.ListBox, strFiltro As String)


        Dim columnCounter As Integer
        Dim listString As String

        Dim rowCounter As Integer

        oLb.ListIndex = -1

        ' Read the whole list
        Call mCode.Read

        ' Remove unmatching items
        For rowCounter = oLb.ListCount - 1 To 0 Step -1

            listString = vbNullString

            ' Concat the list columns values in one string
            For columnCounter = 0 To oLb.columnCount

                listString = listString & oLb.Column(columnCounter, rowCounter)

            Next columnCounter

            If InStr(1, listString, strFiltro, 1) = 0 Then

                ' Remove items that don't match
                oLb.RemoveItem rowCounter

            End If

        Next

    End Sub



回答2:


Something like so?

Private Sub TextBox1_Change()

Dim strID As String
Dim lngRow As Long
Dim a As Variant

strID = TextBox1.Text

On Error GoTo eHandle
lngRow = WorksheetFunction.Match(strID, Range("a1:a10"), 0)
On Error GoTo 0 
If lngRow > 0 Then
    Me.ListBox1.RowSource = ""
    Me.ListBox1.ColumnCount = 4
    Me.ListBox1.ColumnWidths = "20;20;20;20"
    Me.ListBox1.RowSource = "Sheet1!a" & lngRow & ":d" & lngRow
End If

Exit Sub

eHandle:

    lngRow = 0
    Resume Next

End Sub

Private Sub UserForm_Click()

End Sub


来源:https://stackoverflow.com/questions/54519097/how-to-make-a-search-filter-in-excel-vba-that-displays-search-result-in-the-list

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!