我有一些人,他们的工作时间通过他们自己列上的单元格中的条件格式显示 - 例如B7:B36,C7:C36,D7:D36等。我尝试将条件格式化单元格计数到列E.单元格中的最终结果是#Value(Arvo),但是当您按F9时,则可以显示数字。
当我逐步运行代码时,我注意到在“Range(”B6“,ws.Cells.SpecialCells(xlCellTypeLastCell))之后.ClearFormats程序跳转到函数”函数CountRed(MyRange As Range“并保持不变在循环中一段时间。
这是因为在单元格E6中有一个函数“CountRed(B6)+ CountGreen(C6)+ CountBlue(D6)”吗?
此外,我希望E栏中的列号集中在中央。
退出时间为空时出错:
结果出现错误:
结果应如下所示:
也可以找到原始代码here - 感谢Floris!
Option Explicit
Private Sub worksheet_change(ByVal target As Range)
If Not Intersect(target, Range("B4:Q4")) Is Nothing Then
'Sub makeTimeGraph()
Dim startRow As Long
Dim endRow As Long
Dim entryTimeRow As Long
Dim entryTimeFirstCol As Long
Dim Applicaton
Dim ws As Excel.Worksheet
Dim timeRange As Range
Dim c
Dim timeCols As Range
Dim entryTime
Dim exitTime
Dim formatRange As Excel.Range
Dim eps
eps = 0.000001 ' a very small number - to take care of rounding errors in lookup
Dim entryName
Dim Jim
Dim Mark
Dim Lisa
Dim nameCols As Range
' change these lines to match the layout of the spreadsheet
' first cell of time entries is B4 in this case:
entryTimeRow = 4
entryTimeFirstCol = 2
' time slots are in column A, starting in cell A6:
Set timeRange = Range("A6", [A6].End(xlDown))
' columns in which times were entered:
Set ws = ActiveSheet
Set timeCols = Range("B4:Q4") ' select all the columns you want here, but only one row
Set nameCols = Range("B3:Q3") ' columns where the names are in the third row
' clear previous formatting
Range("B6", ws.Cells.SpecialCells(xlCellTypeLastCell)).ClearFormats
Application.ScreenUpdating = False
' loop over each of the columns:
For Each c In timeCols.Cells
Application.StatusBar = entryName
If IsEmpty(c) Then GoTo nextColumn
entryTime = c.Value
exitTime = c.Offset(1, 0).Value
entryName = c.Offset(-1, 0).Value
startRow = Application.WorksheetFunction.Match(entryTime + eps, timeRange) + timeRange.Cells(1.1).Row - 1
endRow = Application.WorksheetFunction.Match(exitTime - eps, timeRange) + timeRange.Cells(1.1).Row - 1
Set formatRange = Range(ws.Cells(startRow, c.Column), ws.Cells(endRow, c.Column))
'select format range
formatRange.Select
' select name for coloring
Select Case entryName
Case "Jim"
Call formatTheRange1(formatRange) ' Red Colorinex 3
Case "Mark"
Call formatTheRange2(formatRange) ' Green Colorindex 4
Case "Lisa"
Call formatTheRange3(formatRange) ' Blue Colorindex 5
End Select
nextColumn:
Next c
End If
Range("A1").Activate
Application.ScreenUpdating = True
End Sub
Private Sub formatTheRange1(ByRef r As Excel.Range)
r.HorizontalAlignment = xlCenter
r.Merge
' Apply color red coloroindex 3
With r.Interior
.Pattern = xlSolid
.ColorIndex = 3
'.TintAndShade = 0.8
Selection.UnMerge
End With
End Sub
Private Sub formatTheRange2(ByRef r As Excel.Range)
r.HorizontalAlignment = xlCenter
r.Merge
' Apply color Green Colorindex 4
With r.Interior
.Pattern = xlSolid
.ColorIndex = 4
'.TintAndShade = 0.8
Selection.UnMerge
End With
End Sub
Private Sub formatTheRange3(ByRef r As Excel.Range)
r.HorizontalAlignment = xlCenter
r.Merge
' Apply color Blue Colorindex 5
With r.Interior
.Pattern = xlSolid
.ColorIndex = 5
'.TintAndShade = 0.8
Selection.UnMerge
End With
End Sub
Function CountRed(MyRange As Range)
Dim i As Integer
Application.Volatile
i = 0
For Each cell In MyRange
If cell.Interior.ColorIndex = 3 Then
i = i + 1
End If
Next cell
CountRed = i
End Function
Function CountGreen(MyRange As Range)
Dim i As Integer
Application.Volatile
i = 0
For Each cell In MyRange
If cell.Interior.ColorIndex = 4 Then
i = iCount + 1
End If
Next cell
CountGreen = i
End Function
Function CountBlue(MyRange As Range)
Dim i As Integer
Application.Volatile
i = 0
For Each cell In MyRange
If cell.Interior.ColorIndex = 5 Then
i = i + 1
End If
Next cell
CountBlue = i
End Function
答案 0 :(得分:0)
通过在#VALUE!(ARVO)
程序的末尾添加ws.Calculate
,可以解决Private Sub worksheet_change(ByVal target As Range)
错误。
那说,你想要的结果:
可以使用列B中的条件格式来完成:E列中的D和COUNTIFS函数。
在B栏中设置条件格式:
=AND(A6>=B$4,$A6<B$5)
您可以将条件格式复制到C列和D列,然后根据需要编辑其填充颜色。
在单元格E6中的公式:
=COUNTIFS(A6,">="&B$4,A6,"<"&B$5)
+COUNTIFS(A6,">="&C$4,A6,"<"&C$5)
+COUNTIFS(A6,">="&D$4,A6,"<"&D$5)
从B6向下复制到E,最后一行复制到F6; J6等。
完全不使用VBA,您将提高工作表的性能。通常最好在可能的情况下使用Excel功能和内置函数,并保留VBA来执行重复性任务,并创建UDF来计算使用内置函数无法完成的事情。
答案 1 :(得分:0)
Hyvääpäivää!这又是我...很高兴看到你继续改进你的代码。我做了一些调整,以使其更好地工作。特别是:
Target
的测试 - 因此当您更改开始时间和更改结束时间时,它都会更新。你只是在改变开始时间时做事。1
,与背景颜色相同(因此“不可见”) - 这是由格式化功能添加的SUM(B6:D6)
样式公式。这比检查左侧单元格中颜色的三个自定义函数要快得多......(从代码中删除了这些函数)1
;这是在每列循环中完成的(而不是一次完成)以在“每日”列中保留SUM()
公式。Dim Jim
等语句,因为您没有使用这些变量。既然代码正在修改工作表(通过添加不可见的单元来更改单元格中的值),则存在事情真正减慢的风险(每次更改都会导致事件再次触发) - 所以我关闭了事件当您进入该功能时,请在离开时再次打开它(分别使用Application.EnableEvents = False
或True
);为了安全起见,错误也被捕获(使用On Error GoTo whoops
) - 这些错误会将代码直接发送到代码的“启用事件和退出函数”部分。
据推测,您已经发现此代码需要存在于工作表代码中(而不是常规模块)才能正确接收事件。
这是新代码:
Option Explicit
Private Sub worksheet_change(ByVal target As Range)
On Error GoTo whoops
If Not Intersect(target, Range("B4:Q5")) Is Nothing Then
Dim startRow As Long
Dim endRow As Long
Dim entryTimeRow As Long
Dim entryTimeFirstCol As Long
Dim Applicaton
Dim ws As Excel.Worksheet
Dim timeRange As Range
Dim c
Dim timeCols As Range
Dim entryTime
Dim exitTime
Dim formatRange As Excel.Range
Dim eps
eps = 1e-06 ' a very small number - to take care of rounding errors in lookup
Dim entryName
Dim nameCols As Range
Application.ScreenUpdating = False
Application.EnableEvents = False
' change these lines to match the layout of the spreadsheet
' first cell of time entries is B4 in this case:
entryTimeRow = 4
entryTimeFirstCol = 2
' time slots are in column A, starting in cell A6:
Set timeRange = Range("A6", [A6].End(xlDown))
' columns in which times were entered:
Set ws = ActiveSheet
Set timeCols = Range("B4:Q4") ' select all the columns you want here, but only one row
Set nameCols = Range("B3:Q3") ' columns where the names are in the third row
' clear previous values and formatting
Range("B6", ws.Cells.SpecialCells(xlCellTypeLastCell)).clearFormats
' loop over each of the columns:
For Each c In timeCols.Cells
'Application.StatusBar = entryName
If IsEmpty(c) Then GoTo nextColumn
entryTime = c.Value
exitTime = c.Offset(1, 0).Value
entryName = c.Offset(-1, 0).Value
startRow = Application.WorksheetFunction.Match(entryTime + eps, timeRange) + timeRange.Cells(1.1).Row - 1
endRow = Application.WorksheetFunction.Match(exitTime - eps, timeRange) + timeRange.Cells(1.1).Row - 1
' get rid of any values currently in this row:
timeRange.Offset(0, c.Column - 1).Clear
Set formatRange = Range(ws.Cells(startRow, c.Column), ws.Cells(endRow, c.Column))
' select name for coloring
Select Case entryName
Case "Jim"
Call formatTheRange(formatRange, 3) ' Red Colorindex 3
Case "Mark"
Call formatTheRange(formatRange, 4) ' Green Colorindex 4
Case "Lisa"
Call formatTheRange(formatRange, 5) ' Blue Colorindex 5
End Select
nextColumn:
Next c
End If
whoops:
If Err.Number > 0 Then
MsgBox "error: " & Err.Description
Err.Clear
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Private Sub formatTheRange(ByRef r As Excel.Range, c)
Dim cc
' Apply color c
With r.Interior
.Pattern = xlSolid
.ColorIndex = c
End With
r.Font.ColorIndex = c
' put an invisible 1 in each cell:
For Each cc In r.Cells
cc.Value = 1
Next
End Sub
以下是事物的外观(只显示一组列 - 但这在多列版本中应该可以正常工作):
答案 2 :(得分:0)
我不是写宏的粉丝,除非你用尽了Excel的功能。不要通过ColorIndex攻击问题,而是返回数据源。在E6上使用此公式
{=SUM(($B$4:$D$4<=A6)*($B$5:$D$5>A6))}
请记住使用Ctrl + Shift + Enter启用数组功能,而不仅仅是Enter。粘贴下来,它将执行您的目标行为。