0
votes

I want to glue a shape to another one via VBA. All the shapes are created with an UserForm Module. I want certain shapes to be connected with an arrow (which is also dropped on the page via an UserForm). It works fine connecting two shapes which are not in a group. Now I want to connect two shapes where one or both of them may be in a Group.

This works fine with non-grouped shapes

'get shp, src, aim
[...]
shp.Cells("BeginX").GlueTo src.Cells("PinX")
shp.Cells("EndX").GlueTo aim.Cells("PinX")

I get the aim and src Shapes using this function:

Function getShape(id As Integer, propName As String) As Shape
    Dim shp As Shape
    Dim subshp As Shape
    For Each shp In ActivePage.Shapes
        If shp.Type = 2 Then
            For Each subshp In shp.GroupItems
                If subshp.CellExistsU(propName, 0) Then
                    If subshp.CellsU(propName).ResultIU = id Then
                        Set getShape = subshp
                        Exit For
                    End If
                End If
            Next subshp
        End If

        If shp.CellExistsU(propName, 0) Then
            If shp.CellsU(propName).ResultIU = id Then
                Set getShape = shp
                Exit For
            End If
        End If
    Next
End Function

I think there is something wrong with how I iterate through the subshapes. Any help is appreciated.

2
Strange, at my side I haven't problems and differences. can you share code where you define connector-shape which connected aim and src shapes ?Surrogate
PS: for connect aim and src you want use connector or line ?Surrogate
My connector is a shape itself. I created a new master with a simple curved line. I think my problem must be in one of the for loops because when I look at the variables during execution, the one that should hold the shape that is in the group remains "Nothing" therefore the glue method fails.ksbawpn
Visio have special type of shapes named 'connector', read more about connectors in this article. My code works with connectorsSurrogate
Also, from the look of your code you're getting confused with Excel (and other Office) shapes. The rest of Office has a different structure and object model to Visio. (Note your wiseowl link in a previous question was also Excel based). So instead of foreach subshp in shp.GroupItems, it should be ...In shp.ShapesJohnGoldsmith

2 Answers

2
votes

Ah, @Surrogate beat me to it :) but since I've started writing...in addition to his answer, which shows nicely how to adapt the built in Dynamic connector here's a go with your group finding method + a custom connector.

The code assumes a few things:

  1. a page with two 2D shapes already dropped
  2. one of the shapes is a group shape containing a subshape with the correct Shape Data
  3. A custom master named 'MyConn' which is simple a 1D line with no other modifications

enter image description here

Public Sub TestConnect()
Dim shp As Visio.Shape 'connector
Dim src As Visio.Shape 'connect this
Dim aim As Visio.Shape 'to this

Dim vPag As Visio.Page
Set vPag = ActivePage

Set shp = vPag.Drop(ActiveDocument.Masters("MyConn"), 1, 1)
shp.CellsU("ObjType").FormulaU = 2
Set src = vPag.Shapes(1)

Set aim = getShape(7, "Prop.ID")

If Not aim Is Nothing Then
    shp.CellsU("BeginX").GlueTo src.CellsU("PinX")
    shp.CellsU("EndX").GlueTo aim.CellsU("PinX")
End If

End Sub


Function getShape(id As Integer, propName As String) As Shape
        Dim shp As Shape
        Dim subshp As Shape
        For Each shp In ActivePage.Shapes
            If shp.Type = 2 Then
                For Each subshp In shp.Shapes
                    If subshp.CellExistsU(propName, 0) Then
                        If subshp.CellsU(propName).ResultIU = id Then
                            Set getShape = subshp
                            Exit For
                        End If
                    End If
                Next subshp
            End If

            If shp.CellExistsU(propName, 0) Then
                If shp.CellsU(propName).ResultIU = id Then
                    Set getShape = shp
                    Exit For
                End If
            End If
        Next
    End Function

Note that if you read the docs for Cell.GlueTo, you'll see this item:

The pin of a 2-D shape (creates dynamic glue): The shape being glued from must be routable (ObjType includes visLOFlagsRoutable ) or have a dynamic glue type (GlueType includes visGlueTypeWalking ), and does not prohibit dynamic glue (GlueType does not include visGlueTypeNoWalking ). Gluing to PinX creates dynamic glue with a horizontal walking preference and gluing to PinY creates dynamic glue with a vertical walking preference.

and hence why I'm setting the ObjType cell to 2 (VisCellVals.visLOFlagsRoutable). Normally you'd set this in your master instance and so wouldn't need that line of code.

1
votes

Please try this code

Dim connector As Shape, src As Shape, aim As Shape
' add new connector (right-angle) to page
Set connector = Application.ActiveWindow.Page.Drop(Application.ConnectorToolDataObject, 0, 0)
' change Right-angle Connector to Curved Connector
connector.CellsSRC(visSectionObject, visRowShapeLayout, visSLOLineRouteExt).FormulaU = "2"
connector.CellsSRC(visSectionObject, visRowShapeLayout, visSLORouteStyle).FormulaU = "1"
Set src = Application.ActiveWindow.Page.Shapes.ItemFromID(4)
Set aim = Application.ActiveWindow.Page.Shapes.ItemFromID(2)
Dim vsoCell1 As Visio.Cell
Dim vsoCell2 As Visio.Cell
Set vsoCell1 = connector.CellsU("BeginX")
Set vsoCell2 = src.Cells("PinX")
vsoCell1.GlueTo vsoCell2
Set vsoCell1 = connector.CellsU("EndX")
Set vsoCell2 = aim.Cells("PinX")
vsoCell1.GlueTo vsoCell2