【问题标题】:How to detect changes in cell format?如何检测单元格格式的变化?
【发布时间】:2014-01-25 06:29:26
【问题描述】:

我想在 Excel 工作表中嵌入一个程序,该程序将检测单元格格式何时发生变化,例如从文本到数字。

但我不知道如何获取单元格的格式类型。我尝试使用Worksheet_Change事件处理程序来检查数据类型,如下:

Private Sub worksheet_change(ByVal Target As Range)

If Target.Address = "a1" Then
    If VarType(Target) <> 5 Then
        MsgBox "cell format has been changed"
    End If
End If


End Sub

但是有了这段代码,如果我将单元格 A1 的数据类型从数字更改为文本,Worksheet_Change 不会被触发;仅当我更改单元格的内容时才会调用事件处理程序。

此外,此过程可以检测内容是否从数字更改为字母字符串,例如从“35.12”到“abcd”,但不是数字类型数字到文本类型数字;如果我将单元格B1设置为文本,然后输入“40”,然后将单元格B1的内容粘贴到单元格A1中,vartype()仍然返回“5”,因此不会触发警报。

无论内容类型是否发生变化,我如何才能检测到格式是否发生了变化?

【问题讨论】:

  • 这些更改总是会通过用户与工作表的交互发生吗?您是否只对查找格式何时更改感兴趣(即您不关心其他格式更改)?

标签: vba excel


【解决方案1】:

好问题!

如果您只想在 NumberFormat 更改上触发事件(您似乎错误地将其称为数据格式,NumberFormat 是您想要的属性),以下是一个很好的示例。

我正在拦截所有选择更改事件并检查是否有任何 NumberFormat 更改。

Option Explicit

'keep track of the previous
Public m_numberFormatDictionary As New dictionary
Public m_previousRange As Range

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    'requires reference to Microsoft Scripting Runtime

    Dim c As Variant
    Dim wasChange As Boolean


    Debug.Print "***********************"

    'make sure you had a previous selection and it was initialized
    If m_numberFormatDictionary.Count > 0 And Not m_previousRange Is Nothing Then

        'Iterate through all your previous formattings and see if they are the same
        For Each c In m_previousRange
            Debug.Print "Found " & c.NumberFormat & " in " & c.Address
            Debug.Print "Stored value is " & m_numberFormatDictionary(c.Address) & " in " & c.Address

            'print out when they are different
            If c.NumberFormat <> m_numberFormatDictionary(c.Address) Then
                Debug.Print "~~~~~~ Different ~~~~~~"
                wasChange = True
            End If

        Next c
    End If

    'clear previous values
    m_numberFormatDictionary.RemoveAll

    'Make sure you don't error out Excel by checking a million things
    If Target.Cells.Count < 1000 Then

        'Add each cell format back into the previous formatting
        For Each c In Target
            Debug.Print "Adding " & c.NumberFormat & " to " & c.Address
            m_numberFormatDictionary.Add c.Address, c.NumberFormat
        Next c

        'reset the range to what you just selected
        Set m_previousRange = Target
    End If

    'simple prompt now, not sure what your use case is
    If wasChange Then
        MsgBox "There was at least one change!"
    End If

End Sub

我不确定您在寻找什么,您必须适当地修改 print/msgbox 语句。根据您的用例,您可能需要稍微修改一下,但它适用于我的所有测试示例。

【讨论】:

  • 非常聪明。我没有想过捕获选择动作来获取单元格的预更改状态。但是有一个大问题:如果我选择工作表中的所有单元格(我的用户肯定会这样做),Target.Cells.Count 会出现溢出错误。
  • 您可以使用CountLarge(但您仍然希望为要处理的单元格数量设置一些合理的上限)
【解决方案2】:

似乎没有在单元格格式类型更改时触发的事件。

但是,我从另一个论坛站点获得了此信息。

要在不使用宏的情况下编辑单元格格式,必须选择单元格(通过左键单击图标,或右键单击)。因此,使用工作表 SelectionChanged,无论何时选择一个单元格,您都可以获取该单元格的格式和地址,并检查前一个单元格的地址和格式 VS 前一个单元格的格式现在是什么。因此,如果前一个单元格的格式现在与上次捕获时的格式不同,则它已被更改。

您可以将此与更改事件结合使用,以查看从现在(在单元格内容更改后)到选择单元格时格式是否已更改。

这是另一个论坛的链接,因为我不能声称这是我自己的发明: http://www.mrexcel.com/forum/excel-questions/3704-calculate-format-change.html

【讨论】:

  • 此外,可以使用“Numberformat”属性获得单元格格式属性(文本、数字、货币等...)。例如表示“Number”的“NumberFormat”属性值为0.00,表示general的值为“General”,表示文本的值为“@”
【解决方案3】:

基于this response on StackOverflow,这里有一些可能对您有用的代码,假设更改将由用户生成,并且在他们进行更改后所选范围会发生变化...

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    Static LastRange As Range
    Static LastNumberFormat As String

    If Not LastRange Is Nothing Then
        If LastRange.Cells(1).NumberFormat <> LastNumberFormat Then
            'Your action or message box notification goes here
        End If
    End If

    Set LastRange = Target
    LastNumberFormat = Target.NumberFormat

End Sub

【讨论】:

    猜你喜欢
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多