Stretch Smart Shape & automatically add connection points [SOLVED]

Started by The Walrus, October 16, 2017, 07:08:17 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

The Walrus

Hello,

I'm a relative Visio newbie, thrust into the environment for reasons of cost savings.  Overall, I'm making the transition fairly well but, like any good engineer my ultimate goal is to become really, really lazy.  To that end, I'll expend great amounts of effort to get there!

We are currently using Visio13 for electrical system schematics.  90% or greater of our drawings are for interconnections black boxes together with wires and cables.  The Powers-that-Be have determined that our previous CAD package was too expensive to maintain, and that Visio would suit our needs at a fraction of the cost.  Mostly, they are correct.

Now to the crux of my problem.

In our drawings, we are often having to resize shapes (i.e. electrical connectors). The default behavior in Visio tends to be that the connection points move based on proportion of the shape rather than on grid or with defined spacing.

I would like to build/create a smart shape that started off as two pins, but that the user can stretch or collapse as required in their drawing, while automatically inserting/removing connection points corresponding to the grid.  I've attached a sheet to hopefully demonstrate more precisely the desired effect.

This thread seems to maybe cover the collapsing behavior to some extent, but I'm not sure that's the right approach for what I need.

Any help would be greatly appreciated!
I use Visio 2013 Pro at work and 2016 Pro at home

wapperdude

Visio 2019 Pro

The Walrus

I have spent an awful lot of time not getting very far.  I think my trouble is truly understanding how the properties in teh shape sheets interact.

So, perhaps I need to back off a bit and start more simply.

Looking at the VSD in my OP, I think I'd just like to start simply with being able to stretch a shape and have it preserve some certain dimensions.  See C & D in that VSD.

I'll then build from there.

Are there any decent tutorials somewhere that are specific to just being able to create a 'stretchable' shape that preserves certain dimensions?  Like maybe with an arrow that preserves the size and ratios of the arrow head when stretched?
I use Visio 2013 Pro at work and 2016 Pro at home

wapperdude

Sorry about the confusion.  Attached is a simpler shape.  This demonstrates the basics of stretching a shape between some minimum value and maximum value in discrete steps using the bound function.  As the shape expands or contracts, connection points are "added" or removed" as is appropriate.  Note, no connection points are eliminated, the unused ones are merely stacked on top of each other.  It would require code to reduce or increase the number of connection points as that would require eliminating or adding lines to the Connection point section of the shapesheet.

HTH

Wapperdude
Visio 2019 Pro

wapperdude

Here's another version, this uses a fixed list to choose the number of connection points.  Dbl click the shape to bring up the shapedata, select the number of connection points, and enter the desired pin to pin spacing.  The shape will automatically size based upon those settings.

Wapperdude
Visio 2019 Pro

The Walrus

I'm back, and I've not been able to accomplish any of my desired traits in this thread.  So I'm going to back way off to baby steps.

Step 1.

I would like to build a shape in Visio, and when I stretch it or contact it, I want both ends of the shape to maintain their dimensions.  At this point I am not at all worried about connection points.  I just want the shape to act as a 'smart shape' as in this article.  I can stretch the arrow as much as I want, but the arrow head itself stays the same.  I want to learn how to create this functionality for my shapes (that aren't arrows).

What properties allow me to do this?  Where in the ShapeSheet or elsewhere do I need to go to make this happen?  The Shape Design --> Behavior or Shape Design --> Protection dialogs seem like they should be helpful, but they are not.

I tried using the arrow stencil from General --> Blocks, and opening the ShapeSheet, but I can't seem to find anything that 'locks' the arrowhead dimensions in place.

Please help!
I use Visio 2013 Pro at work and 2016 Pro at home


wapperdude

Wrt shape stretching, this article directly covers the topic:  https://msdn.microsoft.com/en-us/library/aa200966(v=office.10).aspx.  It is part of a very comprehensive discussion based upon V2002.  Everything in this entire article, some 28 chapters, is excellent foundational information.

Enjoy!
Wapperdude
Visio 2019 Pro

The Walrus

I use Visio 2013 Pro at work and 2016 Pro at home

The Walrus

So, thanks to the posts on the 12th, I have made some great progress!  I have been able to use the Geometry section to create a smart shape with the behavior I would like.

Now, on to the connection points.  I've attached a vsd with the shape I've created, and I've added a few connection points that behave as I would like.

Now, I'm looking to add the connection points automatically.

I'm fairly adept at writing excel functions, and it seems that Visio uses a lot of the same functions, but even more.

I'm thinking there ought to be a way to add connection points automatically based on a function of the height.  Perhaps test for height, and divide by distance, and the result is N.  For every N, place a connection point.  Am I barking up the right tree?

Take a peek at what I have so far and feel free to critique.
I use Visio 2013 Pro at work and 2016 Pro at home

The Walrus

I'm getting very much closer, but it appears that I need to run a Macro to get the connection points to work properly.  I haven't written code in ages, and I'm not sure how to call aspects of the shape sheet into Visual Basic, so I would appreciate any help in that arena.  I think my logic is right, or at least right enough to get where I want to go, but syntax is where I'm stuck.

Sub AddConnPts()

Dim I As Integer    'Incrementer
Dim N As Integer    'Number of Connection Points Needed
Dim C As Integer    'Number of existing Connection Points
Dim H As Long       'Height of Shape
Dim HString As String   'String to put in Connect points Y Column
Dim WString As String  'String to put in Connect points X Column

Get Shape NameID            'Don't know how to do this
    Get shape Height = H    'How to get height off shapesheet for NameID
        If H > 0.5 Then
            N = (H - 0.25) / 0.125           'Sets number of needed connection points based on geometry of shape
            Get Existing Connection Points = C  'How to count the number of existing connection points on NameID
            If C < N Then
                For I = C + 1 To N
           
                HString = "IF(Height*1>=0.5,Height*1-0.125*" &I ",0"   'how do I put this in the Connection Points area of Shape Sheet?
                WString = "Width*1"
               
                'How to insert strings in next incremented row of Connection Points section of shape sheet?
           
                Next I
            End If
        End If

End Sub

My intention is to add an Actions section into the part shape sheet and create an "Add Connections" Menu option for the shape that would then run the macro.

Any and all help is greatly appreciated!
I use Visio 2013 Pro at work and 2016 Pro at home

Yacine

Hi Walrus,
I had a look at your request and started working out a solution, for what you exactly asked for, then I understood that you were not that much after the macro itself, but rather the final shape (scaling as needed and moving its connection points) and finally I recalled having seen these exact shapes in an old topic.
Have a look at it: http://visguy.com/vgforum/index.php?topic=6271.15
It probably doesn't follow exactly your strategy, but I remember that Rudy was happy with his final result.
HTH, Y.
Yacine

The Walrus

Thanks, Yacine.

I looked at the implementation you linked, and while similar, that direction won't really work for our implementation.  I also wonder about the efficiency of them in larger drawing packages.  I've noticed that the larger a multi-page drawing is, the more Visio behaves...slowly.  So I wonder if huge, complicated shape sheets attached to every shape would affect performance?

I've also decided to go the macro direction for portability.  It seems to me that I should be able to write one macro to perform the necessary connection point automation across multiple shapes.

It's also now become...personal.  I want to conquer this.

In my research over the past few days, I've found two links that appear to give me the tools I need to conquer this issue.  One is yours, driven by the link above I got to this one, which solves my problem of how to apply the macro to any selected shape.

The other is an MSDN article that helps me add cells to the shape sheet and populate those cells.  This is also the link that makes me believe I can use a generic macro across multiple shapes.

If I am uninterrupted today, I believe I can have a working model today that should provide the functionality I want.  It might need tweaking, but I think I can get there from here.
I use Visio 2013 Pro at work and 2016 Pro at home

The Walrus

So, I didn't have long to work on this today and I'm making progress, but my code is behaving funny.
Sub AddCnPts()
'
' Automatically Add Connection Points
'
    Dim UndoScopeID2 As Long
    UndoScopeID2 = Application.BeginUndoScope("Add Connect")
    Dim intRowIndex1 As Integer
    intRowIndex1 = ActiveWindow.Selection(1).AddRow(visSectionConnectionPts, visRowLast, visTagCnnctPt)
    Dim vsoRow1 As Visio.Row
    Dim vsoCell As Visio.Cell
    Dim vsoShape As Visio.Shape
    Dim strHRow As String
    Dim shpHgt As Long
    Dim intI As Integer
   
    Set vsoShape = ActiveWindow.Selection(1)
    Set vsoCell = vsoShape.CellsU("Height")
    shpHgt = vsoCell
    If shpHgt >= 0.5 Then
            intI = (shpHgt - 0.25) / 0.125           'Sets number of needed connection points based on geometry of shape
    End If
   
    strHRow = "=IF(Height*1>=0.5,Height*1-(0.125*" & intI & "),0)"
   
    Set vsoRow1 = ActiveWindow.Selection(1).Section(visSectionConnectionPts).Row(intRowIndex1)
    vsoRow1.Cell(visCnnctX).FormulaU = "Width*1"
    vsoRow1.Cell(visCnnctY).FormulaU = strHRow
    vsoRow1.Cell(visCnnctDirX).FormulaU = -1#
    vsoRow1.Cell(visCnnctDirY).FormulaU = 0#
    vsoRow1.Cell(visCnnctType).FormulaU = visCnnctTypeInward
    Application.EndUndoScope UndoScopeID2, True
   
End Sub

This is just a starting point to make sure I can access individual cells and actually write the connection point data.  That stuff works.

However, when I set a breakpoint at End Sub so I can look at the variables, I find that vsoCell has the correct value, but shpHgt does not, and neither does intI.  I can't for the life of me figure why shpHgt = vsoCell doesn't actually set the value of vsoCell into the shpHgt variable.  Likewise, intI likes to default to "6".

So this is a learning process, and I don't believe I have ever done anything object-oriented in my life so this is new to me as well.
I use Visio 2013 Pro at work and 2016 Pro at home

Yacine

vsoCell is an object. Whilst VBA often converts correctly, in this case it seems to not having been able to.
But you don't need to introduce this intermediate variable, you can get directly the cell value as shown below.

Sub AddCnPts()
'
' Automatically Add Connection Points
'
    Dim UndoScopeID2 As Long
    Dim intRowIndex1 As Integer
    Dim vsoRow1 As Visio.Row
    'Dim vsoCell As Visio.Cell *** not needed
    Dim vsoShape As Visio.Shape
    Dim strHRow As String
    Dim shpHgt As Long
    Dim intI As Integer
   
    UndoScopeID2 = Application.BeginUndoScope("Add Connect")
    intRowIndex1 = ActiveWindow.Selection(1).AddRow(visSectionConnectionPts, visRowLast, visTagCnnctPt)
   
    If ActiveWindow.Selection.Count <> 1 Then
        MsgBox "This macro works with exactly ONE shape. Please select one and run again.", vbOK
        Exit Sub
    End If
   
    Set vsoShape = ActiveWindow.Selection(1)
    ' Set vsoCell = vsoShape.CellsU("Height")
    ' shpHgt = vsoCell
    shpHgt = vsoShape.Cells("Height").ResultIU
    If shpHgt >= 0.5 Then
            intI = (shpHgt - 0.25) / 0.125           'Sets number of needed connection points based on geometry of shape
    End If
   
    strHRow = "=IF(Height*1>=0.5,Height*1-(0.125*" & intI & "),0)"
   
    Set vsoRow1 = vsoShape.Section(visSectionConnectionPts).Row(intRowIndex1)
    With vsoRow1
        .Cell(visCnnctX).FormulaU = "Width*1"
        .Cell(visCnnctY).FormulaU = strHRow
        .Cell(visCnnctDirX).FormulaU = -1#
        .Cell(visCnnctDirY).FormulaU = 0#
        .Cell(visCnnctType).FormulaU = visCnnctTypeInward
    End With
   
    Application.EndUndoScope UndoScopeID2, True
   
End Sub
Yacine