One of the best bits of Visio is the connections between shapes, but it has always been difficult to understand these connections in code. There are connections to and from shapes, which require you to understand where you are and which way to look … at the beginning or the end of a 1D connector. Visio 2010 has added some useful extra methods to the shape object which makes understanding connections much easier. This post will show you how you can use the new GluedShapes() and ConnectedShapes() methods.
Take, for example, a network diagram where there are connections between servers and routers:
You may wish to list the connections at the start and end of each cable. Previously, this would have meant inspecting the connected cell to see if was at the beginning or end of the line, but now you can use the GluedShapes() method of a shape to retrieve an array of the 2D shapes connected at one end or another with the relevant arguments, visGluedShapesIncoming2D or visGluedShapesOutgoing2D. The ListGluedConnections macro below displays the following in the immediate window:
Connector Dynamic connector
> Router.45 router-02
< Server server-01 Connector Dynamic connector.107 > Router.45 router-02
< Server.30 server-02 Connector Dynamic connector.108 > Router router-01
< Server.75 server-03 Connector Dynamic connector.109 > Router.91 router-03
< Server.30 server-02 Connector Dynamic connector.110 > Router.91 router-03
< Server server-01
Public Sub ListGluedConnections() Dim shp As Visio.Shape Dim connectorShape As Visio.Shape Dim sourceShape As Visio.Shape Dim targetShape As Visio.Shape Dim aryTargetIDs() As Long Dim arySourceIDs() As Long Dim targetID As Long Dim sourceID As Long Dim i As Integer For Each shp In Visio.ActivePage.Shapes If shp.OneD Then Debug.Print "Connector", shp.Name arySourceIDs = shp.GluedShapes(visGluedShapesIncoming2D, "") For i = 0 To UBound(arySourceIDs) Set sourceShape = Visio.ActivePage.Shapes.ItemFromID(arySourceIDs(i)) If sourceShape.CellExists("Prop.NetworkName", Visio.visExistsAnywhere) Then Debug.Print , ">", sourceShape.Name, sourceShape.Cells("Prop.NetworkName").ResultStr("") End If Next aryTargetIDs = shp.GluedShapes(visGluedShapesOutgoing2D, "") For i = 0 To UBound(aryTargetIDs) Set targetShape = Visio.ActivePage.Shapes.ItemFromID(aryTargetIDs(i)) If targetShape.CellExists("Prop.NetworkName", Visio.visExistsAnywhere) Then Debug.Print , "<", targetShape.Name, targetShape.Cells("Prop.NetworkName").ResultStr("") End If Next End If Next End Sub
Similarly, you may want to simply list the next connected 2D shape, effectively ignoring the cable. In this case, you can use the new ConnectedShapes() method, with the relevant arguments visGluedShapesIncoming2D or visGluedShapesOutgoing2D, to produce an output like the following ( using the ListNextConnections macro below):
Shape Server server-01
> Router.45 router-02
> Router.91 router-03
Shape Router router-01
< Server.75 server-03 Shape Server.30 server-02 > Router.45 router-02
> Router.91 router-03
Shape Router.45 router-02
< Server server-01
< Server.30 server-02 Shape Server.75 server-03 > Router router-01
Shape Router.91 router-03
< Server server-01
< Server.30 server-02
Public Sub ListNextConnections() Dim shp As Visio.Shape Dim connectorShape As Visio.Shape Dim sourceShape As Visio.Shape Dim targetShape As Visio.Shape Dim aryTargetIDs() As Long Dim arySourceIDs() As Long Dim targetID As Long Dim sourceID As Long Dim i As Integer For Each shp In Visio.ActivePage.Shapes If Not shp.OneD Then If shp.CellExists("Prop.NetworkName", Visio.visExistsAnywhere) Then Debug.Print "Shape", shp.Name, shp.Cells("Prop.NetworkName").ResultStr("") arySourceIDs = shp.ConnectedShapes(visConnectedShapesOutgoingNodes, "") For i = 0 To UBound(arySourceIDs) Set sourceShape = Visio.ActivePage.Shapes.ItemFromID(arySourceIDs(i)) If sourceShape.CellExists("Prop.NetworkName", Visio.visExistsAnywhere) Then Debug.Print , "<", sourceShape.Name, sourceShape.Cells("Prop.NetworkName").ResultStr("") End If Next aryTargetIDs = shp.ConnectedShapes(visConnectedShapesIncomingNodes, "") For i = 0 To UBound(aryTargetIDs) Set targetShape = Visio.ActivePage.Shapes.ItemFromID(aryTargetIDs(i)) If targetShape.CellExists("Prop.NetworkName", Visio.visExistsAnywhere) Then Debug.Print , ">", targetShape.Name, targetShape.Cells("Prop.NetworkName").ResultStr("") End If Next End If End If Next End Sub
I think this makes interrogation of connected diagrams, of all flavours, much simpler, though I would love to have similar ShapeSheet functions too!
Constantin says
Hi,
sorry but I cannot understand why the following code give us the SOURCE IDs and not the TARGET IDs?
> arySourceIDs = shp.ConnectedShapes(visConnectedShapesOutgoingNodes, “”)
I think, you asking the VISIO API for all the shapes, that are connected via outgoingnodes with shp.
Consider shp1 –> shp –> shp2
When I say shp.ConnectedShapes(visConnectedShapesOutgoingNodes, “”), then the method returns the shp2.ID thought? And shp2 is target and not source?
davidjpp says
Well, it’s been a while since I wrote this, but looking back at the code now, I think that you are correct – my Outgoing and Incoming could be the wrong way round.
Constantin says
Thank you for the answer, as a newsbie I wasn’t sure, whether I understand the Connectivity API methods.
I would besides this like to know am I right in a following considerations. If I want to convert a BPMN diagramm(created with Visio 2010 Premium BPMN) to a *.xpdl or *.bpmn file, I could do this with the following “utilities”:
– VISIO Connectivity API methods( e.g. iterating through shapes and query whether a shape is event, task or gateway)
– For each Shape –> Read Visio Shape Data Information from “Shape Data” Section. There are many additional informations like Prop.BpmnTaskType etc.
– of course I must first check, if the BPMN diagramm is correct, because it must have one start event and one end event etc., but I bought your book about VISIO Diagramm validation and this is a good reading
What do you think about my considerations, are they correct, or am I wrong?
Many thanks
Constantin
davidjpp says
I think that you could do as you intend …. provided all of the information that you need is stored in the Shape Data. In fact, I was a little surprised that an export wasn’t included for BPMN.
Constantin says
Maybe export will be included as soon as the BPMN xml format is stable/final and there are process engines processing the BPMN files.
I’m doing a little bit of trial and error winth VISIO 2010 and I have for example the following shapes:
Shape1->dragged as Task from BPMN Template,
Shape2->dragged as Task from BPMN Template. Then changed to Standard Loop Task(UI or right click context menu)
Shape3->dragged as Standard Loop Task from BPMN Template
When I try to get the shape.NameU, shape.Master.NameU and shape.MasterShape.NameU for each of theese shapes, I get for
Shape1: shape.NameU: Task, shape.Master.NameU: Task and shape.MasterShape.NameU: Sheet.5
Shape2: shape.NameU: Task.15, shape.Master.NameU: Task and shape.MasterShape.NameU: Sheet.5
Shape3: shape.NameU: Standard Loop Task, shape.Master.NameU: Standard Loop Task and shape.MasterShape.NameU: Sheet.5
Maybe I could get the index from Prop.BpmnLoopType Cell, but why Shape2 property is not changed to Standard Loop Task?
REIXACH says
Hi,
I am looking for a simple way to repport cabling in Visio without having to do it manually but also without macro’s programming (wich is the only way I found so far).
Specificly, I would like a “custom connector” that would automacticly identify which equipements it is connected to and put that info into the shape data fields.
I was hoping to use such feature to:
1. Schematically draw equipements in visio;
2. Connect equipements with this custom connector (with “connected shapes auto-reconition”);
3. Use visio built-in shape repport to genarate a cables listting.
Does any one know if a connector like that is at all possible?
and if so, where could I find such feature?
thankyou.
davidjpp says
It is not possible to do this without some code. In this article of mine, I use code to push the data into Shape Data values so that the Visio shape reports can be used.
https://blog.bvisual.net/2013/05/21/getting-the-name-of-glued-connection-points/
JP says
Hi David,
I am VBA newbie and I tried to run the code but no results are displayed.
Any help with what the issue might be?
David Parker says
Have you got the Immediate Window open?
JP says
No, when I run any macro I don’t get any result. I tried other pieces of code.
1) The file is .vsdm
2) Macro settings – Enable all macros (checked)
3) Trust access to the VBA project object model (checked)
Thanks,
JP
David Parker says
There are two properties for getting the text in a shape, depending upon whether there is inserted references:
1. shape.Text() …
2. shape.Characters.Text() …
In the ShapeSheet, the ShapeText(…) function has a few optional arguments …