Gray out items in a Combo Box list after use so users cannot select them

回眸只為那壹抹淺笑 提交于 2020-05-16 03:15:49

问题


I have a project that I am working on for hardware deployment at new locations. I have a userform combo box with a list of IP addresses that will be assigned to certain hardware items(i.e. credit card machines). I am trying to find a way where once one of the IP addresses is selected for use, that the item in the combobox list is either removed or grayed out and the user cannot reuse. But if for some reason the IP comes back available, that the item is now available for use in the list. The hardware and IP and other info will be added to a table/database in excel. So I am assuming that I have to validate this IP list against that table/database. But I am lost as to how I can accomplish the validation. I have tried data validation but I would like to this in VBA based on the combobox.

And here is the current code feeding the IP address combo box. You can either enter a single IP or a range.

Private Sub Submit_Data_Click()
 Dim wb As Workbook, ws As Worksheet, rngTarget As Range
    Dim s1 As String, ip1 As Variant
    Dim s2 As String, ip2 As Variant
    Dim i As Integer, n As Integer

    Set wb = ThisWorkbook
    Set ws = wb.Sheets("Arrays")
    Set rngTarget = ws.Range("I" & Rows.Count).End(xlUp)

    If Me.Add_single_IP = True Then
        s1 = Me.sgle_IP_add_tb1
        s2 = s1
    Else
        s1 = Me.rge_IP_start_tb2
        s2 = Me.Rge_IP_End_tb2
    End If

    ' split string into bytes
    ip1 = Split(s1, ".")
    ip2 = Split(s2, ".")

    ' validate
    Dim msg As String
    If UBound(ip1) <> 3 Or UBound(ip2) <> 3 Then
        msg = "IP must be n.n.n.n"
    ElseIf ip1(3) > 255 Or ip2(3) > 255 Then
        msg = "Host must be 1 to 255"
    ElseIf ip1(3) > ip2(3) Then
        msg = s1 & " is greater then " & s2
    ElseIf ip1(0) <> ip2(0) Or ip1(1) <> ip2(1) Or ip1(2) <> ip2(2) Then
        msg = "Different networks"
    End If

    ' failed validation
    If Len(msg) > 0 Then
        MsgBox msg, vbCritical, s1 & "-" & s2
        Exit Sub
    End If

    ' calc range and write to sheet
    n = ip2(3) - ip1(3) + 1
    For i = 1 To n
       Set rngTarget = rngTarget.Offset(1, 0) ' move down
       rngTarget = Join(ip1, ".")
       ip1(3) = ip1(3) + 1
    Next
    MsgBox n & " addresses added ", vbInformation, s1 & "-" & s2
End Sub

Like I stated prior...If I can remove the IP's from the selection as they are assigned so that that we do not have duplicates and then have the ability to make it available again if the hardware piece is no longer being used is great. If it's easier then allowing it to still be visible but grayed out in the list, and of course NOT allow it to be selected and adding a MsgBox error to user that the IP is already in use will also work well.

Thanks for any and all help.


回答1:


Remove Column I from the RowSource of the combo box and add the items you want when the form initializes.

Private Sub UserForm_Initialize()

    Dim ws As Worksheet, iLastRow As Long, i As Long
    Set ws = ThisWorkbook.Sheets("Arrays")
    Me.ComboBox1.Clear
    iLastRow = ws.Cells(Rows.Count, "I").End(xlUp).Row
    For i = 3 To iLastRow
        If Len(ws.Cells(i, "H")) = 0 Then ' not assigned
            Me.ComboBox1.AddItem ws.Cells(i, "I")
        End If
    Next

End Sub



回答2:


I would input all IP addresses into a separate 'helper' range with 2 columns. The first column would have the IP address and second column will have a Yes or No value. I'd use the combination of INDEX and MATCH to populate the 2nd column dynamically (explained below).

I would then populate the combobox with the new column filled with IP addressed but the only IP addresses populated into the combobox are the ones with a No in the column next to it as they are not 'In Use'.


  Example of the Helper columns:            Example of your Array sheet columns:
         A            B                            H                 I
   +------------+------------+               +--------------+-----------------+ 
 1 | IP Address |   In Use?  |             1 | Brand/Model  |  CC Machine IP  |
 2 |  10.0.0.1  |     Yes    |             2 |  Model ABC   |     10.0.0.1    |
 3 |  10.0.0.2  |     Yes    |             3 |  Brand 123   |     10.0.0.4    |
 4 |  10.0.0.3  |     No     |             4 |              |                 |
 5 |  10.0.0.4  |     Yes    |             5 |  Brand 456   |     10.0.0.2    |
 6 |  10.0.0.5  |     No     |             6 |              |                 |
   +------------+------------+               +--------------+-----------------+

This would populate the combobox with the values; 10.0.0.3 and 10.0.0.5 in that order with no blank spaces between them.


But how exactly do we achieve this?

Assume I've set up the helper columns on a new sheet called "HelperSheet" with the 'IP Addresses' in Column A and the 'In Use?' Yes/No in Column B and the IP addresses from your input userform are entered to sheet "Arrays". You can make the necessary adjustments to these values in your own code.

First, enter all the IP addresses you want to use in Column A. The order that you enter them in will dictate the order they will populate in the combobox.

To make it easy you can enter the first IP address and then fill down the rest. You can fill down values/formulas by clicking the bottom right corner of the cell and dragging down the sheet.

Next we need to enter the INDEX/MATCH formula into Column B in the first row an IP address has been entered. If your first IP address is in cell A2, the first formula should be next to it in cell B2.

=IFERROR(IF(INDEX(Arrays!$I$1:$I$255,MATCH(A1,Arrays!$I$1:$I$255,0))=A1,"Yes"),"No")

If you want to learn more about these sheet functions you can read about them on Microsoft Office Support Page:

  • IFERROR
  • IF
  • INDEX
  • MATCH

Next, fill the formula down the column all the way to the last IP address row. You can fill down values/formulas by clicking the bottom right corner of the cell and dragging down the sheet.

Now each cell in Column B that has an IP address next to in in Column A should have the above formula in it - The only difference will be the reference to A1 in the MATCH function, as it is not an absolute reference (which would look like $A$1) - as it is a relative reference, it will increment the number for each row.

As you start to fill Column I on the "Arrays" sheet, the values in Column B on "HelperSheet" will start to change to Yes as long as they match a corresponding value in Column A. Naturally as you remove the IP address from Column I on "Arrays" , the value in Column B on "HelperSheet" will change to NO. Any IP address entered that doesn't match an address on the "HelperSheet" will be ignored.


Now to populate the Combobox

In the VBE, click on the Arrays Sheet from the list down the left hand side and change the dropdowns to 'Worksheet' and 'Change'. This is going to run the code each time a change is made on the "Arrays" sheet.

Here is an example code (comments have been added to the far right to help explain each line as necessary).

You will need to change the name of UserForm2 to match the name of your userform that has the ComboBox on it.

Private Sub Worksheet_Change(ByVal Target As Range)                'Target is the cell/cells that a change has been made on to make the code run.

Dim IPRangeItem As Long
Dim myArray As Variant
Dim IPRange As Range
Dim LastRow As Long
Dim ArrayCounter As Long

If Target.Column = 9 Then                                                         'This will only run the code below if the column the cells was changed in is I (the 9th column) otherwise it will exit the subroutine.

    LastRow = ThisWorkbook.Sheets("HelperSheet").Cells(Rows.Count, 1).End(xlUp).Row    'Finding the last row on our helper sheet where the IP addresses are entered. 
    Set IPRange = ThisWorkbook.Sheets("HelperSheet").Range("A1:B" & LastRow)
    myArray = IPRange                                                             'This line puts the range defined above straight into an Array.

        UserForm2.ComboBox1.Clear                                              'Ensures the combobox is always empty before values are assigned. 
        ArrayCounter = 1
        For IPRangeItem = 1 To UBound(myArray)
            If myArray(ArrayCounter, 2) = "No" Then                           'Looking to see if the value in Column B was "No" (remember we put the entire helper range into an array which is faster and easier to use)
                UserForm2.ComboBox1.AddItem myArray(ArrayCounter, 1)                'If it was a "Yes" the IP address value is added to the Combobox list otherwise as below nothing happens.
            Else
                'Do nothing
            End If
            ArrayCounter = ArrayCounter + 1
        Next IPRangeItem
Else
    'Do nothing
End If
End Sub

Now each time a change is made to Column I on your "Arrays" sheet, the combobox will be re-populated with all addresses not in use, taking into account the changes made.

NOTE: The formula entered into Column B on "HelperSheet" only evaluates up to row 255, if you need to extend this you will need to update the ranges in the INDEX and MATCH sections accordingly.

NOTE: As this code runs each time ANY change is made on the "Arrays" sheet, it may cause poor performance if there are a large number of changes made to your sheet often - this code is not run when any other sheets are updated/changed.

Here is an example of both ranges and the combobox:

Arrays Sheet:

HelperSheet Sheet:

ComboBox list:

Notice the combobox is missing the addresses you have entered into the "Arrays" sheet as they are 'In Use' based on the "HelperSheet" values.



来源:https://stackoverflow.com/questions/61045203/gray-out-items-in-a-combo-box-list-after-use-so-users-cannot-select-them

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