简体   繁体   English

VBA-优化UDF(单元格颜色计数器)

[英]VBA - Optimize UDF (Cell Color Counter)

I have a workbook with a main control sheet and 40-50 different data sheets that are copy/paste valued into the file from an external source (each sheet has anywhere from 30 to 500 rows and 10 to 100 columns with data). 我有一个工作簿,其中包含一个主控制表和40-50个不同的数据表,这些数据表可以从外部源复制/粘贴到文件中(每个表具有30至500行和10至100列的数据)。

The purpose of the workbook is to compare cells in various data sheet columns and highlight them if they fit a certain variance criteria; 该工作簿的目的是比较各个数据表列中的单元格,并突出显示它们是否符合特定的差异标准。 the highlighted cells on each data sheet are then counted and displayed on the main control sheet (using UDF formulas). 然后,对每个数据表上突出显示的单元格进行计数并显示在主控制表上(使用UDF公式)。

After reading the cpearson site, I realized that counting highlighted cells was nearly impossible if you used traditional conditional formatting... but I only figured this out after I had already written the custom CF code in VBA for 40+ sheets (this was done so that formatting could be removed or applied with a macro button after the data sheets had been "refreshed" using copy/paste). 阅读cpearson网站后,我意识到,如果您使用传统的条件格式,则对计数突出显示的单元进行计数几乎是不可能的……但是我只有在我已经用VBA编写了40多个工作表的自定义CF代码后才意识到这一点(这样做是在使用复制/粘贴“刷新”数据表后,可以删除格式或使用宏按钮应用格式)。

So after a nice long cry, I essentially recreated conditional formatting (again in VBA) using looping to achieve my goal. 因此,在长时间的哭泣之后,我基本上使用循环重新创建了条件格式(在VBA中也是),以实现我的目标。


Example criteria: 25% less than or greater than the cell value compared. 示例标准:小于或大于所比较的单元格值25%。

Example Data Sheet: 数据表示例:

[col 1] *** [col 2]
2014 *****2015
1 *********1.1
3 **********3
532 *******555
323 *******46 <<<this would Highlight
42 *******-112 <<<<this would highlight

(The highlighting would occur if cells in col 2 are either 25% greater or
 less than the cells in col 1 cell for the corresponding row.)

asterisks are only used for the purpose of spacing the two columns in this example

Example code: 示例代码:

Dim ref As WorksheetDim wkb As Workbook

Set wkb = ThisWorkbook
Set ref = ThisWorkbook.Sheets("Reference")
pn1 = ref.Range("E17").Value


With wkb.Sheets(pn1)
.Select

Set e1 = wkb.Sheets(pn1)

 For i = 7 To 53
 j = 2
 k = j + 8


    If e1.Cells(i, j).Value > 0 And IsNumeric(e1.Cells(i, j).Value) = True _
    Then If e1.Cells(i, j).Value > 1.25 * e1.Cells(i, k).Value _
Or e1.Cells(i, j).Value < 0.75 * e1.Cells(i, k).Value _
    Then e1.Cells(i, j).Interior.Color = RGB(252, 213, 181)


If e1.Cells(i, j).Value < 0 And IsNumeric(e1.Cells(i, j).Value) = True _
    Then If e1.Cells(i, j).Value < 1.25 * e1.Cells(i, k).Value _
Or e1.Cells(i, j).Value > 0.75 * e1.Cells(i, k).Value _
    Then e1.Cells(i, j).Interior.Color = RGB(252, 213, 181)

Next i

  ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

  For i = 7 To 53
  j = 2
  k = j + 9


If e1.Cells(i, j).Value > 0 And IsNumeric(e1.Cells(i, j).Value) = True _
    Then If e1.Cells(i, j).Value > 1.25 * e1.Cells(i, k).Value _
Or e1.Cells(i, j).Value < 0.75 * e1.Cells(i, k).Value _
    Then e1.Cells(i, j).Interior.Color = RGB(252, 213, 181)


If e1.Cells(i, j).Value < 0 And IsNumeric(e1.Cells(i, j).Value) = True _
    Then If e1.Cells(i, j).Value < 1.25 * e1.Cells(i, k).Value _
Or e1.Cells(i, j).Value > 0.75 * e1.Cells(i, k).Value _
    Then e1.Cells(i, j).Interior.Color = RGB(252, 213, 181)

Next i


End With

End Sub

(There are often blank columns between populated data columns and hidden rows scattered throughout the sheets) (填充的数据列和散布在工作表之间的隐藏行之间通常有空白列)

I then created a UDF to fit my counting needs: 然后,我创建了一个满足我的计数需求的UDF:

Function CountRed(MyRange As Range) As Integer                                       
'Application.Volatile                                                          
CountRed = 0                                                                    
For Each cell In MyRange                                                        
If Not cell.EntireRow.Hidden And cell.Interior.Color = RGB(252, 213, 181) 
CountRed = CountRed + 1                                                         
End If                                                                          
Next cell
End Function

I have two main issues: 我有两个主要问题:

  1. When the conditional formatting is applied, the cell displaying the UDF formula (=CountRed[WkshtName]{Range:Range}) does not automatically update; 应用条件格式时,显示UDF公式(= CountRed [WkshtName] {Range:Range})的单元格不会自动更新; this being the case even if "application.volatile" is active for the UDF and the workbook is set to automatic calculation. 即使UDF的“ application.volatile”处于活动状态并且工作簿设置为自动计算,情况也是如此。

  2. Speed. 速度。

With these two conditions in mind (application.volatile and automatic calculation), the highlighted cell count number (output of the UDF formula) will only update if I click one of the UDF formula cells and press F9 (or I can click the formula bar and press enter), but the bigger problem is that my workbook times out for a solid 4-5 minutes while it updates ALL of the UDF formulas on my page (this is my assumption based on quicker processing times with less UDF formulas on the page or smaller range criteria used in the UDF formulas). 考虑到这两个条件(application.volatile和自动计算),仅当我单击UDF公式单元格之一并按F9时,突出显示的单元格计数编号(UDF公式的输出)才会更新(或者我可以单击公式栏然后按Enter键),但是更大的问题是我的工作簿在更新页面上所有UDF公式的过程中稳定地停留了4-5分钟(这是我的假设,是基于更快的处理时间和页面上较少的UDF公式或UDF公式中使用的较小范围标准)。 *Turning off application.volatile and leaving automatic calculation on yields similar results. *关闭application.volatile并保留自动计算的结果。

To combat this I have turned OFF both automatic calculation and application.volatile (this seemingly has no effect either way). 为了解决这个问题,我同时关闭了自动计算和application.volatile(这似乎没有任何作用)。

I know this method will not allow for any type of automatic updating of the output UDF formula (highlighted cell count number), but the manual recalculation (F9 or formula "enter") of each UDF formula now only takes 5-10 seconds depending on the range size (it will also only update the cell you clicked on). 我知道此方法将不允许对输出UDF公式(突出显示的单元格计数编号)进行任何类型的自动更新,但是每个UDF公式的手动重新计算(F9或公式“输入”)现在仅需5-10秒,具体取决于范围大小(它也只会更新您单击的单元格)。

My main hiccup here occurs when I try and include a click button macro that forces an update of the whole page to eliminate the need for updating each UDF formula cell (ex. ThisWorkbook.Worksheets("Reference").Calculate), my calculation time then slows back down near the original updating times (3-4 minutes) and leaves me questioning if it is really that much faster after all. 当我尝试添加一个单击按钮宏来强制更新整个页面,从而无需更新每个UDF公式单元格时(例如ThisWorkbook.Worksheets(“ Reference”)。Calculate),这就是我的主要计算时间,这是我的计算时间然后将速度放慢到原始更新时间(3-4分钟)附近,然后让我怀疑这是否真的快得多。

All of that leads me to ask... 所有这些使我问...

Is there was any way to optimize or speed up the looping/processing time of my custom UDF? 有什么方法可以优化或加快自定义UDF的循环/处理时间?

Automatic updating would be icing on the cake, but if I have to force a manual recalculation then I would love for it to be as fast as possible. 自动更新将为您锦上添花,但是如果我必须强制执行手动重新计算,那么我希望它能尽快实现。


Please let me know if I need to clarify anything, or take screen shots of my workbook/code (I apologize in advance if my explanation is fairly convoluted; I have been using VBA for a limited time and am certainly still a novice). 请让我知道是否需要澄清任何内容,或者为我的工作簿/代码拍摄屏幕快照(如果我的解释相当复杂,我会先道歉;我在有限的时间内一直在使用VBA,并且肯定仍然是新手)。

Note: I am using Excel 2007. 注意:我正在使用Excel 2007。

THANK YOU IN ADVANCE !! 先感谢您 !!

Your code is slow because you refer to Excel to check each cell in the range. 您的代码很慢,因为您引用Excel来检查范围内的每个单元格。 The most efficient way would be to load the used range into VBA memory and working with those arrays - check this set of articles - it's extremely useful and well written https://fastexcel.wordpress.com/making-your-vba-udfs-efficient/ 最有效的方法是将使用的范围加载到VBA内存中并使用这些数组-检查这组文章-这是非常有用且写得很好的https://fastexcel.wordpress.com/making-your-vba-udfs-高效/

Also for faster calculation - you can calculate a range of the worksheet, no need to recalc all sheet. 同样,为了更快地计算-您可以计算工作表的范围,而无需重新计算所有工作表。

Hope this helps 希望这可以帮助

You can keep a count of the colored cells as you color them, then use that value, instead of counting the colored cells in a separate operation. 您可以在对有色单元进行着色时对其进行计数,然后使用该值,而不是在单独的操作中对有色单元进行计数。

Sub DoColors()

    Dim ref As Worksheet, e1 As Worksheet
    Dim wkb As Workbook, pn1
    Dim rw As Range, i As Long, j As Long, n As Long, v, v2, v3

    Set wkb = ThisWorkbook
    Set ref = wkb.Sheets("Reference")
    pn1 = ref.Range("E17").Value

    Set e1 = wkb.Sheets(pn1)

    j = 2
    n = 0
    For i = 7 To 53

        Set rw = e1.Rows(i)

        v = rw.Cells(j).Value

        If IsNumeric(v) And v > 0 Then

            v2 = rw.Cells(j + 8).Value
            v3 = rw.Cells(j + 9).Value

            If Abs(v - v2) / v2 > 0.25 Or Abs(v - v3) / v3 > 0.25 Then
                rw.Cells(j).Interior.Color = RGB(252, 213, 181)
                n = n + 1
            End If

        End If
    Next i

    'put n somewhere...

End Sub

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

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