想要
Loop through multiple selection areas (r = 1 to n)
Delete rows in area r
Next area
注释
选择可以是不连续的,也可以是任何(垂直)顺序。即区域1可以是8-10行,区域2可以是2-3行,区域3可以是14-18行。所选单元格区域不应重叠以防止错误。
问题
在一个区域中执行行删除会导致下面的所有数据上移。下面的选定区域不会移动。因此,新数据(您不想删除)将滚动到选定区域。
示例
Row 1: A B C
Row 2: D E F (Select R2C1:R2C3 first)
Row 3: G H I
Row 4: J K L (CTRL Select R4C1:R4C3 next)
Row 5: M N O
已选择2个区域。我们希望删除第2行和第4行。
代码
For aCounter = 1 to Selection.Areas.Count
Selection.Areas(aCounter).EntireRow.Delete
Next
结果
Row 1: A B C
Row 2: G H I (This row is selected)
Row 3: J K L
Row 4: (blank) (This row is also selected)
Row 5: (blank)
发生了什么
选择的第一个区域(Areas(1))是第2行,已被删除。 3-5行汇总,但第2行仍保留在第4行。这意味着JKL进入第3行,而MNO进入第4行。在下一个循环中,Areas(2)仍设置为第4行,因此MNO为删除。
应该怎么办
Areas(2)应该已被删除的行数向上移动。
问题
有没有一种方法可以轻松地对此进行编码,而无需遍历所有区域,检查它们是否在已删除的行之下,以及每次删除一行时都将它们向上移动到已删除的行数上?
答案 0 :(得分:1)
从底部开始,并在上移时删除行。
例如:
<rich:dataTable value="#{capitalsBean.capitals}" var="cap" id="table">
<f:facet name="header">
<rich:columnGroup>
<rich:column>
<h:outputText value="State Name" />
</rich:column>
<rich:column>
<h:outputText value="State Time Zone" />
</rich:column>
<rich:column>
<h:outputText value="Marked" />
</rich:column>
</rich:columnGroup>
</f:facet>
<rich:column filter="#{filteringBean.stateFilter}">
<f:facet name="header">
<h:inputText value="#{filteringBean.stateFilterValue}" id="input">
<a4j:ajax event="keyup" render="table@body">
<a4j:attachQueue requestDelay="700"
ignoreDupResponses="true" />
</a4j:ajax>
</h:inputText>
</f:facet>
<h:outputText value="#{cap.state}" />
</rich:column>
<rich:column filterExpression="#{fn:containsIgnoreCase(cap.timeZone, filteringBean.zoneFilterValue)}">
<f:facet name="header">
<h:selectOneMenu value="#{filteringBean.zoneFilterValue}">
<f:selectItems value="#{filteringBean.zoneList}" />
<a4j:ajax event="change" render="table@body" />
</h:selectOneMenu>
</f:facet>
<h:outputText value="#{cap.timeZone}" />
</rich:column>
<rich:column>
<h:selectBooleanCheckbox value="#{filteringBean.marked}" disabled="false"/>
</rich:column>
答案 1 :(得分:1)
使用Union一次删除:(无重叠区域)
Sub try()
Dim MyRng As Range
For aCounter = 1 To Selection.Areas.Count
If Not MyRng Is Nothing Then
Set MyRng = Application.Union(MyRng, Selection.Areas(aCounter))
Else
Set MyRng = Selection.Areas(aCounter)
End If
Next
MyRng.EntireRow.Delete
End Sub
具有重叠的区域:
Sub try2()
Dim MyRng As Range, MyRow As Range
For aCounter = 1 To Selection.Areas.Count
If Not MyRng Is Nothing Then
For Each MyRow In Selection.Areas(aCounter).Rows
If Intersect(MyRow, MyRng) Is Nothing Then
Set MyRng = Application.Union(MyRng, MyRow)
End If
Next MyRow
Else
Set MyRng = Selection.Areas(aCounter)
End If
Next
MyRng.EntireRow.Delete
End Sub
答案 2 :(得分:1)
如果选择了多个区域,并且2行或更多行重叠,则VBA会引发重叠错误。要解决此问题,您必须手动进行合并并记录行(请确保不要记录重复的行)。
这是一个涉及使用System.Collections.ArrayList容器对象的解决方案。它不是标准VBA库的一部分。如果您不打算共享文件,则可以添加对\ WINDOWS \ Microsoft.NET \ Framework \ v4.0.30319 \ mscorlib.tlb或mscorlib.dll的引用。然后代码如下:
Dim col As New Collection
Dim i As Long, j As Long, r As Long
CreateObject ("System.Collections.ArrayList")
Dim alist As New ArrayList
For i = 1 To Selection.Areas.Count
For j = 1 To Selection.Areas(i).Rows.Count
r = Selection.Areas(i).Rows(j).Row
If Not alist.Contains(r) Then alist.Add r
Next
Next
alist.Sort
alist.Reverse
For i = 0 To alist.Count - 1
Rows(alist(i)).EntireRow.Delete
Next
这是创建一个ArrayList容器对象,然后针对每个区域检查该行是否已在列表中。如果没有,它将添加它。
这将创建一个行列表,这些行的顺序取决于选择区域的顺序。
ArrayList具有内置的.sort和.reverse方法以及也很方便的.contains方法。
现在,结果ArrayList包含要以相反顺序删除的行,因此您只需单步浏览列表并删除。此方法将解决重叠的选择区域问题。
除了@Evr用户的想法外,这是一个可移植的模块,用于处理不同列中重叠区域的情况:
Dim myrng As Range, arng As Range, offrng As Range
Dim acounter As Long
For acounter = 1 To Selection.Areas.Count
If Not myrng Is Nothing Then
Set arng = Selection.Areas(acounter)
Set offrng = arng.Offset(, -arng.Columns(1).Column + 1).Resize(, 1)
Set myrng = Application.Union(myrng, offrng)
Else
Set myrng = Selection.Areas(1).Offset(, -Selection.Areas(1).Columns(1).Column + 1).Resize(, 1)
End If
Next
myrng.EntireRow.Delete
这是它的工作方式:
第一个选定区域存储在myrng中,但它又返回到列A。因此,负列值+1的原因。例如,如果区域为$ D9:$ F12,我们将不在乎D到F列...我们只关心第9-12行。因此,我们抵消了范围。第一列是4,因此我们将-4 + 1 = -3偏移。结果范围为$ A9:$ F12。然后,resize命令将其返回到一列:$ A9:$ A12。
范围“ arng”是“区域”列表中的下一个选定范围。它也移回A列并调整大小。结果被放入offrng中。
然后将yrg与offrng合并,结果是一个范围内的唯一行地址数组,然后可以使用.EntireRow.Delete将其删除。