Для русскоязычных пользователей Visio. Начинающих и профессионалов. Где взять, как сделать, что купить и т.д.

Соединения

Соединения, коннекторы - это изюминка Visio, исключительно важная вещь.

В качестве обобщающего материала для пользователей-рисовальщиков предлагается переводная статья Все, что нужно знать о соединительных линиях Visio с оригинала All you need to know about Visio desktop connectors.

Название немного смешное, потому как это далеко не все, что нужно знать. Программисты, как обычно, лезут гораздо глубже. Обобщающий материал для программистов - Небольшая справка по соединениям фигур.

Кроме того, часто возникают вопросы, связанные с изменением (добавлением и удалением) соединений. Поэтому полезно ознакомиться со следующими источниками:

Вопрос: Можно ли определить присоединенный шейп через ShapeSheet?

Ответ: Нельзя.

Связанная статья Getting the Name of Glued Connection Points

В статье Дэвида Паркера пример кода VBA и совет использовать AddAdvise вместо WithEvents

Также вопросы в форумах:
Find out informations of a connected (glued) shape
Вопрос по коннектору
Имя приклеенной фигуры из таблицы свойств

Кроме того, есть мысль о специальных коннекторах, в которых код можно запускать не через ConnectionsAdded, ConnectionsDeleted, а отслеживая изменение ячейки

Scratch.A = RUNMACRO("ThisDocument.ttt")+DEPENDSON(BegTrigger)

Если нужно что-то передать, то можно и через CallThis. =CALLTHIS("ThisDocument.ttt")+DEPENDSON(BegTrigger)

с обработчиком

Sub ttt(shp As Visio.Shape)
MsgBox shp.Cells("BegTrigger").Formula
End Sub

Перечень литературы

15.10.2012  Adding More Smartness to Visio Connectors  David Parker.   

07.05.2012  Working with connected diagrams programmatically  E. Schmidt.   

13.07.2009  Automatically Number & Connect Shapes – With Code!  Chris Roth.   

22.04.2009  Analyze Connectivity Between Process Flows  Chris Roth.   

17.03.2008  Connect All Shapes to Each Other  Chris Roth.   

Ответы на вопросы

Как красиво приклеить?

Для склеивания двух объектов Shape использую Line Connector и Connection Point:
CObj, NObj - объекты Shape, хост и сегмент
conObj - объект Line Connector
(1) conObj.Cells("BeginX").GlueTo CObj
(2) conObj.Cells("EndX").GlueTo NObj.Cells ("Connections.X1")
Часто, при переносе какого-либо из двух объектов, "Line Connector" пересекает изображение объекта, выглядит плохо.
Вручную можно "Line Connector" приклеить к Shape объекту целиком, при этом используемый "Connection Point" выбирается автоматически в соответствии с расположением Shape объектов. Как образовать такое соединение программным путём? 

Коннектор можно клеить к:
- точкам соединения - Connections.Xn или Connections.Yn (Ваш пример)
- изломам геометрии - Geometry.Xn или Geometry.Yn
- сторонам шейпа - AlignLeft, AlignCenter, AlignRight, AlignTop, AlignMiddle или AlignBottom
- наконец, динамический клей (то, что Вам нужно) - к PinX или PinY
Типа: conObj.Cells("EndX").GlueTo NObj.Cells("PinX")
А если уж совсем хочется эффектов, то можно еще поманипулировать секцией Shape Layout для совершенстования обтекания (это аналогично вкладке Format/Behavior/Placement). 

Как определить в Visual Basic цепочку из соединенных шейпов?

Сделал схему ЛВС, рабочие места соединил с портами на патч панели и коммутаторах соединителями. Как можно определить в Visual Basic цепочку из соединенных шейпов и как можно пройти по этой цепочке.
Это надо для того, чтобы легко идентифицировать соответствующие порты в коммутаторах по выбранным рабочим местам. 

Доступ к идентификаторам объектов связанных коннектором можно получить из самого коннектора.
Имя_коннектора.Connects.Item(i).ToCell.Shape.NameID
NameID - это идентификатор Шейпа на листе Sheet.номер
Имя трафарета, который использовался при создании, определяется ссылкой к полю Name
i - это номера соединяемых шейпов
Для того чтобы получить доступ к CustomProperties полям надо 

page.Shapes.Item(i).Cells("Prop.CodeCable").Formula 

Prop.CodeCable - название ячейки, отображаемое в ShapeSheet (в случае патч корда это так и выглядит), отображается название по-другому нежели в CustomProperties
Если такого пропертиса нет, то возвращается ошибка end of expected 

Можно ли получить доступ к Connection points шейпа из VB и удалить ненужные точки?

Задача:
есть мастер (прямоугольник), который имеет 10 Connection points слева и 10 справа. Во время перетаскивания мастера на документ и перехода в шейп требуется убрать лишние Connection points (что бы они были не видны и не доступны пользователю). Количество лишних Connection points определяется программой по заданному алгоритму. 

В шейп-листе есть секция Connection Points. Для удаления Points нужно из этой секции удалить строку.
Строка в общем случае удаляется примерно так: 

shpObj.DeleteRow visSectionFirstComponent + 0, visRowVertex + 3 

Для секции Connection Points это будет выглядеть примерно так: 

shpObj.DeleteRow visSectionConnectionPts+0, visRowConnectionPts+2 

В примере удалится точка № 3 (из расчета 0, 1, 2, 3...). 

Sub ttt()
ActivePage.Shapes(1).DeleteRow visSectionConnectionPts + 0, visRowConnectionPts + 2
End Sub 

Как определить к какому именно конекшен поинту произошло подключение?

Меня интересует именно раздел работа VB с Visio. Вопрос как определить к какому именно конекшен поинту произошло подключение и запросить у этого объекта кастомные свойства. То есть, есть труба которая подключается например к емкости нужно понять, к чему она подключена (емкость, клапан, насос, узел), к какой части емкости верх низ середина, и запросить кастомные свойства этого объекта в зависимости от места подключения к нему. 

Коннекторы с точки зрения анализа соединений отличаются от прочих шейпов.
Труба у Вас наверное будет коннектором. У коннектора нужно смотреть коллекцию Connects. В ней будет столько элементов, сколько раз этот коннектор подключен куда-либо. Если труба - ConnectorObj, то коллекция - ConnectorObj.Connects, число подключений - ConnectorObj.Connects.Count.
Вычислить, к чему она подключена, можно через свойство ToSheet. Если у Вас на рисунке выбрана только эта труба, то ActiveWindow.Selection(1).Connects(1).ToSheet.Master.Name даст имя мастер-шейпа элемента, подключенного к первому концу трубы.
А вот у емкости и прочих шейпов смотреть надо уже другую коллекцию - FromConnects (вместо Connects) и свойство FromSheet вместо ToSheet. То есть вроде как смотрим с обратной стороны на то же подключение.
Ну, и еще два свойства - FromPart и ToPart объекта Connect помогут определить часть шейпа (там куча констант, показывающих низ, верх, номер Connection Point'а и т.д.) 

Как отменить огибание коннектором при пересечениях

Есть несколько слоев, ненужные скрыты. На перекрестке видимый коннектор огибает другой коннектор (невидимый). Как сделать видимый коннектор ровным, т.е. без значка дуги в месте пересечения? 

Хитрый случай. Одной кнопкой не решается. Можно использовать свойство страницы LineJumpCode и сделать так, что при пересечении видимого коннектора с невидимым дуга всегда стояла на невидимом коннекторе.
1. В свойствах страницы в Layout and Routing в блоке Line jumps нужно указать First displayed line.
2. Переместить невидимые коннекторы вниз. Для этого, например, выделить все и выполнить Bring to Front.
При этом все невидимое не выделится и окажется внизу. В том числе и невидимые гнутые коннекторы. 

Почему-то не присоединяются конекторы

Подготовил оргструктуру. Она матричная, поэтому к квадратикам могут идти стрелки от двух - трех других квадратиков. Т.е. к шейпу подключаются по 2-3 конектора.
Затем, спустя какое-то время, понадобилось внести изменения.
Возникла проблема - если к шейпу ведет один конектор, то второй либо накладывается на первый, либо первый исчезает. Как быть? Что исправить и где? 

Это особенность оргструктуры. В них работает аддон, который задает именно такое поведение.
Один из вариантов решения - отключить события автоматизации. Опасно тем, что если потом когда-то их включить, то опять все исчезнет.
Второй вариант – для дополнительных подключений использовать не Dynamic connector, а Dotted-line report. Он тоже есть в оргдиаграммах. Его можно отформатировать, чтобы выглядел так же, как Dynamic connector. Этот исчезать не будет. 

Жесткая точка соединения

Есть разные элементы с точкой соединения (1). Есть главный элемент, у которого много точек соединения (2). Нужно создать жесткую связь, чтобы элементы 1 не отрывались от элемента 2 никак (кроме удаления). 

Сделайте жесткую связь и защиту 2-го элемента.
Для этого создайте соединительную точку Внутрь(Inward), а у зависимой фигуры соединительную точку Наружу(Outward). Соедините их жесткой связью и сделайте защиту зависимой фигуры Формат>Защита(Format>Protection). В этом окне отметьте все галочки, кроме удаления. 

Теперь новая проблема. Есть элементы, которые надо сначала вытащить на лист, повернуть, а уже потом цеплять, а с защитой не получается. Что делать? 

Используйте маркеры направления жестких связей.
http://www.prodigitall.narod.ru/articles/article12.html 

У меня их нет, как их настроить? 

Тогда вручную через ShapeSheet. Раздел Connection point, ячейки DirX/A и DirY/B. Это положение маркера в мм, относительно центра соединитеьлной точки. 

Соединить 2 фигуры прямой линией

Нужно соединить линией(стрелкой) две фигуры так, чтобы при перетаскивании одной за ней тянулась и эта линия, а не отрывалась от неё. Но это не всё. Обычный соединитель такое позволяет, но он не проводится по диагонали - только изгибается под прямым углом. А мне нужно, чтобы эта линия всегда была прямая и не изгибалась. Как такое сделать? 

Соедините их обычной прямой линией. Только сначала надо поставить галочку в Tools / Snap & Glue / Glue To - Shape Handles. 

Создание произвольного коннектора

Необходимо получить коннектор с числом отрезков более 7, т.к. этого недостаточно, можно ли напрямую самому наносить места расположения точек изменения угла? 

Прижмите клавишу Ctrl и дергайте за зеленые точки посредине отрезков. 

Какой конец коннектора присоединился к шейпу?

Подскажите как определить начало или конец коннектора присоединился к шэйпу. Отлавливаю ConectionsAdded у Page-а, беру FromShape (это коннектор) и смотрю у него коллекцию Connects, никак не могу понять как определить начало коннектора прицепилось или конец. 

Нужно посмотреть FromPart у объекта Connect.
visBegin = 9 - начало
visEnd = 12 - конец
Например, если селектирован коннектор, то в данном примере одна строчка даст 9, вторая - 12. 

Sub ttt()
MsgBox ActiveWindow.Selection(1).Connects(1).FromPart
MsgBox ActiveWindow.Selection(1).Connects(2).FromPart
End Sub 

Как отловить соединение шейпов

Как отловить соединение шейпов. И как узнать какие это шейпы. 

Все соединения можно посмотреть в коллекциях Connects или FromConnects шейпа или коллекции Connects страницы.
А дальше выбирается из этой коллекции очередной Connect и рассматриваются его свойства FromSheet, ToSheet для определения участвующих шейпов и свойства FromPart, ToPart для уточнения их частей.
Или надо событие соединения отловить?
Если так, то нужно объявлять страницу с WithEvents. При этом станет возможной обработка события ConnectionsAdded(ByVal Connects As IVConnects). Ну, а здесь уже в обработчике получаем тот же самый объект Connects и начинаем точно также рассматривать его свойства.
Вот простейший пример, который показывает соединение 2х шейпов с помощью третьего, например с помощью "Dynamic connector". 

Sub Example1()
s1 = ""
lastFromSheet = ""
lastToSheet = ""
For i = 1 To ActivePage.Connects.Count
thisFromSheet = ActivePage.Connects(i).FromSheet
thisToSheet = ActivePage.Connects(i).ToSheet
If lastFromSheet = thisFromSheet Then
s1 = s1 + lastToSheet + " -> " + thisToSheet + vbCrLf
End If
lastFromSheet = thisFromSheet
lastToSheet = thisToSheet
Next
MsgBox (s1)
End Sub 

Разделение соединителей

Пожалуйста, подскажите, какие параметры или настройки позволяют предотвратить наложение соединителей (connector). настройки страницы почему-то на это не влияют.
Есть две фигуры, их надо соединить двумя параллельными коннекторами. Оба коннектора должны выходить из одной connection point на первой фигуре и приходить на одну connection point на другой фигуре. Нужно, чтобы эти коннекторы не накладывались друг на друга, а автоматом разносились 

Автоматом коннекторы разносятся только при динамическом соединении, да и то только в том случае, если выбран прямоугольный тип коннектора (Right-Angle).
Если коннектор приклеен к точкам соединения, то они будут накладываться. Но конфигурацию коннектора можно изменить вручную. Для это нужно выбрать коннектор, найти мышью середину коннектора или его сегмента и переместить ее зажимая клавишу Ctrl. 

Доступ к Connection points из VB

Задача: есть мастер (прямоугольник), который имеет 10 Connection points с лева и 10 с права. Во время перетаскивания мастера на документ и перехода в шейп требуется убрать лишние Connection points (что бы они были не видны и не доступны пользователю). Количество лишних Connection points определяется программой по заданному алгоритму.
Вопрос: можно ли получить доступ к Connection points шейпа из VB и удалить ненужные точки? 

В шейп-листе есть секция Connection Points. Для удаления Points нужно из этой секции удалить строку.
Строка в общем случае удаляется примерно так:
shpObj.DeleteRow visSectionFirstComponent + 0, visRowVertex + 3
Для секции Connection Points это будет выглядеть примерно так:
shpObj.DeleteRow visSectionConnectionPts+0, visRowConnectionPts+2
В примере удалится точка № 3 (из расчета 0, 1, 2, 3...). 

Sub ttt()
ActivePage.Shapes(1).DeleteRow visSectionConnectionPts + 0, visRowConnectionPts + 2
End Sub 

Как создать много точек соединения?

Подскажите пожалуйста, как добавить коннекшен поинтс к шейпу...
Нашел на форуме тему, но не могу понять как AddRows работает. Подскажите, пожалуйста, конкретно, что в параметры надо забросить, чтоб добавить, к примеру 4, 6, 8 точек. 

Все очень просто. Если фигура не имеет раздела конекшен поинтов, то сначала надо создать его. Делаем это так: 

Dim UndoScopeID1 As Long
UndoScopeID1 = Application.BeginUndoScope("Add Section")
Application.ActiveWindow.Shape.AddSection visSectionConnectionPts
Application.EndUndoScope UndoScopeID1, True 

Затем добавляем коннекшен поинт 

Dim UndoScopeID2 As Long
UndoScopeID2 = Application.BeginUndoScope("Insert Row")
Application.ActiveWindow.Shape.AddRow visSectionConnectionPts, 0, visCnnctX
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctX).FormulaU = "Width*0"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctY).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctDirX).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctDirY).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctType).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctAutoGen).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, 6).FormulaU = ""
Application.EndUndoScope UndoScopeID2, True 

Затем добавляем следующий 

Dim UndoScopeID3 As Long
UndoScopeID3 = Application.BeginUndoScope("Insert Row")
Application.ActiveWindow.Shape.AddRow visSectionConnectionPts, 0, visCnnctX
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctX).FormulaU = "Width*0"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctY).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctDirX).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctDirY).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctType).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctAutoGen).FormulaU = "0 mm"
Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, 6).FormulaU = ""
Application.EndUndoScope UndoScopeID3, True 

И так далее....
В значениях параметров, пишите то что вам нужно... координанты поинта в фигуре и прочее...
Да... чуть не забыл самое главное, если хотите задать имя строке точки коннектора, то это делается так: 

Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 0, visCnnctX).RowNameU = "MyConnector1" 

В данном примере мы присваиваем имя MyConnector1 первой строке (первому коннектору), аналогично: 

Application.ActiveWindow.Shape.CellsSRC(visSectionConnectionPts, 1, visCnnctX).RowNameU = "MyConnector2" 

Второму и т.д. 

Умный коннектор

Нужно создать универсальный коннектор, который будет изменять свой цвет и начертание в зависимости от значений пользовательских свойств. Предполагаю использовать при рисовании схем ЛВС. Скажите с чего начать и куда грести?
Если конкретно, то требуется следующее:
Создается пользовательское свойство "Технология" значения которого берутся из списка "Ethernet;Fast Ethernet;Gigabit Ethernet".
В зависимости от выбранного значения должен меняться цвет коннектора. 

В ячейке где задектся цвет (FillForegnd) 

=if(StrSame(Prop.Row_1;"Ethernet");0;if(StrSame(Prop.Row_1;"Fast Ethernet");1;2)) 

где Prop.Row_1 это ваша "Технология" 

Группа не приклеивается

Сделал я группу и добавил к ней точку подключения типа Out (1). Теперь взяв мышкой эту группу можно приклеить её к какой-либо фигуре, имеющей точку подключения типа In (0). Но если добавить в группу много шейпов, то группа становится слишком "тяжёлой" и перемещение мышкой происходит с задержкой(если удерживать кнопку мышки) - сначала отрисовывается рамка, а потом содержимоею. При этом клей работать перестаёт. Можно это как-нибудь обойти более-менее удобным способом? 

Это ограничение Visio. Если группа содержит более 50 (примерно) шейпов, она перестает приклеиваться.
Возможные методы борьбы:
- сокращать количество входящих, объединяя их операцией Join;
- импортировать часть изображения в EMF и добавлять потом в группу в виде картинки (это будет один шейп). 

Подскажите пример макроса для выбора цепочки связанных объектов

Не посоветует ли кто пример макроса, который по клику на объект "покрасит" всю цепочку соединенных объектов? Или ссылочку на почитать. 

Это не такой-то простой макрос...
Вот для примера макрос, решающий похожую задачу (только с ручным запуском).
На листе есть много квадратиков, соединенных коннекторами. Если выделить один квадратик и запустить макрос bounce, то селектируются все связанные квадратики. Коннекторы не селектировались.
Используется рекурсивный вызов процедуры recurs. Имена набиваются в коллекцию, потом все селектируется. 

Dim Scol As Collection
Sub bounce()
Dim shTmp As Visio.Shape 'временный
Set shTmp = ActiveWindow.Selection(1)
Set Scol = New Collection
Scol.Add shTmp.NameID
recurs shTmp
ActiveWindow.DeselectAll
For i = 1 To Scol.Count
ActiveWindow.Select ActivePage.Shapes(Scol(i)), visSelect
Next
End Sub
Sub recurs(Sh As Visio.Shape)
Dim shTmp As Visio.Shape 'временный
Dim sc As Visio.Shape 'коннектор
For i = 1 To Sh.FromConnects.Count
Set sc = Sh.FromConnects(i).FromSheet
If sc.Connects.Count > 1 Then
If sc.Connects(1).ToSheet = Sh Then
Flag = 0
For Each stmp In Scol
If StrComp(stmp, sc.Connects(2).ToSheet.NameID) = 0 Then Flag = 1
Next
If Flag = 0 Then
Scol.Add (sc.Connects(2).ToSheet.NameID)
Set shTmp = sc.Connects(2).ToSheet
recurs shTmp
End If
Else
Flag = 0
For Each stmp In Scol
If StrComp(stmp, sc.Connects(1).ToSheet.NameID) = 0 Then Flag = 1
Next
If Flag = 0 Then
Scol.Add (sc.Connects(1).ToSheet.NameID)
Set shTmp = sc.Connects(1).ToSheet
recurs shTmp
End If
End If
End If
Next
End Sub 

Отображение точек соединения

Подскажите пожалуйста где отключается отображение точек соединения. 

Меню View / Connection Points.
Но при этом они перестают коннектиться.