Private Sub Worksheet_Change(ByVal Target As Range)
Static lngRow As Long
Dim rng1 As Range
Set rng1 = ThisWorkbook.Names("RowMarker").RefersToRange
If lngRow = 0 Then
lngRow = rng1.Row
Exit Sub
End If
If rng1.Row = lngRow Then Exit Sub
If rng1.Row < lngRow Then
MsgBox lngRow - rng1.Row & " rows removed"
Else
MsgBox rng1.Row - lngRow & " rows added"
End If
lngRow = rng1.Row
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim lNewRowCount As Long
ActiveSheet.UsedRange
lNewRowCount = ActiveSheet.UsedRange.Rows.Count
If lOldRowCount = lNewRowCount Then
ElseIf lOldRowCount > lNewRowCount Then
MsgBox ("Row Deleted")
lOldRowCount = lNewRowCount
ElseIf lOldRowCount < lNewRowCount Then
MsgBox ("Row Inserted")
lOldRowCount = lNewRowCount
End If
End Sub
在ThisWorkBook模块中添加以下内容:
Private Sub Workbook_Open()
ActiveSheet.UsedRange
lOldRowCount = ActiveSheet.UsedRange.Rows.Count
End Sub
Private usedRowsCount As Long 'use private to limit access to var outside of sheet
'Because select occurs before change we can record the current usable row count
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
usedRowsCount = Target.Worksheet.UsedRange.rows.count 'record current row count for row event detection
End Sub
'once row count recorded at selection we can compare the used row count after change occurs
'with the Target.Address we can also detect which row has been added or removed if you need to do further mods on that row
Private Sub Worksheet_Change(ByVal Target As Range)
If usedRowsCount < Target.Worksheet.UsedRange.rows.count Then
Debug.Print "Row Added: ", Target.Address
ElseIf usedRowsCount > Target.Worksheet.UsedRange.rows.count Then
Debug.Print "Row deleted: ", Target.Address
End If
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Target.Cells.Count = Cells.Columns.Count Then
MsgBox "Row added or deleted"
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Application.ScreenUpdating = False
Dim olr As Long, nlr As Long, olc As Long, nlc As Long
With Target.Parent.Cells
nlc = .Find(what:=Chr(42), after:=.Cells(1), LookIn:=xlValues, lookat:=xlPart, _
SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
nlr = .Find(what:=Chr(42), after:=.Cells(1), LookIn:=xlValues, lookat:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Application.Undo 'undo the last change event
olc = .Find(what:=Chr(42), after:=.Cells(1), LookIn:=xlValues, lookat:=xlPart, _
SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
olr = .Find(what:=Chr(42), after:=.Cells(1), LookIn:=xlValues, lookat:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Application.Repeat 'redo the last change event
End With
If nlr <> olr Or nlc <> olc Then
Select Case nlr
Case olr - 1
Debug.Print "One (1) row has been deleted"
Case Is < (olr - 1)
Debug.Print (olr - nlr) & " rows have been deleted"
Case olr + 1
Debug.Print "One (1) row has been inserted"
Case Is > (olr + 1)
Debug.Print (nlr - olr) & " rows have been inserted"
Case olr
Debug.Print "No rows have been deleted or inserted"
Case Else
'don't know what else could happen
End Select
Select Case nlc
Case olc - 1
Debug.Print "One (1) column has been deleted"
Case Is < (olc - 1)
Debug.Print (olc - nlc) & " columns have been deleted"
Case olc + 1
Debug.Print "One (1) column has been inserted"
Case Is > (olc + 1)
Debug.Print (nlc - olc) & " columns have been inserted"
Case olc
Debug.Print "No columns have been deleted or inserted"
Case Else
'don't know what else could happen
End Select
Else
'deal with standard Intersect(Target, Range) events here
End If
bm_Safe_Exit:
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Dim CurRowCnt as Double
CurRowCnt = Evaluate(Application.Names("CurRowCnt").RefersTo)
Select Case CurRowCnt
'' ########## ROW(S) ADDED
Case Is > ThisWorkbook.CustomDocumentProperties("RowCnt").Value
Dim r As Range
Dim NewRow as Range
ThisWorkbook.CustomDocumentProperties("RowCnt").Value = _
Evaluate(Application.Names("CurRowCnt").RefersTo)
For Each r In Selection.Rows.EntireRow
Set NewRow = Intersect(Application.Range("Table1"), r)
'Process new row(s) here
next r
'' ########## ROW(S) DELETED
Case Is < ThisWorkbook.CustomDocumentProperties("RowCnt").Value
ThisWorkbook.CustomDocumentProperties("RowCnt").Value = _
Evaluate(Application.Names("CurRowCnt").RefersTo)
'Process here
'' ########## CELL CHANGE
'Case Is = RowCnt
'Process here
'' ########## PROCESSING ERROR
Case Else 'Should happen only on error with CurRowCnt or RowCnt
'Error msg here
End Select
7条答案
按热度按时间pdsfdshx1#
您可以定义一个范围名称,如
RowMarker =$A$1000
然后,您的change事件上的代码将存储这个标记的位置,并报告任何更改(然后存储新的位置)
brgchamk2#
试试这个代码:
在ThisWorkBook模块中添加以下内容:
然后在它自己的模块中:
代码假定第1行中有数据。请注意,第一次运行它时会得到一个false结果,这是因为代码需要将lRowCount设置为正确的变量。一旦完成,从那时起就应该没事了。
如果你不想使用Public变量和工作表打开事件,那么你可以在工作表的某个地方使用一个命名范围,并在那里存储行计数(lRowCount)。
csga3l583#
在寻找了一点决定解决它自己。在工作表模块中(例如在VBA编辑器中的Microsoft Excel对象下的Sheet1)插入以下内容:
p1tboqfb4#
假设:“区分两者”意味着将添加/删除行与任何其他类型的更改区分开。如果你的意思是,如何判断更改是添加行还是删除行,那么忽略我下面的答案。
在插入或删除行的情况下,target.cells.count将是该行中的所有单元格。因此,您可以使用此If语句来捕获它。请注意,我使用cells.columns.count,因为它可能对每个文件都不同。如果用户选择整行并点击“delete”(删除值),它也会触发,所以你需要编写一个解决方案,尽管……
1mrurvl15#
区分插入和删除的一些最终目的将决定一旦识别出插入或删除后如何继续。以下内容可能会大幅减少,但我已经试图涵盖每一种可能的情况。
本质上,这段代码标识最后一个单元格的列方式和最后一个单元格的行方式。然后撤消最后一个操作并再次检查。比较两个结果允许它确定行/列是否已被插入/删除。完成四次测量后,它将重新执行最后一次操作,以便可以处理任何其他标准的Worksheet_Change操作。
rnmwe5a26#
有两种稍微不同的方法都基于下面的模板。
1.定义
Range
类型的模块或类模块变量。1.通过使用绝对地址将其分配给变量来“固定”特殊范围,并保存其地址或大小(取决于方法)。
1.若要确定用户操作的子类型,请在工作表更改事件处理程序中使用变量进行操作。
在第一种方法中,感兴趣的整个范围被分配给变量,并且范围的大小被保存。然后,在图纸更改事件处理程序中,必须处理以下情况:
Address
属性=>固定范围不再存在时发生异常;在第二种方法中,“标记”范围被分配给变量(参见下面的示例),并且范围地址被保存,以便 * 确定任何方向上的移动或移位 *。然后,在工作表更改事件处理程序中,必须处理以下情况:
Address
属性=>固定的“标记”范围不再存在时发生异常;abs(new_row - saved_row) > 0 or abs(new_col-saved_col) > 0
=>固定范围被移动或移位。优点:
UsedRange
属性缺点:
WithEvents
-变量分配给Nothing
,以便取消订阅事件。下面的示例显示了这两种方法都可以工作。在模块中定义:
然后运行
set_m_st
(只需将光标放在sub中并调用Run
action)以锁定范围$A$10:$F$10
。在其上方插入或删除行或单元格(不要与更改单元格值混淆)。运行get_m_st
查看固定范围的更改地址。删除固定的范围以获取get_m_st
中的“Object required”异常。sdnqo3pr7#
捕获worksheet_change事件中的行添加和删除。
我创建了一个命名范围,名为“CurRowCnt”;公式:= ROWS(表1)。使用以下命令在VBA代码中访问:
此命名范围将始终保存插入或删除行后的行数。我发现它提供了一个比使用全局或模块级变量更稳定的CurRowCnt,更适合编程、测试和调试。
我将CurRowCnt保存到一个自定义文档属性中,同样是出于稳定性的考虑。
我的Worksheet_Change事件结构如下: