我正在尝试获取Shape
中与Worksheet
相对应的ChartObject
的引用。我发现没有办法做到这一点。通过反复试验并在少数情况下进行简单测试的唯一近似假设ZOrder
的{{1}}与相应ChartObject
的索引相同:< / p>
Shape
(略微过量的定义变量用于调试目的)。
还有更确定的方法吗?
用于挑选正确的Function chobj2shape(ByRef cho As ChartObject) As Shape
' It appears that the ZOrder of a ChartObject is the same as the Index of
' the corresponding Shape, which in turn appears to be the same as its ZOrderPosition
Dim zo As Long
Dim ws As Worksheet
Dim shc As Shapes
Dim sh As Shape
zo = cho.ZOrder
Set ws = cho.Parent
Set shc = ws.Shapes
Set sh = shc.Item(zo)
Set chobj2shape = sh
'Set sh = Nothing
End Function
的任何标识符都应该是唯一的。该名称不一定是唯一的(请参阅https://stackoverflow.com/questions/19153331/duplicated-excel-chart-has-the-same-name-name-as-the-original-instead-of-increm),因此无法保证其有效。 Shape
/ Index
只是猜测,至少可以满足唯一性的要求。
修改:在Excel VBA: Index = ZOrderPosition in a Shapes collection?中查看@Andres的回答。很明显,ZOrderPosition
的{{1}}不等于ZOrder
或相应ChartObject
的{{1}}(我已经验证了这一点) 。
但似乎Index
等于相应ChartObject
的{{1}}。这已通过Shape
验证:
ZOrder
答案 0 :(得分:9)
在类似问题中丢失了几个小时后,我发现了几个与excel中引用形状相关的概念,但没有一个能让我满意100%。要访问形状,您有4种纯方法:
Shape.Name :快速,但不可靠。形状的名称可用于获取形状的引用,但前提是您没有重复的名称。代码:ActiveSheet.Shapes("Shape1")
Shape.ZOrderPosition :非常快,但不可靠。形状的ZOrder可用于获取形状的引用,因为它与形状集合中的形状的索引相同。但是,如果您没有违反先前规则的形状组(请参阅:https://stackoverflow.com/a/19163848/2843348)。代码:ActiveSheet.Shapes(ZOrderFromOneShape)
设置shpRef = Shape :FAST,RELIABLE,但不是PERSISTENT。我总是尽力使用它,特别是当我创建一个新形状时。此外,如果我必须稍后迭代新形状,我会尝试将对象引用保留在集合中。但是不是Persistent,这意味着如果你再次停止并运行VBA代码将会丢失所有引用和集合。代码:Set shp = NewShape
,或者您可以将其添加到集合中:coll.add NewShape
以便稍后循环播放。
Shape.ID :RELIABLE,PERSISTENT,但不直接支持!形状的ID非常可靠(不要更改,也不能重复工作表中的ID)。但是,没有直接的VBA功能可以知道其ID的形状。唯一的方法是遍历所有形状,直到ID与您要查找的ID匹配,但这可能非常慢!。
代码:
Function FindShapeByID(ws as excel.worksheet, ID as long) as Excel.Shape
dim i as long
set FindShapeByID = nothing 'Not found...
for i = 1 to ws.shapes.count
if ws.shapes(i).ID = ID then
set FindShapeByID = ws.shapes(i) 'Return the shape object
exit function
end if
next i
End Function
注1 :如果要多次访问此功能,可以使用Shape ID缓存来改进它。这样你只会循环一次。
注意2 :如果您将形状从一个工作表移动到另一个工作表,形状的ID将会改变!
通过混合和使用上述知识,我得出两个主要方法:
例如:
dim col as new Collection
dim shp as Excel.Shape
'' <- Insert the code here, where you create your shape or chart
col.add shp1
'' <- Make other stuffs
for each shp in col
'' <- make something with the shape in this loop!
next shp
问题当然是收集和参考不是永久性的。当你停止并重新启动vba代码时,你将松开它们!
这里是代码:
Function findShapeByNameAndID(ws As Excel.Worksheet, name As String, ID As Long) As Shape
Dim sh As Excel.Shape
Set findShapeByNameAndID = Nothing 'Means not found
On Error GoTo fastexit
Set sh = ws.Shapes(name)
'Now check if the ID matches
If sh.ID = ID Then
'Found! This should be the usual case!
Set findShapeByNameAndID = sh
Else
'Ups, not the right shape. We ha to make a loop!
Dim i As Long
For i = 1 To ws.Shapes.Count
If ws.Shapes(i).ID = ID Then
'Found! This should be the usual case!
Set findShapeByNameAndID = ws.Shapes(i)
End If
Next i
End If
fastexit:
Set sh = Nothing
End Function
希望这能帮到你!
注1:您是否要搜索可能在组内的形状,然后该功能更复杂。
注2:ZOrder看起来不错,但找不到它有用。当我试图利用它时,总会有一个缺失的部分......
答案 1 :(得分:-1)
我认为以下代码更合适也更正确。
Sub qTest()
Dim cho As ChartObject
Set cho = ActiveSheet.ChartObjects(1)
Dim SH As Shape
Set SH = cho.ShapeRange.Item(1)
SH.Select 'here Shape will be selected..
Debug.Print TypeName(SH) '...which we can check here
End Sub