All Forums
 Категория Visio
 Форум Вопросы и ответы
 Как программно определить связи между фигурами
Next Page
Author Previous Topic Topic Next Topic

Victorm72

Russia
7 Posts

Posted - 07/07/2006 :  17:45:47
Здравствуйте, Знатоки Visio!

Задача в кратце следующая:
Вывести информацию о сущностях и их связях в Excel для дальнейшего анализа.

Просмотрел Ваши посты по программированию на VBA в Visio, нашел много полезного и вывод в таблицу информации об объектах сделал, но как быть со связями? Очень хочется их тоже сохранить! :)
Пример:
На диаграмме есть объекты Shape: Entity.1, Entity.2 и connector.1, который их связывает, подскажите пожалуйста, как можно программно определить связи между этими объектами Shape?

С уважением,
Виктор

Edited by - Victorm72 on 07/07/2006 17:46:33

Tumanov

Russia
1198 Posts

Posted - 07/07/2006 :  19:49:42
1. С точки зрения склеивания шейпы можно различить на пассивные и активные. Пассивные - это Entity.1, Entity.2. К ним клеится нечто. Активный - connector.1. Он клеится.
2. Точка склейки - это такой объект Connect.
3. У активных шейпов объекты Connect собираются в коллекцию Connects. Свойство Connect.ToCell укажет на ячейку в пассивном шейпе, к которой приклеено. Сам шейп, естественно, можно определить через Connect.ToCell.Shape.
У пассивных - они же собираются в коллекцию FromConnects. Соответственно, вместо ToCell используется Connect.FromCell, а Connect.FromCell.Shape покажет шейп-коннектор.
Вот и все правила.
Просматриваем в шейпах коллекции Connects и FromConnects, через объекты Connect переходим на приклееные шейпы, просматриваем их коллекции и так пока не переберем все цепочки. Важно только не перепутать, когда From, когда To.
Go to Top of Page

Victorm72

Russia
7 Posts

Posted - 07/10/2006 :  09:42:16
Видимо я упустил одну очень существенную деталь - у меня Visio 2000, а эти свойства, как я понял появились в Visio 2003.
Как связи реализовывались в Visio 2000?

С уважением,
Виктор
Go to Top of Page

Tumanov

Russia
1198 Posts

Posted - 07/10/2006 :  12:58:03
Вот уж нет...
Вот цитата из DVS 2000, в которой говорится о тех же самых объектах:
A Shape object has two connection-related properties:
• A Connects property, which returns a Connects collection that includes a
Connect object for each shape, group, or guide to which that shape is glued
• A FromConnects property, which returns a Connects collection that includes a
Connect object for each shape, group, or guide glued to that shape
Go to Top of Page

Victorm72

Russia
7 Posts

Posted - 07/11/2006 :  09:05:25
Я был не прав - подвело незнание "мат.части"... :(
На моей тестовой схеме фактически не было связей - фигуры соприкосались, но линки установленны не были... Исправил и получил правильный ответ. :)

Теперь появился следующий вопрос:
как определить в сторону какого объекта направленна стрелка - в какой точке начало, а в какой конец связи? есть ли для этого соответствующие признаки?
Go to Top of Page

Tumanov

Russia
1198 Posts

Posted - 07/11/2006 :  10:10:27
В Visio все есть... :)
Сама связь не ориентированна, но, рассматривая части коннектора, можно понять, начало это или конец.
Выше уже говорилось, что Connect.ToCell (со стороны активного шейпа) укажет на ячейку в пассивном шейпе.
Но можно посмотреть и на себя - Connect.FromCell покажет свою приконнекченную ячейку. Это одна из ячеек шейпа, которые доступны через шейп-лист. Значит по имени ячейки можно понять, какая это часть шейпа.
То есть Connect.FromCell.Name скажет нам либо BeginX, либо EndX.
Но это не лучший способ, а только иллюстрация выхода на ячейку.
Точнее пользоваться свойством FromPart. Оно указывает часть шейпа, участвующую в соединении.
Для коннектора Connect.FromPart даст Вам либо visBegin (константа 9), либо visEnd (константа 12). Для пассивных шейпов разнообразие констант больше, их можно посмотреть в Help на слово FromPart (ToPart).
Go to Top of Page

Victorm72

Russia
7 Posts

Posted - 07/11/2006 :  14:54:59
Разобрался. Огромное спасибо! :)
Но задачи усложняются...
Начал работать с реальной схемой и выяснил, что в ней кроме отсутствия некоторых точек соединения присутствует еще один не очень приятный момент - надписи относящиеся к связям выполнены в виде отдельных объектов (прямоугольников с текстом) размещенных над линией связи. Как объяснили разработчики схемы это сделано из-за невозможности правильно спозиционировать текст надписи выполненный по правилам, что снижало "читаемость схемы".
Есть ли возможность программно определить "визуальное перекрытие" объектов shape, а именно коннекторов (Connector) и надписей (Sheet) не прибегая к сложным геометрическим вычислениям?
Go to Top of Page

Sign

16 Posts

Posted - 07/11/2006 :  15:49:35
quote:
Originally posted by Victorm72


Есть ли возможность программно определить "визуальное перекрытие" объектов shape, а именно коннекторов (Connector) и надписей (Sheet) не прибегая к сложным геометрическим вычислениям?


На счет специальных возможностей не скажу. Но и без этих возможностей сложных расчетов, думаю, производить не придется. По опыту знаю, что такие надписи, как правило, стараются поставить поближе к середине соединеля. Посему задача сведется к нахождению минимального расстояния по PinX,PinY пар твоя_надпись-соединитель. Естественно соединители брать только из тех, что "ниже" твоей надписи, с учетом ориентации текста.
Go to Top of Page

Tumanov

Russia
1198 Posts

Posted - 07/11/2006 :  16:54:52
Для позиционирования таких надписей в коннектор часто вводят управляющую точку, перемещением которой задается позиция текстового блока (это если не хотят пользоваться инструментом Text Block Tool). Получается и текст в шейпе и двигается он довольно легко...
А в Вашем случае придется воспользоваться свойством SpatialNeighbors, которое вернет объект Selection, содержащий коллекцию шейпов, находящихся в заданной зависимости от коннектора. В данном случае наверное следует искать шейпы с отношением "visSpatialTouching". Только нужно не забыть, что приконнекченные шейпы тоже будут включены в коллекцию. Надо будет отсеять их от надписей. Скорее всего это можно сделать по типу шейпа.
Вот такой код на подключенном коннекторе с дополнительной надписью возвращает троечку.
Sub ttt()
Dim Sel As Visio.Selection
Set Sel = ActiveWindow.Selection(1).SpatialNeighbors(visSpatialTouching, 0.2, 0)
Debug.Print Sel.Count
End Sub
Go to Top of Page

Victorm72

Russia
7 Posts

Posted - 07/11/2006 :  18:58:30
Это то что мне нужно - интересующие меня объекты я вижу! :)))
Следующим шагом я хочу избавится от пересекающихся соединений, которые тоже попадают в список объектов, каким свойством объекта мне можно воспользоваться для определения типа содержащейся в объекте фигуры?
Я попробовал через Master, но столкнулся с тем, что для объектов "типа" Sheet.123 (я их идентифицирую только по имени, т.к. где на самом деле тип объекта я не знаю), значение этого свойства равно Nothing, а определить это программно мне не удается - попадаю на ошибку исполнения... :(

Sub ttt()
Dim Sel As Visio.Selection
Set Sel = ActiveWindow.Selection(1).SpatialNeighbors(visSpatialTouching, 0.2, 0)
For Each oSel In Sel
If Not IsEmpty(oSel.Master) Then
MsgBox (oSel.Name & " - " & oSel.Master.Name) '- здесь валимся по ошибке
End If
Next
End Sub

На объекте который называется Sheet.123 этот код валится, т.к. для этого объекта oSel.Master=Nothing, а я к нему обращаюсь... :(((
Как этого избежать? Понятно, что не обращаться к такому объекту, но как его идентифицировать? Не по имени-же?
Go to Top of Page

Tumanov

Russia
1198 Posts

Posted - 07/11/2006 :  19:53:11
А почему не по имени? Все равно имя мастера включается в имя шейпа.
Если набор используемых мастеров небольшой, то вполне нормально будет работать.
Кстати, коннекторы у Вас не на отдельном слое? Можно было бы еще по принадлежности к слою. Хотя... по именам все равно проще.
Go to Top of Page

Victorm72

Russia
7 Posts

Posted - 07/12/2006 :  09:05:01
Очень не хочется связываться с операциями со строками...
К тому-же, с точки зрения программирования проводить типизацию по имени я бы отнес к не самому удачному стилю - если кому-то придет в голову создавать объекты программно, то не факт, что они будут названы так-же как при "ручном" добавлении, или я не прав?
А другого способа определить тип элемента действительно не существует?
Каким условием можно обойти обращение к Nothing?
Go to Top of Page

Tumanov

Russia
1198 Posts

Posted - 07/12/2006 :  11:27:40
1. Visio сам создает имена. Этот процесс не зависит от того, как создается объект (вручную или программно).
2. В данном случае слово "тип" не совсем удачно. В данном случае, как я понял, нас интересует только, существует ли у шейпа прототип-мастер.
3. Можно просто спросить у него:
If oSel.Master Is Nothing Then
Debug.Print "Nothing"
End If
Go to Top of Page

bdfy

Belarus
267 Posts

Posted - 08/02/2009 :  20:45:20
задача:
1. есть несколько шейпов.
2. запускается скрипт который заменяет эти несколько шейпов одним.
при этом помещает этот новый шейп в те же коорд. с тем же углом.
3. нужно еще коннекты перенести. т.е создать для нового шейпа все склейки которые были у неск. старых (ну кроме как между собой )
замена проходит примерно так

Set vs = Application.ActiveWindow.Selection
Application.ActiveWindow.Page.Drop Application.ActiveDocument.Masters.ItemU("X"), 0, 0
Set Xsh = Application.ActiveWindow.Selection

params = Array("BeginX", "BeginY", "EndX", "EndY")
    For Each p In params
    Xsh(1).Cells(p) = vs(1).Cells(p)
    Next p
   
vs.Delete

т.е новому шейпу задаются коорд. первого из выдел. группы (хотя надо бы всей группы по-хорошему ).
нужно еще снять пассивные и активные соед. и создать их для нового шейпа.
подсмотрел тут в соседней ветке функцию возвращающую соединения
Public Function ConnectedShapes(ByVal sh As Visio.Shape)
Dim Passive() As Visio.Shape
Dim Active() As Visio.Shape

    'Set sh = ActiveWindow.Selection.Item(1) 'выделенный шейп
    'Активные связи 2D-шейпа
    If sh.Connects.Count > 0 Then 'условие наличия активных связей
    For I = 1 To sh.Connects.Count 'цикл перебора всех активных связей
    ReDim Preserve Active(I)
    Set Active(I - 1) = sh.Connects().ToSheet 'активные связи (к чему приклеен)
   ' Debug.Print "active " & Active(I - 1).Name
    Next
    End If

    'Пассивные связи 2D-шейпа
    If sh.FromConnects.Count > 0 Then 'условие наличия пассивных связей
    For I = 1 To sh.FromConnects.Count 'цикл перебора всех пассивных связей
    ReDim Preserve Passive(I)
    Set Passive(I - 1) = sh.FromConnects(I).FromSheet 'пассивные связи (какие шейпы приклеены к выделенному)
  '  Debug.Print "passive " & Passive(I - 1).Name
    Next
    End If
    
    ConnectedShapes = Array(Active, Passive)
End Function

если вызвать
ar = ConnectedShapes(sh)
Active = ar(0)
Passive = ar(1)
я получу ячейки указывающие место склейки на другой фигуре. а место склеики на обрабатываемой где искать ?
Go to Top of Page

Tumanov

Russia
1198 Posts

Posted - 08/03/2009 :  16:13:00
Если Вам нужны места склейки, то цитируемый макрос не подходит. Он пользуется свойством .ToSheet, которое возвращает шейп.
sh.Connects().ToSheet
А у Connect есть еще свойства ToPart и FromPart. Вот они показывают именно части шейпа.
Go to Top of Page

bdfy

Belarus
267 Posts

Posted - 08/06/2009 :  15:56:35
поковырял. написал такую функцию
Public Function ConnectedCells(ByVal sh As Visio.Shape)

Dim strFrom(), strTo() As String
Dim vsoConnectTo(), vsoConnectFrom() As Visio.Shape

        Set vsoConnects = sh.Connects

        'For each connection, get the shape it connects to
        'and the part of the shape it connects to,
        'and print that information in the Immediate window.
        For intCounter = 0 To vsoConnects.Count - 1
            ReDim Preserve strTo(intCounter + 1), vsoConnectTo(intCounter + 1)
            
            Set vsoConnect = vsoConnects(intCounter + 1)
            Set vsoConnectTo(intCounter) = vsoConnect.ToSheet
            intToData = vsoConnect.ToPart

            If intToData = visConnectError Then
                strTo(intCounter) = "error"
            ElseIf intToData = visNone Then
                strTo(intCounter) = "none"
            ElseIf intToData = visGuideX Then
                strTo(intCounter) = "guideX"
            ElseIf intToData = visGuideY Then
                strTo(intCounter) = "guideY"
            ElseIf intToData = visWholeShape Then
                strTo(intCounter) = "dynamic glue"
            ElseIf intToData >= visConnectionPoint Then
                strTo(intCounter) = "connection point " & _
                    CStr(intToData - visConnectionPoint + 1)
            Else
                strTo(intCounter) = "???"
            End If

            'Print the name and part of the shape the
            'Connect object connects to.
           ' Debug.Print "To " & vsoConnectTo(intCounter).Name & " " & strTo(intCounter) & "."
    Next intCounter


        'For each connection, get the shape it originates from
        'and the part of the shape it originates from,
        'and print that information in the Immediate window.
        For intCounter = 0 To vsoConnects.Count - 1
            ReDim Preserve strFrom(intCounter + 1), vsoConnectFrom(intCounter + 1)
            Set vsoConnect = vsoConnects(intCounter + 1)
            Set vsoConnectFrom(intCounter) = vsoConnect.FromSheet
            intFromData = vsoConnect.FromPart
            
'Debug.Print "vsoFrom " & vsoConnectFrom(intCounter).Name

            'FromPart property values
            If intFromData = visConnectError Then
                strFrom(intCounter) = "error"
            ElseIf intFromData = visNone Then
                strFrom(intCounter) = "none"
            ElseIf intFromData = visLeftEdge Then
                strFrom(intCounter) = "left"
            ElseIf intFromData = visCenterEdge Then
                strFrom(intCounter) = "center"
            ElseIf intFromData = visRightEdge Then
                strFrom(intCounter) = "right"
            ElseIf intFromData = visBottomEdge Then
                strFrom(intCounter) = "bottom"
            ElseIf intFromData = visMiddleEdge Then
                strFrom(intCounter) = "middle"
            ElseIf intFromData = visTopEdge Then
                strFrom(intCounter) = "top"
            ElseIf intFromData = visBeginX Then
                strFrom(intCounter) = "beginX"
            ElseIf intFromData = visBeginY Then
                strFrom(intCounter) = "beginY"
            ElseIf intFromData = visBegin Then
                strFrom(intCounter) = "begin"
            ElseIf intFromData = visEndX Then
                strFrom(intCounter) = "endX"
            ElseIf intFromData = visEndY Then
                strFrom(intCounter) = "endY"
            ElseIf intFromData = visEnd Then
                strFrom(intCounter) = "end"
            ElseIf intFromData >= visControlPoint Then
                strFrom(intCounter) = "controlPt_" & _
                    str(intFromData - visControlPoint + 1)
            Else
                strFrom(intCounter) = "???"
            End If

          '  Debug.Print "From " & vsoConnectFrom(intCounter).Name & " " & strFrom(intCounter)

        Next intCounter

    ConnectedCells1 = Array(vsoConnectTo, strTo, vsoConnectFrom, strFrom)

        If False Then 'debug
        For j = 0 To UBound(ConnectedCells1) - 1
            ar = ConnectedCells1(j)
            text = ""
            For I = 0 To UBound(ar) - 1
            text = text & ar(I) & "  "
            Next I
            'Debug.Print j & " " & text
        Next j
        End If
    ConnectedCells = ConnectedCells1
End Function

возвращает массив указывающий на активные и пассивные соедининия. насколько я понимаю то для каждой сцепки должен быть To и From shape ?
тогда почему так вот странно работает прилагаемый пример ? почему для X.260 не показывается соединение с X.300 ?
вот пример
http://rapidshare.de/files/48047960/glue.vsd.html
выделить 24ый прямоугольник ( на нем номер) , запустить aarestore_glues. макрос покажет только одну связь :
0 line
1 connection point 1
2 X.260
3 end
но очевидно же что этот шейп еще к соседнему прямугольнику привязан.

Go to Top of Page
Previous Topic Topic Next Topic  
Next Page
Данный сайт является архивом форума visio.artberg.ru, который был закрыт в связи с переходом на новую платформу visio.getbb.ru
Все материалы доступны только для чтения! Если у вас появились вопросы, или вы хотите что-то обсудить, связанное с Visio, обращайтесь на новый форум!
Архив был создан благодаря совместным усилиям Генадия Туманова @Tumanov (visio.artberg.ru), Александра ака @Surrogate (visio.getbb.ru), и Николая Белых @nbelyh (unmanagedvisio.com)