问题描述
有人可以告诉我以下代码是否针对 Excel VBA 进行了优化和正确,以便在单元格焦点上大写?
有时它会减慢 Excel 的速度。有没有更好的版本?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Range
Application.EnableEvents = False
For Each cell In Target
If IsEmpty(cell) Then
ElseIf cell.HasFormula = True Then
cell.Font.Name = "Arial Narrow"
cell.Font.Size = 9
Else
cell = UCase(cell)
cell.Font.Name = "Arial Narrow"
cell.Font.Size = 9
End If
Next
Application.EnableEvents = True
End Sub
解决方法
缩进不一致,重复的语句可以重新组织,不需要重复;不需要存在空代码块,将 Boolean
表达式与 Boolean
字面量进行比较的条件表达式是多余的,为了更清晰的代码,可以显式地进行隐式默认成员调用:
Application.EnableEvents = False
Dim cell As Range
For Each cell In Target
If Not IsEmpty(cell.Value) Then
If Not cell.HasFormula Then
cell.Value = UCase(cell.Value)
End If
cell.Font.Name = "Arial Narrow"
cell.Font.Size = 9
End If
Next
Application.EnableEvents = True
Rubberduck(免费,开源;我管理项目)可以帮助缩进,它的代码检查会警告空块(并建议反转条件)和隐式默认成员调用Range
(cell.Value
)。
至于性能,作为 Worksheet.Change
事件处理程序意味着每次修改任何单元格时,宏都会迭代每个修改过的单元格。大部分时间都是针对单个单元格的,因此循环大部分时间只迭代一次;您可能可以通过禁用 ScreenUpdating
并将 Calculation
模式设置为 xlCalculationManual
以及将 EnableEvents
设置为 True
来获得几毫秒的时间,但 IMO 的好处是将是微不足道的。
考虑使用样式而不是设置单个单元格的 Font.Name
和 Font.Size
,但这里最有影响力的修改是测试 Target
与特定特定有趣 {{ 1}} 个工作表上的单元格 - 例如,如果您只想在 Range
位于 Target
范围内时运行该循环,您可以将此测试作为宏执行的第一件事,以当修改的单元格超出该范围时,阻止执行任何代码:
A2:C25
请注意,If Application.Intersect(Target,Me.Range("A2:C25") Is Nothing Then
'modified cell isn't in A2:C25; bail out
Exit Sub
End If
事件处理程序不会“针对单元格焦点”运行,而是“针对单元格值/公式修改”运行;考虑处理 Worksheet.Change
,以便在单元格获取 Excel 的选择矩形时运行代码。