简体   繁体   English

检查Excel 2003数据验证

[英]Checking Excel 2003 data validation

The following bit of VBA will highlight any cells in a sheet with data validation errors: VBA的以下位将突出显示工作表中具有数据验证错误的所有单元格:

Sub CheckValidation(sht As Worksheet)
Dim cell As Range
Dim rngDV As Range
Dim dvError As Boolean

On Error Resume Next
Set rngDV = sht.UsedRange.SpecialCells(xlCellTypeAllValidation)
On Error GoTo 0

If rngDV Is Nothing Then
    sht.ClearCircles
Else
    dvError = False
    For Each cell In rngDV
        If Not cell.Validation.Value Then
            dvError = True
            Exit For
        End If
    Next

    If dvError Then
        sht.CircleInvalid
        sht.Activate
    Else
        sht.ClearCircles
    End If
End If
End Sub

However, the "For Each" loop runs really slowly in sheets with a lot of data validation. 但是,“ For Each”循环在带有大量数据验证的工作表中运行非常缓慢。

Does anyone know of a way to avoid the "For Each" loop, or speed it up somehow? 有谁知道避免“ For Each”循环或以某种方式加快循环速度的方法?

I would have thought that the following would be equivalent to set the value of 'dvError': 我以为以下内容等同于设置'dvError'的值:

dvError = Not rngDV.Validation.Value

But for some reason, rngDV.Validation.Value is true even when there are data validation errors. 但是由于某种原因,即使存在数据验证错误,rngDV.Validation.Value仍为true。

I had a slightly different requirement where I wanted to restrict the values entered by a user to a valid date range or the text "ASAP" which I resolved using the following; 我有一个稍微不同的要求,我想将用户输入的值限制为有效的日期范围或使用以下方法解决的文本“ ASAP”;

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim sErr        As String
    Dim sProc       As String

    On Error GoTo ErrHandler

    Application.EnableEvents = False

    Select Case Target.Column
    Case 11
        sProc = "Validate Date"

        'The value must be a date between "1 Nov 2011" and "30 Jun 2012" or "ASAP"...
        If IsDate(Target.Value) Then
            If Target.Value < CDate("2011-11-01") _
            Or Target.Value > CDate("2012-06-30") Then
                Err.Raise vbObjectError + 1
            End If
        ElseIf LCase(Target.Value) = "asap" Then
            Target.Value = "ASAP"
        ElseIf Len(Trim(Target.Value)) = 0 Then
            Target.Value = vbNullString
        Else
            Err.Raise vbObjectError + 1
        End If
    End Select

ErrHandler:
    Select Case Err.Number
    Case 0
        'Nothing to do...
    Case vbObjectError + 1
        sErr = "The Date must be between ""1 Nov 2011"" and ""30 Jun 2012"" or equal ""ASAP""."
    Case Else
        sErr = Err.Description
    End Select

    If Len(Trim(sErr)) > 0 Then
        Target.Select
        MsgBox sErr, vbInformation + vbOKOnly, sProc
        Target.Value = vbNullString
    End If

    Application.EnableEvents = True
End Sub

Tried your code and it's working quite fast with 4536 cells containing validations - as you are rightly breaking your FOR at the first occurence of an unvalidated cell 试过了您的代码,它可以与包含验证的4536个单元格一起快速运行-因为您在第一次出现未经验证的单元格时就正确地破坏了FOR

I tried to measure time at various points of your code by following: 我尝试通过以下方法在代码的各个点测量时间:

Dim Tick As Variant
Tick = Now()
' ... code
Debug.Print "ValCount", rngDV.Cells.Count ' just to see how many cells are in that range
' ... code
Debug.Print "Pt1",  (Now() - Tick) * 86400000 'display milliseconds
' ... code
Debug.Print "Pt2",  (Now() - Tick) * 86400000 'display milliseconds
' ... code
Debug.Print "Pt3",  (Now() - Tick) * 86400000 'display milliseconds
' etc.

and got a not measureable delay (except when stepping thru debugger with F8 - of course) 并得到了不可测量的延迟(当然,通过调试器使用F8时除外-当然)

As a generic hint ... try to find out where exactly your code is slow and let's take it from there. 作为一般提示...尝试找出您的代码到底在哪里慢,让我们从那里开始。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM