如何比较 VBA 中的值?
How do I compare values in VBA?
我有这个潜艇。当按下用户表单上的按钮时它会被激活,并用于对一个条目进行计数。我将此数据库中的条目总数存储在 A1 中。还有另一个按钮用于倒数一个条目,它工作得很好。他们都有检查,因此他们不会加载不存在的条目。不知何故这个不起作用。
Private Sub ButtonRight_Click()
MsgBox TextBoxID.Value
MsgBox Cells(1, 1).Value
MsgBox (TextBoxID.Value < Cells(1, 1).Value)
If TextBoxID.Value < Cells(1, 1).Value Then
LoadEntry (TextBoxID.Value + 1)
End If
End Sub
LoadEntry Sub 也用在其他地方并且有效。我有这个带有 MsgBox 的输出内容用于调试。它给出输出 1、2、false。所以 (1 < 2) = false.
这里是另一个有效的比较:
Private Sub ButtonLeft_Click()
If TextBoxID.Value > 1 Then
LoadEntry (TextBoxID.Value - 1)
End If
End Sub
问题是隐式转换。
字符串作为文本进行比较,因此“10”小于“2”,因为它按字母顺序 排序。
Debug.Print "10" > "2" ' output: False
TextBox
控件的值始终是 String
;为了将其视为数值,您必须首先将其转换为数值 - 但前提是这样做是合法的(例如,“ABC”没有等效的数值)。
此外,单元格的值是一个 Variant
,它可能包含一个数字或另一个可以(将)正确但隐式转换为数值的值,但它也可以是一个 Variant/Error
(例如 #N/A
或 #VALUE!
错误)每次您尝试将它与任何东西(除了另一个 Variant/Error
值),因此单元格的值也应该在比较之前进行验证和显式转换:
Dim rawValue As String
rawValue = TextBoxID.Value
If IsNumeric(rawValue) Then
Dim numValue As Double
numValue = CDbl(rawValue)
Dim cellValue As Variant
cellValue = ActiveSheet.Cells(1, 1).Value
If IsNumeric(cellValue) Then
If numValue < CDbl(cellValue) Then
LoadEntry numValue + 1
End If
End If
End If
请注意,不合格的 Cells
隐含地指的是 无论 ActiveSheet 是什么 - 如果这不是意图,请考虑使用显式 Worksheet
对象,例如Sheet1.Cells(1, 1)
。如果它 是 故意的,请考虑使用 ActiveSheet
对其进行限定,以便代码说出它所做的,并按照它说的去做。
比较VBA中不同类型的值不是一个简单的任务,比较的结果取决于变量的类型,转换为数字的可能性等。变体变量的比较方式不同于“非变体”变量。参见 https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/comparison-operators
根据文档,TextBox 对象的值 属性 具有基本类型 Variant(请参阅 https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/value-property-microsoft-forms)。
因此,比较Variant/String
(TextBox.Value与字符串)和Variant/Double
(Cell.Value与数字)的结果-TextBox.Value总是大于Cell.Value:
Private Sub CommandButton1_Click()
TextBox1.Value = "123"
[A1].Value = 9999
Debug.Print "TextBox1.Value = " & TextBox1.Value & ", Type is " & TypeName(TextBox1.Value)
Debug.Print "[A1].Value = " & [A1].Value & ", Type is "; TypeName([A1].Value)
Debug.Print "TextBox1.Value > [A1].Value : (" & TextBox1.Value & " > " & [A1].Value & ") is " & (TextBox1.Value > [A1].Value)
Me.Hide
End Sub
'Output:
'TextBox1.Value = 123, Type is String
'[A1].Value = 9999, Type is Double
'TextBox1.Value > [A1].Value : (123 > 9999) is True
因此,比较前建议:
- 将比较值的类型减少为一种;
- 处理类型转换错误
简单的方法是使用 Val() 函数 https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/val-function
Private Sub ButtonRight_Click()
If Val(TextBoxID.Value) < Val(Cells(1, 1).Value) Then
LoadEntry (TextBoxID.Value + 1)
End If
End Sub
同样出于这个目的,我建议创建一个函数:
Function getNumDef(v As Variant, Optional defV As Long = -1) As Long
getNumDef = defV 'inintially getNumDef set as defaul value
On Error Resume Next
getNumDef = CLng(v) ' if error occurs, getNumDef value remains defV
End Function
可以通过以下方式申请:
Private Sub ButtonRight_Click()
Dim TBV as Long, CV as Long
TBV = getNumDef(TextBoxID.Value) 'Type conversion and error handling
CV = getNumDef(Cells(1, 1).Value) 'Type conversion and error handling
If TBV < 0 Or CV < 0 Then
MsgBox "Some of the values are not numeric or less than 0" _
& vbCrLf & "Check the raw data", vbCritical + vbOKOnly, "Sub ButtonRight_Click()"
Else
If TBV < CV Then
'The parentheses in `LoadEntry (TextBoxID.Value + 1)` are syntax sugar,
' i.e. the argument `TextBoxID.Value + 1` in parentheses is passed as ByVal.
'If the argument without (), i.e. `LoadEntry TextBoxID.Value + 1`,
'it is passed as described in the Sub definition or the default ByRef
LoadEntry TextBoxID.Value + 1
End If
End If
End Sub
我有这个潜艇。当按下用户表单上的按钮时它会被激活,并用于对一个条目进行计数。我将此数据库中的条目总数存储在 A1 中。还有另一个按钮用于倒数一个条目,它工作得很好。他们都有检查,因此他们不会加载不存在的条目。不知何故这个不起作用。
Private Sub ButtonRight_Click()
MsgBox TextBoxID.Value
MsgBox Cells(1, 1).Value
MsgBox (TextBoxID.Value < Cells(1, 1).Value)
If TextBoxID.Value < Cells(1, 1).Value Then
LoadEntry (TextBoxID.Value + 1)
End If
End Sub
LoadEntry Sub 也用在其他地方并且有效。我有这个带有 MsgBox 的输出内容用于调试。它给出输出 1、2、false。所以 (1 < 2) = false.
这里是另一个有效的比较:
Private Sub ButtonLeft_Click()
If TextBoxID.Value > 1 Then
LoadEntry (TextBoxID.Value - 1)
End If
End Sub
问题是隐式转换。
字符串作为文本进行比较,因此“10”小于“2”,因为它按字母顺序 排序。
Debug.Print "10" > "2" ' output: False
TextBox
控件的值始终是 String
;为了将其视为数值,您必须首先将其转换为数值 - 但前提是这样做是合法的(例如,“ABC”没有等效的数值)。
此外,单元格的值是一个 Variant
,它可能包含一个数字或另一个可以(将)正确但隐式转换为数值的值,但它也可以是一个 Variant/Error
(例如 #N/A
或 #VALUE!
错误)每次您尝试将它与任何东西(除了另一个 Variant/Error
值),因此单元格的值也应该在比较之前进行验证和显式转换:
Dim rawValue As String
rawValue = TextBoxID.Value
If IsNumeric(rawValue) Then
Dim numValue As Double
numValue = CDbl(rawValue)
Dim cellValue As Variant
cellValue = ActiveSheet.Cells(1, 1).Value
If IsNumeric(cellValue) Then
If numValue < CDbl(cellValue) Then
LoadEntry numValue + 1
End If
End If
End If
请注意,不合格的 Cells
隐含地指的是 无论 ActiveSheet 是什么 - 如果这不是意图,请考虑使用显式 Worksheet
对象,例如Sheet1.Cells(1, 1)
。如果它 是 故意的,请考虑使用 ActiveSheet
对其进行限定,以便代码说出它所做的,并按照它说的去做。
比较VBA中不同类型的值不是一个简单的任务,比较的结果取决于变量的类型,转换为数字的可能性等。变体变量的比较方式不同于“非变体”变量。参见 https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/comparison-operators
根据文档,TextBox 对象的值 属性 具有基本类型 Variant(请参阅 https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/value-property-microsoft-forms)。
因此,比较Variant/String
(TextBox.Value与字符串)和Variant/Double
(Cell.Value与数字)的结果-TextBox.Value总是大于Cell.Value:
Private Sub CommandButton1_Click()
TextBox1.Value = "123"
[A1].Value = 9999
Debug.Print "TextBox1.Value = " & TextBox1.Value & ", Type is " & TypeName(TextBox1.Value)
Debug.Print "[A1].Value = " & [A1].Value & ", Type is "; TypeName([A1].Value)
Debug.Print "TextBox1.Value > [A1].Value : (" & TextBox1.Value & " > " & [A1].Value & ") is " & (TextBox1.Value > [A1].Value)
Me.Hide
End Sub
'Output:
'TextBox1.Value = 123, Type is String
'[A1].Value = 9999, Type is Double
'TextBox1.Value > [A1].Value : (123 > 9999) is True
因此,比较前建议:
- 将比较值的类型减少为一种;
- 处理类型转换错误
简单的方法是使用 Val() 函数 https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/val-function
Private Sub ButtonRight_Click()
If Val(TextBoxID.Value) < Val(Cells(1, 1).Value) Then
LoadEntry (TextBoxID.Value + 1)
End If
End Sub
同样出于这个目的,我建议创建一个函数:
Function getNumDef(v As Variant, Optional defV As Long = -1) As Long
getNumDef = defV 'inintially getNumDef set as defaul value
On Error Resume Next
getNumDef = CLng(v) ' if error occurs, getNumDef value remains defV
End Function
可以通过以下方式申请:
Private Sub ButtonRight_Click()
Dim TBV as Long, CV as Long
TBV = getNumDef(TextBoxID.Value) 'Type conversion and error handling
CV = getNumDef(Cells(1, 1).Value) 'Type conversion and error handling
If TBV < 0 Or CV < 0 Then
MsgBox "Some of the values are not numeric or less than 0" _
& vbCrLf & "Check the raw data", vbCritical + vbOKOnly, "Sub ButtonRight_Click()"
Else
If TBV < CV Then
'The parentheses in `LoadEntry (TextBoxID.Value + 1)` are syntax sugar,
' i.e. the argument `TextBoxID.Value + 1` in parentheses is passed as ByVal.
'If the argument without (), i.e. `LoadEntry TextBoxID.Value + 1`,
'it is passed as described in the Sub definition or the default ByRef
LoadEntry TextBoxID.Value + 1
End If
End If
End Sub