Visio VBA:嵌套循环中的无效参数

时间:2013-08-13 22:58:24

标签: vba visio nested-loops visio-vba

在Microsoft Visio Professional 2010中,我已经分离了我在这个小代码片段中遇到的错误。在页面上是一个容纳2个形状的容器,我想在另一个循环中迭代这些形状。但是我一直收到无效的参数错误。

我对解决方案的尝试是顶部块,但它只适用于内部循环的相同定义。在外循环的第二次迭代中似乎有些东西在变化,但我不确定。我觉得它与定义For Each循环的方式有关。

Sub Nested_Loop_Error()

    Dim a As Variant
    Dim b As Variant
    Dim lngs() As Long

    'This Works
    lngs = ActiveDocument.Pages(1).Shapes.ItemFromID(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
    For a = 0 To 1
        For Each b In lngs
            'Do nothing
        Next b
    Next a


    'This does not work
    For a = 0 To 1
        For Each b In ActiveDocument.Pages(1).Shapes.ItemFromID(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
            MsgBox "In Loop for a=" & a
        Next b
    Next a

End Sub

编辑: 我一直在玩它并让它发挥作用,但我真正感兴趣的是它的工作原理。当a = 1时,第二个代码块失败,在docMyDoc.Pages行中给出一个无效参数......

以下是显示使用变量或文档变量在循环中定义ActiveDocument的区别的代码。使用调试器我无法看到docMyDoc或varMyDoc的定义方式有所不同。

Sub Nested_Loop_Error2()
    Dim a As Variant
    Dim b As Variant
    Dim docMyDoc As Visio.Document
    Dim varMyDoc As Variant

    'This works
    For a = 0 To 1
        Set varMyDoc = ActiveDocument
        For Each b In varMyDoc.Pages(1).Shapes.ItemFromID(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
            MsgBox "Using variant, a=" & a
        Next b
    Next a

    'This does not work
    For a = 0 To 1
        Set docMyDoc = ActiveDocument
        For Each b In docMyDoc.Pages(1).Shapes.ItemFromID(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
            MsgBox "Using document, a=" & a
        Next b
    Next a
End Sub

2 个答案:

答案 0 :(得分:1)

使用Variant类型对编译器没有多大帮助:名为“b”的变量应为Long类型,而“a”类型为Integer。

这就是说,你没有使用“a”变量,而是重复两次你在内循环中做的事情(Msgbox),但没有其他变化。

此外,您需要引用ID为b的形状,即您没有做的。

另一个提示:不要在类型之后命名变量,而是在它们的语义之后命名。

我认为你打算做的事情就像GetMemberShapes method's reference in MSDN中的例子:

Sub Nested_Loop()

    Dim lngMemberID as Long
    Dim vsoShape as Visio.Shape
    Dim j as Integer

    For j = 0 to 1
        For Each lngMemberID In ActiveDocument.Pages(1).Shapes(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
            Set vsoShape = ActivePage.Shapes.ItemFromID(memberID)
            Debug.Print vsoShape.ID
        Next lngMemberID
    Next j

 End Sub

在这里,你的vsoShape变量将首先引用一个,然后引用另一个形状。即使您的页面中有更多形状,它也会起作用。

这是Collections和For Each循环的好东西:集合是由其他对象列表组成的特殊对象。它们有自己的方法,如Item,Count和快捷方式,例如在括号之间使用数字从集合中检索单个对象(如Pages(1))。

您对For Each的处理方法是遍历集合中的所有对象(或数组中的所有值)。

出于您的目的,我将尝试以下一般结构:

dim oPage as Visio.Page
dim oShape as Visio.Shape
dim oInnerShape as Visio.Shape

For each oPage In ActiveDocument.Pages
  For each oShape in oPage.Shapes
      If oShape.Master.Name = "xxx" Then       ' You can check the type of the shape
          For each oInnerShape In oShape
             ' set and compute width and height
          Next oInnerShape
          ' set and compute width and height of the containing shape
       End If
  Next oShape
  ' Rearrange shapes
Next oPage

您可以构建一个存储形状ID,宽度和高度的数组,同时迭代形状,然后使用该数组重新排列形状。

此致

答案 1 :(得分:0)

我的计算机上没有Visio,但您确定第一个嵌套循环有效吗?

我怀疑lngs = ActiveDocument.Pages(1)... Dim lngs() As Long

Excel VBA会在尝试使用arr = Array(1,2)存储Dim arr() As Long时抛出“类型不匹配”错误。最好关闭Dim lngs As Variant,即使你知道它是一个Long返回的数组。

第二个嵌套循环在理论上起作用。