如何使用VBA从excel中的列表框中进行多选得到结果?
How to get results based on multiple selection from the list box in excel using VBA?
我想要完成的是:
当我在单元格 D2 中 select 超过一种类型的折扣时(注意:单元格 D2 有一个宏允许我从下拉列表中 select 超过一种选择并将两个选择分开通过逗号),我想在单元格 E2 中获得它们对应值的乘积。在这种情况下,由于我 select 编辑了“学生”和“退伍军人”,我在单元格 E2 中得到 0.5 和 0.03 = 0.15 的倍数。
因为我有多种折扣类型,一个简单的 if 语句是行不通的,因为我可能 select 一次以任何顺序 select 两个以上的折扣。请帮忙,因为我是 VBA 的新手。谢谢!
这是我用于下拉列表框中多个 selection 的代码。注意:我从网上复制了这段代码。
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Oldvalue As String
Dim Newvalue As String
Application.EnableEvents = True
On Error GoTo Exitsub
If Not Intersect(Target, Columns(4)) Is Nothing Then
If Target.SpecialCells(xlCellTypeAllValidation) Is Nothing Then
GoTo Exitsub
Else: If Target.Value = "" Then GoTo Exitsub Else
Application.EnableEvents = False
Newvalue = Target.Value
Application.Undo
Oldvalue = Target.Value
If Oldvalue = "" Then
Target.Value = Newvalue
Else
If InStr(1, Oldvalue, Newvalue) = 0 Then
Target.Value = Oldvalue & ", " & Newvalue
Else:
Target.Value = Oldvalue
End If
End If
End If
End If
Application.EnableEvents = True
Exitsub:
Application.EnableEvents = True
End Sub
如果您有 Excel 365,这可以使用公式轻松完成,使用 FILTERXML
和溢出范围
=PRODUCT(XLOOKUP(FILTERXML("<a><s>"&SUBSTITUTE(E2,",","</s><s>")&"</s></a>","//s"),A:A,B:B,0,0))
或者,UDF(不需要 Excel 365)
Function NetDiscount(LookupItems As Variant, Discounts As Range, Optional Seperator As String = ",") As Variant
Dim LookupArray() As String
Dim LookupItem As Variant
Dim idx As Variant
Dim Discount As Double
Dim OneOrMoreFound As Boolean
LookupArray = Split(LookupItems, Seperator)
Discount = 1#
For Each LookupItem In LookupArray
idx = Application.Match(LookupItem, Discounts.Columns(1), 0)
If Not IsError(idx) Then
OneOrMoreFound = True
Discount = Discount * Discounts.Cells(idx, 2).Value2
End If
Next
If Not OneOrMoreFound Then
' Return default value if no items found
Discount = 0#
End If
NetDiscount = Discount
End Function
与您的问题无关,但您的事件代码中存在一个重大错误:如果您的“折扣类型”列表包含包含在另一个项目(例如“公民”和“老年人”)中的项目,并且较长的项目已被选中,那么您的代码将不会添加较短的项目,因为 If InStr(1, Oldvalue, Newvalue) = 0 Then
会在较长的项目中找到较短的值。
这是一个重构版本,解决了这个问题和其他样式问题
Private Sub Worksheet_Change(ByVal Target As Range)
Dim OldValue As String
Dim NewValue As String
Dim Seperator As String
Dim CombinedValue As String
On Error GoTo ExitSub
If Target.Count > 1 Then GoTo ExitSub
If Target.Value = vbNullString Then GoTo ExitSub
If Not Intersect(Target, Me.Columns(4)) Is Nothing Then
If Not Target.SpecialCells(xlCellTypeAllValidation) Is Nothing Then
Application.EnableEvents = False
Seperator = ", "
NewValue = Target.Value
Application.Undo
OldValue = Target.Value
If OldValue = vbNullString Then
CombinedValue = Seperator & NewValue
Else
OldValue = Seperator & OldValue
NewValue = Seperator & NewValue
If InStr(1, OldValue, NewValue) = 0 Then
CombinedValue = OldValue & NewValue
Else
CombinedValue = OldValue
End If
End If
Target.Value = Mid$(CombinedValue, Len(Seperator) + 1)
End If
End If
ExitSub:
Application.EnableEvents = True
End Sub
我想要完成的是:
当我在单元格 D2 中 select 超过一种类型的折扣时(注意:单元格 D2 有一个宏允许我从下拉列表中 select 超过一种选择并将两个选择分开通过逗号),我想在单元格 E2 中获得它们对应值的乘积。在这种情况下,由于我 select 编辑了“学生”和“退伍军人”,我在单元格 E2 中得到 0.5 和 0.03 = 0.15 的倍数。
因为我有多种折扣类型,一个简单的 if 语句是行不通的,因为我可能 select 一次以任何顺序 select 两个以上的折扣。请帮忙,因为我是 VBA 的新手。谢谢!
这是我用于下拉列表框中多个 selection 的代码。注意:我从网上复制了这段代码。
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Oldvalue As String
Dim Newvalue As String
Application.EnableEvents = True
On Error GoTo Exitsub
If Not Intersect(Target, Columns(4)) Is Nothing Then
If Target.SpecialCells(xlCellTypeAllValidation) Is Nothing Then
GoTo Exitsub
Else: If Target.Value = "" Then GoTo Exitsub Else
Application.EnableEvents = False
Newvalue = Target.Value
Application.Undo
Oldvalue = Target.Value
If Oldvalue = "" Then
Target.Value = Newvalue
Else
If InStr(1, Oldvalue, Newvalue) = 0 Then
Target.Value = Oldvalue & ", " & Newvalue
Else:
Target.Value = Oldvalue
End If
End If
End If
End If
Application.EnableEvents = True
Exitsub:
Application.EnableEvents = True
End Sub
如果您有 Excel 365,这可以使用公式轻松完成,使用 FILTERXML
和溢出范围
=PRODUCT(XLOOKUP(FILTERXML("<a><s>"&SUBSTITUTE(E2,",","</s><s>")&"</s></a>","//s"),A:A,B:B,0,0))
或者,UDF(不需要 Excel 365)
Function NetDiscount(LookupItems As Variant, Discounts As Range, Optional Seperator As String = ",") As Variant
Dim LookupArray() As String
Dim LookupItem As Variant
Dim idx As Variant
Dim Discount As Double
Dim OneOrMoreFound As Boolean
LookupArray = Split(LookupItems, Seperator)
Discount = 1#
For Each LookupItem In LookupArray
idx = Application.Match(LookupItem, Discounts.Columns(1), 0)
If Not IsError(idx) Then
OneOrMoreFound = True
Discount = Discount * Discounts.Cells(idx, 2).Value2
End If
Next
If Not OneOrMoreFound Then
' Return default value if no items found
Discount = 0#
End If
NetDiscount = Discount
End Function
与您的问题无关,但您的事件代码中存在一个重大错误:如果您的“折扣类型”列表包含包含在另一个项目(例如“公民”和“老年人”)中的项目,并且较长的项目已被选中,那么您的代码将不会添加较短的项目,因为 If InStr(1, Oldvalue, Newvalue) = 0 Then
会在较长的项目中找到较短的值。
这是一个重构版本,解决了这个问题和其他样式问题
Private Sub Worksheet_Change(ByVal Target As Range)
Dim OldValue As String
Dim NewValue As String
Dim Seperator As String
Dim CombinedValue As String
On Error GoTo ExitSub
If Target.Count > 1 Then GoTo ExitSub
If Target.Value = vbNullString Then GoTo ExitSub
If Not Intersect(Target, Me.Columns(4)) Is Nothing Then
If Not Target.SpecialCells(xlCellTypeAllValidation) Is Nothing Then
Application.EnableEvents = False
Seperator = ", "
NewValue = Target.Value
Application.Undo
OldValue = Target.Value
If OldValue = vbNullString Then
CombinedValue = Seperator & NewValue
Else
OldValue = Seperator & OldValue
NewValue = Seperator & NewValue
If InStr(1, OldValue, NewValue) = 0 Then
CombinedValue = OldValue & NewValue
Else
CombinedValue = OldValue
End If
End If
Target.Value = Mid$(CombinedValue, Len(Seperator) + 1)
End If
End If
ExitSub:
Application.EnableEvents = True
End Sub