How to tell if a Connection Point is connected

Started by arnold006287, March 04, 2024, 07:00:10 PM

Previous topic - Next topic

0 Members and 3 Guests are viewing this topic.

arnold006287

Hi there,
Hoping to find some help, I have a rectangular shape with connection points on either side of it and text in the middle. I am struggling to find any information on how to tell, within the ShapeSheet, whether a connection point has a connector connected to it. Ideally, I would like to be able to tell whether a connector is connected to connection points Connections.A or Connections.B and then change the horizontal alignment of the text accordingly. I'm fairly certain that, if this is something accessible from the ShapeSheet, that would be the easiest route - I have some custom C programming but would prefer this to be automated and not require any clicking to adjust the alignment. I'm hoping it's just a simple attribute that I'm missing.

Thanks in advance for any and all help with this!

Yacine

The object connecting to another has some information about the connection. The object connected from hasn't. So basically you could use the connector, not the rectangle.
But even this information is not trivial to extract.
I recommend using code (VBA or C#)
The are lots of posts to this subject. From memory some are from our host Visio Guy, but Wapperdude has also done a lot.
Yacine

Thomas Winkel

#2
Hi,

This is not possible with ShapeSheet.
Thus, automation must be done with code.
You could trigger the code from ShapeSheet cell "EventXFMod" in the connector or listen to Page.ShapeAddded/Changed events.

I guess what Yacine means is:
Only the connector knows to / from what cell it is connected.
And this is required to identify the glued connection points (Top, Bot, Left, Right).
From a rectangle you can only get the connector and the other rectangle, but not the connection point.

Here some demo code for your experiments.
* Add a rectangle
* Add connection points to each side
* Open the ShapeSheet and give the connection points row names: Top, Bot, Left, Right
* Copy the rectangle
* Connect both rectangles
* Select a rectangle and run StartFromShape()
* Select the connector and run StartFromConnector()
* See results in Immediate window


Public Sub StartFromShape()
    Dim pge As Visio.Page
    Dim shpSelected As Visio.Shape
    Dim shp As Visio.Shape
    Dim iDs() As Long
    Dim i As Integer
   
    Set pge = ActivePage
    Set shpSelected = ActiveWindow.Selection.PrimaryItem
   
    iDs = shpSelected.GluedShapes(visGluedShapesAll1D, "")
    For i = 0 To UBound(iDs)
        Set shp = pge.Shapes.ItemFromID(iDs(i))
        Debug.Print shp.Name
    Next
   
    iDs = shpSelected.ConnectedShapes(visConnectedShapesAllNodes, "")
    For i = 0 To UBound(iDs)
        Set shp = pge.Shapes.ItemFromID(iDs(i))
        Debug.Print shp.Name
    Next
End Sub

Sub StartFromConnector()
    Dim shp As Shape
    Dim con As Connect
   
    Set shp = ActiveWindow.Selection.PrimaryItem
   
    For Each con In shp.Connects
        Debug.Print con.ToSheet.Name & " -> " & con.ToCell.RowName
    Next con
End Sub

arnold006287

Quote from: Yacine on March 04, 2024, 08:48:48 PM
The object connecting to another has some information about the connection. The object connected from hasn't. So basically you could use the connector, not the rectangle.
But even this information is not trivial to extract.
I recommend using code (VBA or C#)
The are lots of posts to this subject. From memory some are from our host Visio Guy, but Wapperdude has also done a lot.

Thank you! I will look into them, I appreciate the suggestion on an alternative way to accomplish this, I'll look at that route too

arnold006287

Quote from: Thomas Winkel on March 04, 2024, 09:45:32 PM
Hi,

This is not possible with ShapeSheet.
Thus, automation must be done with code.
You could trigger the code from ShapeSheet cell "EventXFMod" in the connector or listen to Page.ShapeAddded/Changed events.

I guess what Yacine means is:
Only the connector knows to / from what cell it is connected.
And this is required to identify the glued connection points (Top, Bot, Left, Right).
From a rectangle you can only get the connector and the other rectangle, but not the connection point.

Here some demo code for your experiments.
* Add a rectangle
* Add connection points to each side
* Open the ShapeSheet and give the connection points row names: Top, Bot, Left, Right
* Copy the rectangle
* Connect both rectangles
* Select a rectangle and run StartFromShape()
* Select the connector and run StartFromConnector()
* See results in Immediate window


Public Sub StartFromShape()
    Dim pge As Visio.Page
    Dim shpSelected As Visio.Shape
    Dim shp As Visio.Shape
    Dim iDs() As Long
    Dim i As Integer
   
    Set pge = ActivePage
    Set shpSelected = ActiveWindow.Selection.PrimaryItem
   
    iDs = shpSelected.GluedShapes(visGluedShapesAll1D, "")
    For i = 0 To UBound(iDs)
        Set shp = pge.Shapes.ItemFromID(iDs(i))
        Debug.Print shp.Name
    Next
   
    iDs = shpSelected.ConnectedShapes(visConnectedShapesAllNodes, "")
    For i = 0 To UBound(iDs)
        Set shp = pge.Shapes.ItemFromID(iDs(i))
        Debug.Print shp.Name
    Next
End Sub

Sub StartFromConnector()
    Dim shp As Shape
    Dim con As Connect
   
    Set shp = ActiveWindow.Selection.PrimaryItem
   
    For Each con In shp.Connects
        Debug.Print con.ToSheet.Name & " -> " & con.ToCell.RowName
    Next con
End Sub


Thanks a ton, this was super helpful to envision what you were thinking - just so I'm following your StartFromShape() Sub, does that actually look for the connected shape? So if I were to connect shape B to shape A and select shape A, running StartFromShape(), it would print out Shape B, is that right?

wapperdude

You may find this interesting/helpful...
http://visguy.com/vgforum/index.php?topic=8701.msg38015#msg38015

Other related links:
http://visguy.com/vgforum/index.php?topic=8912.msg39138#msg39138
http://visguy.com/vgforum/index.php?topic=10263.msg47877#msg47877
http://visguy.com/vgforum/index.php?topic=5844.msg23444#msg23444



Visio connectivity background:  connectivity information is contained in the connectors.  It is not contained in the shapes glued to the connector ends.  Connectivity information is not provided in any shapesheet.  Such information must be extracted using code.  Depending upon needs, connectivity can determine if connector is fully connected, has a floating end, what shapes are connected to it (thus, to each other), and what connection points are involved (and info about each point).

Visio 2019 Pro

Thomas Winkel

StartFromShape() returns both:
* The first for loop all glued connectors
* The second for loop all connected rectangles

For your application you will need StartFromConnector() to get the connection point information.

Hope the code in the attached document makes it more clear.

arnold006287

Quote from: wapperdude on March 05, 2024, 07:39:53 PM
You may find this interesting/helpful...
http://visguy.com/vgforum/index.php?topic=8701.msg38015#msg38015

Other related links:
http://visguy.com/vgforum/index.php?topic=8912.msg39138#msg39138
http://visguy.com/vgforum/index.php?topic=10263.msg47877#msg47877
http://visguy.com/vgforum/index.php?topic=5844.msg23444#msg23444



Visio connectivity background:  connectivity information is contained in the connectors.  It is not contained in the shapes glued to the connector ends.  Connectivity information is not provided in any shapesheet.  Such information must be extracted using code.  Depending upon needs, connectivity can determine if connector is fully connected, has a floating end, what shapes are connected to it (thus, to each other), and what connection points are involved (and info about each point).

That sums things up perfectly, great info, thank you

wapperdude

#8
Thomas' code has nice clean features, and is focused upon either a single selected shape or connector.

I drew from his code, and modified the above 1st referenced link, to provide additional, useful connector information.  The code shows all connectors and attached shapes.  It now includes any text, the connector row identity. 

Attached is his file, updated. 

For convenience, here's the code:

Public Sub ListGluedConnections()
'Code lists shapes attached to connectors on a page
'Original code developed by David Parker
'Code located @ https://blog.bvisual.net/2009/09/16/listing-connections-in-visio-2010/
'Minor code modification by Wapperdude, 2/4/2019
'Additional code changes based upon Thomas Winkel; http://visguy.com/vgforum/index.php?topic=10308.msg48165#msg48165
'Code 1st lists connector, then shows, if any, incoming and outgoing shapes
'
    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
    Dim vCon As Connect
    Dim typeSkip As Boolean
   
    typeSkip = False
   
    For Each shp In Visio.ActivePage.Shapes
        If shp.OneD Then
            For Each vCon In shp.Connects
                If Not typeSkip Then
                    Debug.Print "Connector", shp.Name, shp.Text, vCon.ToCell.RowName
                    arySourceIDs = shp.GluedShapes(visGluedShapesIncoming2D, "")
                    For i = 0 To UBound(arySourceIDs)
                        Set sourceShape = Visio.ActivePage.Shapes.ItemFromID(arySourceIDs(i))
                        Debug.Print "Src Shp: ", sourceShape.Name, sourceShape.Text
                        typeSkip = True
                    Next
                Else
                    If shp.Connects.Count < 2 Then
                        Debug.Print "Connector", shp.Name, shp.Text, vCon.ToCell.RowName
                    End If
                    aryTargetIDs = shp.GluedShapes(visGluedShapesOutgoing2D, "")
                    For i = 0 To UBound(aryTargetIDs)
                        Set targetShape = Visio.ActivePage.Shapes.ItemFromID(aryTargetIDs(i))
                        Debug.Print "Tgt Shp: ", targetShape.Name, targetShape.Text
                        typeSkip = False
                    Next
                End If
            Next
        Debug.Print ""
        End If
  Next
End Sub

Visio 2019 Pro

arnold006287

Quote from: Thomas Winkel on March 05, 2024, 07:51:44 PM
StartFromShape() returns both:
* The first for loop all glued connectors
* The second for loop all connected rectangles

For your application you will need StartFromConnector() to get the connection point information.

Hope the code in the attached document makes it more clear.

Thanks Thomas, I appreciate you putting that into a file for me, that really does make it a whole lot clearer - this leads me to think that while I can't do what I originally intended on hoping to do, I might be able to use the concepts you have in your code for something... I'm just not quite sure what yet lol might have to sleep on it a couple of nights to see.

Thanks again for all of the help!

arnold006287

Quote from: wapperdude on March 06, 2024, 05:42:14 PM
Thomas' code has nice clean features, and is focused upon either a single selected shape or connector.

I drew from his code, and modified the above 1st referenced link, to provide additional, useful connector information.  The code shows all connectors and attached shapes.  It now includes any text, the connector row identity. 

Attached is his file, updated. 

For convenience, here's the code:

Public Sub ListGluedConnections()
'Code lists shapes attached to connectors on a page
'Original code developed by David Parker
'Code located @ https://blog.bvisual.net/2009/09/16/listing-connections-in-visio-2010/
'Minor code modification by Wapperdude, 2/4/2019
'Additional code changes based upon Thomas Winkel; http://visguy.com/vgforum/index.php?topic=10308.msg48165#msg48165
'Code 1st lists connector, then shows, if any, incoming and outgoing shapes
'
    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
    Dim vCon As Connect
    Dim typeSkip As Boolean
   
    typeSkip = False
   
    For Each shp In Visio.ActivePage.Shapes
        If shp.OneD Then
            For Each vCon In shp.Connects
                If Not typeSkip Then
                    Debug.Print "Connector", shp.Name, shp.Text, vCon.ToCell.RowName
                    arySourceIDs = shp.GluedShapes(visGluedShapesIncoming2D, "")
                    For i = 0 To UBound(arySourceIDs)
                        Set sourceShape = Visio.ActivePage.Shapes.ItemFromID(arySourceIDs(i))
                        Debug.Print "Src Shp: ", sourceShape.Name, sourceShape.Text
                        typeSkip = True
                    Next
                Else
                    If shp.Connects.Count < 2 Then
                        Debug.Print "Connector", shp.Name, shp.Text, vCon.ToCell.RowName
                    End If
                    aryTargetIDs = shp.GluedShapes(visGluedShapesOutgoing2D, "")
                    For i = 0 To UBound(aryTargetIDs)
                        Set targetShape = Visio.ActivePage.Shapes.ItemFromID(aryTargetIDs(i))
                        Debug.Print "Tgt Shp: ", targetShape.Name, targetShape.Text
                        typeSkip = False
                    Next
                End If
            Next
        Debug.Print ""
        End If
  Next
End Sub



This is slick, I think it's similar to the code you had in the other post, thanks for hooking me up with the file - just so I can understand, what is the line
For i = 0 To UBound(aryTargetIDs)
doing?

wapperdude

#11
Before I answer your question, note that connectors may have 0, 1, or 2 connections.  When VBA loops through a connector, it will get listed twice.  Kinda annoying.  Hence, the typeSkip parameter.  Of course, that forces the code to handle special cases and things get a bet messy.  That's a nice feature about Thomas' approach and not using glued shape construct.

But, now to your question.  The preceding line, fills a 1 dimensional array with attached shapeIDs.  The next line, your question, then steps thru these shapeIDs.  This allows locating attachment points of both ends.

The code examines 1D shapes.  These may be connectors or lines.  It then checks for incoming (source) shapes, prints results. Loops thru, finds outgoint (target) shapes.  Prints results, but doesn't duplicate printing the connector info.

A connector that only has 1 attached shape, may either be incoming or outgoing, hence, a special case for the code.

I did clean the code a smidge, and added  a few more test conditions in the attached file.  Note, gluing connector to connector still fails.


Public Sub ListGluedConnections()
'Code lists shapes attached to connectors on a page
'Original code developed by David Parker
'Code located @ https://blog.bvisual.net/2009/09/16/listing-connections-in-visio-2010/
'Minor code modification by Wapperdude, 2/4/2019
'Additional code changes based upon Thomas Winkel; http://visguy.com/vgforum/index.php?topic=10308.msg48165#msg48165
'Code 1st lists connector, then shows, if any, incoming and outgoing shapes
'
    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
    Dim vCon As Connect
    Dim typeSkip As Boolean
   
    typeSkip = False
   
    For Each shp In Visio.ActivePage.Shapes
        If shp.OneD Then
            For Each vCon In shp.Connects
                If Not typeSkip Then
                    Debug.Print "Connector", shp.Name, shp.Text
                    arySourceIDs = shp.GluedShapes(visGluedShapesIncoming2D, "")
                    For i = 0 To UBound(arySourceIDs)
                        Set sourceShape = Visio.ActivePage.Shapes.ItemFromID(arySourceIDs(i))
                        Debug.Print "Src Shp: ", sourceShape.Name, sourceShape.Text, vCon.ToCell.RowName
                        typeSkip = True
                    Next
                Else
                    If shp.Connects.Count < 2 Then
                        Debug.Print "Connector", shp.Name, shp.Text
                    End If
                    aryTargetIDs = shp.GluedShapes(visGluedShapesOutgoing2D, "")
                    For i = 0 To UBound(aryTargetIDs)
                        Set targetShape = Visio.ActivePage.Shapes.ItemFromID(aryTargetIDs(i))
                        Debug.Print "Tgt Shp: ", targetShape.Name, targetShape.Text, vCon.ToCell.RowName
                        typeSkip = False
                    Next
                End If
            Next
        Debug.Print ""
        End If
  Next
End Sub

Visio 2019 Pro

wapperdude

Well, decided to see if there was a more efficient form for the code.  Turns out yes.  This is major update to last posted reply:

Public Sub ListGluedConnections()
'Code 1st lists connector, then shows, if any, incoming and outgoing shapes
'
    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
    Dim vCon As Connect
    Dim typeSkip As Boolean
   
    typeSkip = False
   
    For Each shp In Visio.ActivePage.Shapes
        If shp.OneD Then
            For Each vCon In shp.Connects
                If Not typeSkip Then
                    Debug.Print "Connector:"; shp.Name, shp.Text 'vCon.FromSheet, vCon.FromSheet.Text
                    Debug.Print vCon.ToSheet.Text, vCon.ToCell.RowName
                    typeSkip = True
                Else
                    If shp.Connects.Count < 2 Then
                        Debug.Print "Connector", shp.Name, shp.Text
                    End If
                    Debug.Print vCon.ToSheet.Text, vCon.ToCell.RowName
                    typeSkip = False
                End If
            Next
        Debug.Print ""
        End If
    Next
End Sub
Visio 2019 Pro

Thomas Winkel

#13
Wow, this thread is becoming a real connector knowledge base 8)

But, coming back to the original question this is really simple using the techniques described above.
See attached document.

Comments:
* Code triggered from ShapeSheet cell "EventXFMod" in the connector
-> Thus the connector shapes must be prepared. This proceeding may be helpful:
     https://support.microsoft.com/en-us/office/create-a-custom-connector-48f47591-b9d5-4e6f-9203-5b34ce09a5e9
* Used Macro Recorder to quickly find the align code.
* Avoid Code in Documents, better store it central in a stencil.

wapperdude

Fascinating.  Interesting that it precludes doing a walking glue connection and only allows connection points.
Visio 2019 Pro