【问题标题】:VBA: Format cell on #VALUE ErrorVBA:在#VALUE错误上格式化单元格
【发布时间】:2012-01-20 14:48:00
【问题描述】:

我创建了一个函数,它在范围内搜索特定值并返回相邻特征。

Function Busca(valor As String)
    Dim bus(0 To 1)
    bus(0) = Worksheets("Sheet2").Range("A1:A10").Find(valor, LookAt:=xlWhole). _
        Offset(0, 1)
    bus(1) = Worksheets("Sheet2").Range("A1:A10").Find(valor, LookAt:=xlWhole). _
        Offset(0, 2)
    Busca = bus
End Function

如果A1:A10 中的valor 不匹配,则函数返回{#VALUE,#VALUE},这没问题,但我想返回类似{"No match", ""} 的内容,其中包含“不匹配”单元格给定的颜色。我已经尝试过数据验证、错误处理和If ThenActiveCell.Interior.ColorIndex 无济于事。另外,如果错误得到纠正,我希望单元格恢复为透明状态。

我想事件处理程序可以解决问题,但我是 VBA 的新手,还有很多东西我不明白。

编辑

按照建议,要清楚:

如果未找到匹配项,如何使输出单元格更改颜色,如果找到匹配项(在 VBA 中)则不显示颜色?

【问题讨论】:

  • 您的函数如图所示不返回任何内容...您是否考虑过只使用 VLOOKUP() 之类的工作表公式?函数(从工作表调用时)不能更改工作表:它们只能将值返回到调用单元格。如果您需要添加颜色,则可以使用条件格式。
  • 我已经更正了公式。我不知道函数不能改变工作表。作为条件格式,我不确定将功能添加为 Sub 是否更方便。我希望普通用户无法更改内容,但不想用密码保护工作区。

标签: error-handling excel excel-formula vba


【解决方案1】:

我不确定你要去哪里加上偏移量附加到 xlWhole,它指的是是否检查整个单元格。这里有一些注意事项,你会看到 find 返回一个对象:

Function Busca(valor As String)
''http://msdn.microsoft.com/en-us/library/aa195730(v=office.11).aspx
Dim bus(0 To 1)
With Worksheets("Sheet2").Range("A1:A10")
    Set c = .Find(valor, LookAt:=xlWhole)
    If Not c Is Nothing Then
        bus(0) = c.Address

        Set c = .FindNext(c)
        If Not c Is Nothing Then
            bus(1) = c.Address
        Else
            bus(1) = "None"
        End If
    Else
        bus(0) = "None"
    End If
End With
Debug.Print bus(0), bus(1)
Busca = bus
End Function

【讨论】:

  • 哇,这太尴尬了。代码中缺少括号。它应该是Worksheets("Sheet2").Range("A1:A10").Find(valor, LookAt:=xlWhole).Offset(0, 1)。我现在已经更正了。重点是检索匹配右侧单元格的信息和匹配右侧的两个单元格的信息。
  • @Manuel 您说“如果找不到匹配项,则输出单元格会改变颜色”。什么是输出单元?恐怕你还不清楚。你的意思是找到一些东西,如果右边的单元格匹配,很好,如果没有,改变右边单元格的颜色?
  • 对不起,不够清晰。输出单元格将是输入函数的单元格。正如我在@TonyDallimore 的回答中所写的评论一样,假设我在单元格F10:F11 中输入函数,如果找不到匹配项,我希望F10 改变颜色。
  • @Manuel 你有什么反对按钮的吗?
【解决方案2】:

这是根据提问者的新信息完全重写的答案。

如果我理解正确,您希望创建一个自定义函数来更改单元格的颜色。 Microsoft 的自定义函数帮助中的以下文本表明您不能:

您可以在自定义函数中使用的 VBA 关键字数量较少 比您可以在宏中使用的数字。自定义函数不是 除了将值返回到 工作表或另一个 VBA 宏或函数中使用的表达式。 例如,自定义函数不能调整窗口大小,编辑公式 一个单元格,或更改文本的字体、颜色或图案选项 一个细胞。如果您在函数中包含此类“操作”代码 过程中,函数返回#VALUE!错误。

我知道两种可能满足您要求的替代方案。在灵光一现后,后来添加了第三种选择。

备选方案 1:提供允许值的下拉列表

将光标定位到具有限制值的单元格。从工具栏中选择数据,然后选择验证。将显示一个数据验证表单。

如果尚未选择,请选择“设置”选项卡。单击“允许:”下的框,然后选择列表。在源框中输入:“=$A$1:$A$10”。 (“=”是必需的。如果您希望能够创建此单元格的副本,则 $s 很重要。)单击“确定”。

当用户将光标定位到该单元格时,他们可以输入允许的值,也可以从列表中选择允许的值。尝试输入任何其他值将导致错误消息。数据验证表单中的其他选项卡允许您输入帮助消息和您自己的错误消息。

由于源框中的 $s,您可以将原始单元格及其验证复制到其他单元格。

备选方案 2:条件格式

如果允许的值是一个范围,条件格式将满足您的要求。例如假设允许的范围是 10 到 20。

从工具栏中选择格式,然后选择条件格式。

显示条件 1 的框。 “Between”已经显示。在右侧的框中输入 10 和 20。

单击添加以显示条件 2 的框。用“小于”替换“之间”。在下一个框中输入 10。单击“格式”。单击“颜色”。选择“红色”。单击“确定”。

单击“添加”以显示条件 3 的框。将“介于”替换为“大于”。在下一个框中输入 20。单击“格式”。单击“颜色”。选择“红色”。单击“确定”。

单击“确定”接受条件格式。

用户可以在单元格中输入他们喜欢的任何内容,但除非在 10 到 20 之间,否则它将是红色的。

您可以创建任意数量的格式化单元格副本。

工作表更改事件

我早该想到事件。我相信这正是您想要的。

在 VBA 编辑器中,项目资源管理器通常在屏幕左侧可见。如果不是,请点击Ctrl+R

右键单击要控制选定值的工作表的行。点击View Code

代码区域的标题为工作表,否则为空白。您可以在该区域放置各种例程,但相关例程是工作表事件例程。每当发生诸如工作表激活或停用之类的事件时,将调用这些例程。您想要的事件是 Change ,每当用户更改单元格时都会调用它。这个套路的魅力在于它可以为所欲为。

将下面的 Worksheet_Change 例程复制并粘贴到工作表代码区域中。

它的参数是用户改变的单元格的地址。

TgtRngList 设置为您希望巡逻的范围列表。我已将其设置为 C1:C1000、F1:F1000 和 A1。您必须将其更改为您要巡逻的范围。

OKValueList 设置为巡查范围的允许值列表。它们可能在某个地方的工作表中,但我认为在这里定义它们更容易。将列表更改为您想要的任何内容。

代码检查更改的单元格是否位于巡逻区域之一。如果是,则检查它是否具有允许的值。该检查的结果会导致单元格设置为黑色或红色。

Option Explicit
Sub Worksheet_Change(ByVal ChangedCell As Range)

  ' This routine is called whenever the user changes a cell.
  ' It is not called if a cell is changed by Calculate

  Dim ColChanged As Integer
  Dim InxOV As Integer
  Dim InxTR As Integer
  Dim OKValueList() As Variant
  Dim Patrolled As Boolean
  Dim RowChanged As Integer
  Dim TgtColLeft As Integer
  Dim TgtColRight As Integer
  Dim TgtRngPartList() As String
  Dim TgtRngList() As Variant
  Dim TgtRngPart As String
  Dim TgtRowBottom As Integer
  Dim TgtRowTop As Integer
  Dim ValueChanged As String
  Dim ValueOK As Boolean

  ' Fill TgtRngList withe ranges that are to be patrolled by this routine
  TgtRngList = Array("C1:C1000", "F1:F1000", "A1")

  ' Fill OKValueList with the permitted values for these cells.
  OKValueList = Array("V1", "V2", "V3", "V4", "V5", _
                      "V6", "V7", "V8", "V9", "V10")

  ColChanged = ChangedCell.Column
  RowChanged = ChangedCell.Row

  Patrolled = False
  For InxTR = LBound(TgtRngList) To UBound(TgtRngList)
    TgtRngPartList = Split(TgtRngList(InxTR), ":")
    ' Decode top left of range
    TgtRngPart = TgtRngPartList(LBound(TgtRngPartList))
    TgtRowTop = Range(TgtRngPart).Row
    TgtColLeft = Range(TgtRngPart).Column
    If LBound(TgtRngPartList) = UBound(TgtRngPartList) Then
      ' There is no colon so single cell range
      TgtRowBottom = TgtRowTop
      TgtColRight = TgtColLeft
    Else
      TgtRngPart = TgtRngPartList(UBound(TgtRngPartList))
      TgtRowBottom = Range(TgtRngPart).Row
      TgtColRight = Range(TgtRngPart).Column
    End If
    If RowChanged >= TgtRowTop And RowChanged <= TgtRowBottom And _
       ColChanged >= TgtColLeft And ColChanged <= TgtColRight Then
      ' This is a patrolled cell
      Patrolled = True
      Exit For
    End If
  Next
  If Patrolled Then
    With ActiveSheet
      ValueChanged = .Cells(RowChanged, ColChanged).Value
      ' Check value against permitted list
      ValueOK = False
      For InxOV = LBound(OKValueList) To UBound(OKValueList)
        If ValueChanged = OKValueList(InxOV) Then
          ValueOK = True
          Exit For
        End If
      Next
      If ValueOK Then
        ' Set cell black
        .Cells(RowChanged, ColChanged).Font.Color = RGB(0, 0, 0)
      Else
        ' Set cell red
        .Cells(RowChanged, ColChanged).Font.Color = RGB(255, 0, 0)
      End If
    End With
  End If

End Sub

希望这会有所帮助。

【讨论】:

  • 确实我在代码中遗漏了一个括号。见上面的评论。目标是将输入(在本例中为valor)与一个范围(假设为A1:A10)进行比较。如果在 A3 中找到匹配项,该函数将返回 B3:C3 的值。如果找不到匹配项,我希望输出单元格改变颜色。这是真正的问题,更改颜色部分,而不是查找部分(可能编码错误)。很抱歉没有包含 If Then 部分。
  • 函数信息非常有帮助。下拉不是一个好的解决方案,但条件格式可能。如果返回#VALUE,我可以进行错误处理以分配一些奇怪的值,例如 10,000,000,然后按照您所说的使用条件格式。我仍然更喜欢 VBA 解决方案,这意味着创建一个由我的函数触发的宏,如您的回答中所述。
  • 我有了灵感。请参阅我的答案中的第三种选择。
  • 我一直很忙,没有时间检查您的灵感,但我会尽快检查。非常感谢您的宝贵时间。
  • 抱歉耽搁了。在假期和其他项目之间,我无法查看您的代码。你提议巡逻牢房的方式似乎很有趣。我接受它作为答案。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-15
  • 1970-01-01
相关资源
最近更新 更多