问题
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