按行或列排列的 Excel 范围
Posted
技术标签:
【中文标题】按行或列排列的 Excel 范围【英文标题】:Excel range disposition by rows or columns 【发布时间】:2016-10-06 16:12:31 【问题描述】:Excel Range
类似乎有一个未记录的属性,它决定了 Item
、Cells
和 Count
属性的工作方式(很可能还有其他类方法和属性)。
普通的Range
s似乎有“细胞”的性格;即访问它们的属性需要一个 Cell 索引。
Set x = [A1:H50]
?TypeName(x)
Range
?x.Address
$A$1:$H$50
?x.Count
400
?x(20).Address
$D$3
但您也可以获得“列”或“行”配置的Range
,它们的行为不同。
Set x = [A1:H50].Columns
?TypeName(x)
Range
?x.Address
$A$1:$H$50
?x.Count
8
?x(20).Address
$T$1:$T$50
我正在尝试为Range
编写一个包装器类,它的行为将优于多Area
范围的内置类型。我想更好地了解这个范围“处置”是如何工作的。是否有内置属性或其他简单方法来测试 Range
对象的“处置”? “处置”是范围的不可变属性,还是有办法在不使用“行”、“列”或“单元格”属性获取新范围的情况下更改它?
【问题讨论】:
【参考方案1】:我什至不知道这种行为存在。我查看了 Range Object 的属性列表,但找不到任何可以满足您的包装器需求的东西。相反,我写了一个函数,我认为它可以告诉你“性格”,我称之为方向。
Function getOrientation(ByVal Rng As Range) As String
'If only one row, it's a column orientation
If Rng.Rows.Count = 1 Then
getOrientation = "Column"
Exit Function
End If
'If only one column, it's a row orientation
If Rng.Columns.Count = 1 Then
getOrientation = "Row"
Exit Function
End If
'If the cell count matches the expected cell count, it's Both
If Rng.Count = Rng.Columns.Count * Rng.Rows.Count Then
getOrientation = "Both"
ElseIf Rng.Count = Rng.Columns.Count Then
getOrientation = "Column"
Else
getOrientation = "Row"
End If
End Function
Sub Test()
'Testing
Debug.Print getOrientation(Range("A1:B100").Columns)
Debug.Print getOrientation(Range("A1:B100").Rows)
Debug.Print getOrientation(Range("A1:B100"))
Debug.Print getOrientation(Range("A1:A100"))
Debug.Print getOrientation(Range("A1:C1"))
End Sub
【讨论】:
这会因Range("A1:B2, C3:D5")
等多区域范围而失败。你也可以增强你的代码来处理这样的范围,但我认为@Tmdean 正在寻找的“真正”方式是一个新的Class
放置他需要的所有包装器的地方
是的,同意,更多的是如何分辨方向的示例。你班下面的指标在哪里?例如。当范围定义为 [A1:A100].Rows 时,Rng.Count 将返回行数,而不是列数。
没有指标属性,因为一旦您直接正确地循环遍历 Range 对象的 Areas 属性,我就不需要它。 ColumnsCount 属性只是一个示例;可以轻松添加类似的 RowsCount 以正确计算多区域范围的行数【参考方案2】:
其实MSDN documentation说
返回一个 Range 对象,该对象表示指定的列 范围
这意味着它返回一个Collection
的列,因此.Count
将返回集合元素的数量,即列的数量
但它也补充说:
当应用于作为多区域选择的 Range 对象时,此 属性仅从范围的第一个区域返回列。为了 例如,如果 Range 对象有两个区域——A1:B2 和 C3:D4—— Selection.Columns.Count 返回 2,而不是 4。
立即让路:
在可能包含多个区域的范围上使用此属性 选择,测试Areas.Count判断范围是否包含 不止一个领域。如果是,则循环遍历范围内的每个区域
因此需要一些包装器来增强Range
对象的默认成员
这将是extension methods
的完美空间,不幸的是,这在 VBA 中是不可能的
所以下一步应该是定义一个类
例如,您可以使用以下代码添加一个以“MyRange”命名的新类:
Option Explicit
Dim rng As Range
Public Property Set Range(r As Range)
Set rng = r
End Property
Public Property Get Range() As Range
Set Range = rng
End Property
Function ColumnsCount() As Long '<-- your personalized "Columns.Count" function correctly calculates the number of columns of your range
Dim area As Range
If rng Is Nothing Then Exit Function
For Each area In rng.Areas
ColumnsCount= ColumnsCount+ area.Columns.Count
Next area
End Function
您的代码将利用“MyRange”类如下
Option Explicit
Sub main()
Dim rng As Range ' "normal" range type
Dim myRng As MyRange ' your "personalized" range type
Set rng = Range("A1:B2, C3:D5") '<-- set a "normal range" object
Set myRng = New MyRange '<--| set your "personalized range" object
Set myRng.Range = rng '<-- give it the "normal" range as its "rng" property
MsgBox rng.Columns.Count '<-- this will return 2
MsgBox myRng.ColumnsCount '<-- this will return 4
End Sub
【讨论】:
这基本上是我最终要做的,除了我做了一些 VBA 的东西来使 MyRange 类实现一个默认属性、迭代器函数,并带有一个“处置”标志,以便它的行为就像内置 Range 类型,除了它支持多区域范围和我想要的一些其他功能。 很高兴能提供帮助。我实际上认为“处置”不是真实的,而“区域”属性是正确处理(和扩展)范围对象内置属性的关键。无论如何,您可能会发现“处置”是您进一步编码的有用抽象。您可能还想在Code Rewiew 中分享您的课程代码以进行增强。最后,由于我似乎已经回答了您的问题(这是关于更好地理解“列”属性的工作以及“处置”),您可能希望将此答案标记为已接受。谢谢。 我不明白你为什么认为这不是真实的东西......列和行的返回类型是“范围”;它不返回集合类型......它返回一个 Range,对于一些属性和方法,它的行为方式略有不同。 不是 “它返回一个行为方式略有不同的 Range”,因为对象必须以相同的方式行为。就是它“返回一个表示指定范围内的列的Range对象”和“当应用于一个多区域选择的Range对象时,这个属性只从第一个返回列范围的区域” 。所以这是.Columns
的行为方式,而不是 Range
对象。最重要的是,真正的事情是打扰/处理Range
对象的Areas
属性
考虑到 collection 是同一类的一组对象可能会有所帮助,例如 Worksheets
或 Workbooks
,并且集合本身就是一个对象,比如Worksheets
是Sheets
类型的对象(不是Collection
)。所以Selection
对象充当一个集合,它可能由Range
对象组成(Range
选择中的每个单元格都是一个Range
对象)。后一个示例与Range
对象的Columns
属性几乎相同:它返回一个特定 Range
选择,即您可以在其上的collection例如,调用Count
方法以上是关于按行或列排列的 Excel 范围的主要内容,如果未能解决你的问题,请参考以下文章
PyQt:QTableView + QSqlTableModel - 将所有选定的行或列复制并粘贴到记事本或 Excel 中