Форум пользователей Visio
http://visio.getbb.ru/

В макросе нужно узнать наличие и параметры стрелки у линии
http://visio.getbb.ru/viewtopic.php?f=29&t=1200
Страница 1 из 1

Автор:  АлексейАБ [ 25 авг 2017, 20:47 ]
Заголовок сообщения:  В макросе нужно узнать наличие и параметры стрелки у линии

Здравствуйте
Пишу VBA-макрос Visio для формирования текстового описания VISIO-схемы бизнес-процесса (EPC-схема).
Один из элементов описания - связи операции бизнес-процесса, входящие (условия исполнения операции) и исходящие (возможные решения исполнителя операции).
Нужно узнать наличие и параметры стрелки на каждой стороне линии, соединяющей операцию с соседними элементами.
Все элементы схемы получаю. Множество всех линий, связанных с каждым элементом тоже получаю и все пары связанных фигур определить могу. Но мне нужно направление каждой связи, а я не нашел элементы объектной модели, описывающие стрелки на линиях!
Прошу помощи. Полагаю, не знаю "базовых" принципов построения объектной модели Visio. В схемах возможно применение элементов множества типов. У каждого типа свои индивидуальные свойства и состав типов можно расширять, конструировать самостоятельно. Как VBA работает с элементами, описание которых имеет неизвестную заранее структуру? Все элементы составные из множества элементов и самый "нижний" уровень - базовые элементы? Если предположение верное, то стрелка на линии есть множество элементов (линии и/или треугольники и т.д.). Пытался найти, но не смог. Кроме того, для меня важно знать на какой стороне (на связи с каким соседним элементом) находится стрелка...
Спасибо!

Автор:  Tumanov [ 25 авг 2017, 21:48 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Цитата:
? Если предположение верное, то стрелка на линии есть множество элементов (линии и/или треугольники и т.д.).

Чаще всего неверное.
Вот на картинке показано, как управлять стрелками через шейп-лист (ShapeSheet).
Макрос как раз так и должен действовать.

Вложения:
arrow.gif
arrow.gif [ 67.23 Кб | Просмотров: 983 ]

Автор:  Tumanov [ 25 авг 2017, 21:51 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Вот так устанавливается третий тип стрелки в начало линии.
Код:
Sub ttt()
    Dim sh As Visio.Shape
    Set sh = ActivePage.Shapes(1)
    sh.Cells("BeginArrow") = 3
End Sub

То есть в ячейку с именем "BeginArrow" записывается код типа стрелки.
Оттуда же можно и прочитать значение. Примерно так:
Код:
Debug.Print sh.Cells("BeginArrow")

Автор:  Tumanov [ 25 авг 2017, 21:57 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Цитата:
Как VBA работает с элементами, описание которых имеет неизвестную заранее структуру?

Программист старается такого не допускать.
Если объект сложный и собран из множества шейпов, то стараются данные вынести куда-нибудь в доступное именованное место, чтобы программа могла с ними общаться.
Чаще всего это user-defined секция или ShapeData.
А если большой чертеж нарисовать одними черточками, то пытаться его обработать программно практически бесполезно.

Автор:  nbelyh [ 25 авг 2017, 22:38 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

К сожалению здесь все не так просто.
В Visio все соединители направленные, даже те, что не имеют никаких стрелок. Также направление соединителя "по объектной модели" может противоречить стрелкам.
У каждого соединителя есть "Begin" и "End". Стрелки в объектной модели считаются элементами декора, поэтому могут располагаться произвольно.

Так что во первых нужно решить, как ты хочешь определять направление коннектора - согласно объектной модели или же согласно стрелкам.

API довольно простой, и он есть:

shape.ConnectedShapes (<направление>)

Но он ориентируется вовсе не по стрелкам.
Для "стрелок" нужно выбрать, какие именно тебе интересны. Их куча. Например если вот такие "стрелки", куда направлено соединение?

Изображение

Мы использовали примерно вот такой вот код для определения "направления"
(числа - наше определение что является "стрелкой", определяющей направление коннектора):

Код:
enum Direction
{
   Direction_None   = 0,
   Direction_To   = 1,
   Direction_From   = 2,
   Direction_Both   = 3,
};

long GetArrowDirection(IVShapePtr shape, short side)
{
   IVCellPtr arrow_cell   = shape->GetCellsSRC(visSectionObject, visRowLine, side);
   bstr_t arrow_text      = arrow_cell->GetResultStr(long(visNone));
   long arrow            = _ttol(arrow_text);

   struct ArrowDirection { short begin; short end; short direction; };

   // Visio arrow codes
   static const ArrowDirection arrow_directions[] =
   {
      { 0,   0,   Direction_None },
      { 1,   8,   Direction_To   },
      { 9,   11,   Direction_From   },
      { 12,   19,   Direction_To   },
      { 20,   26,   Direction_From   },
      { 27,   30,   Direction_To   },
      { 31,   38,   Direction_From   },
      { 39,   40,   Direction_To   },
      { 41,   42,   Direction_From   },
      { 43,   45,   Direction_To   },
   };

   for (size_t i = 0; i < countof(arrow_directions); ++i)
   {
      const ArrowDirection& rec = arrow_directions[i];
      if (rec.begin <= arrow && arrow <= rec.end)
         return rec.direction;
   }
   return Direction_None;
}

///  ....... bla-bla-bla ..........

   long src_arrow   = GetArrowDirection(shape, visLineBeginArrow);
   long dst_arrow   = GetArrowDirection(shape, visLineEndArrow);

   if (src_arrow != Direction_None && src_arrow != Direction_Both)   
      src_arrow ^= Direction_Both;

   long direction = (src_arrow | dst_arrow);

   if (direction & Direction_To)
      /// TO

   if (direction & Direction_From)
      /// FROM


Сорри что это не VBA, переводить лениво. Основная ценность - магические числа (константы). На VBA я думаю не так сложно будет переписать :oops:

Автор:  АлексейАБ [ 28 авг 2017, 14:05 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Огромное спасибо за помощь !
Однако, мне не помогло :(
Пусть переменная vShape есть анализируемый объект схемы - прямоугольник с текстом. Как его нашел - не важно.
Выполнение MsgBox(vShape.Text) подтверждает что нужный объект имеется. В схеме этот прямоугольник описывает операцию.
Теперь мне нужны соединенные с прямоугольником линии. Пока независимо от направления.
В переменную vCount = vShape.FromConnects.Count получаю количество соединений у прямоугольника.
Обратил внимание, если линия НЕ "привязана" к прямоугольнику (соединяется только визуально), такое "соединение" здесь не учитывается.
Пока нормально.
Далее цикл от 1 до vCount и vDot = vShape.FromConnects(vN) - перебираю соединения с прямоугольником.
У каждого соединения есть vDot.FromCell.Shape и vDot.ToCell.Shape.
Выбираю тот вариант, который не связан с исходным прямоугольником.
If vDot.FromCell.Shape.ID <> vShape.ID Then
Set vLine = vDot.FromCell.Shape
Else
Set vLine = vDot.ToCell.Shape
End If
Итого есть соединительная линия vLine.
Линии в схеме "надписал" и да, MsgBox(vLine.Text) выводит надписи линий.
Нормально.

Далее. Для каждой линии можно перебрать ее "соединители" на двух концах
For Each vConnect In vLine.Connects
'Один из "соединителей" привязан к моему прямоугольнику, а мне интересен противоположный.
If vConnector.FromCell.Shape.ID <> vShape.ID And vConnector.ToCell.Shape.ID <> vShape.ID Then
'Текущий "соединитель" линии НЕ связан с исходным прямоугольником - это нужный соединитель - нужная сторона линии
'Выбираю сторону "соединителя", которая связана не с линией
If vConnector.FromCell.Shape.ID <> vLine.ID Then
Set vNextShape = vConnector.FromCell.Shape
End If
If vConnector.ToCell.Shape.ID <> vLine.ID Then
Set vNextShape = vConnector.ToCell.Shape
End If

MsgBox ("Линия " & vLine.Text & " связывает анализируемый прямоугольник с блоком " & vNextShape.Text)

End If
Нормально.
НО ОСТАЛСЯ ВОПРОС.
Я могу узнать ОТСУТСТВИЕ стрелки на концах линии:
vLine.Cells("BeginArrow") = 0 ИЛИ vLine.Cells("EndArrow") = 0,
но я не могу узнать какой конец линии считается ее реальным началом. Тот который связан с анализируемым (исходным) прямоугольником или тот который связан с найденным связанным блоком.
Если узнаю сторону линии, соединенную с исходным прямоугольником, смогу проанализировать vLine.Cells("BeginArrow") = 0 ИЛИ vLine.Cells("EndArrow") = 0 и определить "входящая" связь или "исходящая".
У линии есть свойство FromCell.Shape.ID. Предположил, можно сравнить с vConnector.ID, но у vConnector нет свойства ID !
Вот такая проблема ...

Автор:  Tumanov [ 28 авг 2017, 14:25 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Цитата:
но я не могу узнать какой конец линии считается ее реальным началом.

Написано много...
Но, кажется, Вам нужно посмотреть свойства FromPart, ToPart.
Эти свойства могут принимать значения, указывающие в какое место, каким концом и т.д. присоединены шейпы.
Немного смущает понятие "реальное" начало, но скорее всего путем эксперимента Вы найдете нужное именно в Вашем случае значение.
Цитата:
Предположил, можно сравнить с vConnector.ID, но у vConnector нет свойства ID !

А вот так не бывает.
Если vConnector - шейп, то ID (который есть у всякого шейп) должен быть и у него.
==============
Извиняюсь... Это же у Вас не шейп, а объект Connect.
Но у него есть свойства FromSheet, ToSheet, указывающие на шейпы с обеих сторон (от коннекта). То есть линия и квадратик. А у шейпов есть ID.

Автор:  Tumanov [ 28 авг 2017, 14:47 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Вот это не поможет?
FromPart = 9 означает visBegin
То есть для Visio это начало линии.

Вложения:
cnct.jpg
cnct.jpg [ 56.05 Кб | Просмотров: 923 ]

Автор:  АлексейАБ [ 28 авг 2017, 15:20 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Не понял ...
У линии есть два коннектора. Возьмем первый vLine.Connects(1).
У него есть свойства FromShape, ToShape, FromPart, ToPart, но это свойства коннектора, НЕ линии !
Я этими свойствами пользуюсь в приведенном ранее коде. Одна сторона коннектора связана с линией, другая с фигурой, к которой привязан соответствующий конец линии. О направлении самой линии информацию не получу. Где я ошибаюсь?

Автор:  Tumanov [ 28 авг 2017, 15:42 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Коннектор (Connector) - это линия.
Connect - это точка, соединение.
(Это мелочи - просто поправка в терминологии).
У линии могут быть 0, 1, 2, а иногда (редко) больше объектов Connect.
Теперь возьмем первый vLine.Connects(1).
FromSheet указывает на шейп-линию. FromPart покажет начало или конец линии.
ToSheet укажет на квадрат. ToPart покажет присоединенную часть квадрата (центр, слева, справа, номер ConnectionPoint и т.д.).
То есть, мы можем понять, что данный Connect описывает соединение начала линии и первого ConnectionPoint квадрата.
Это надо было узнать?

Автор:  Tumanov [ 28 авг 2017, 15:45 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Соответственно, если подключить второй конец линии к другому квадрату и рассмотреть его Connect, то вместо значения FromPart=9 будет уже FromPart=12 - конец линии.

Автор:  Tumanov [ 28 авг 2017, 15:52 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Кстати, у нас же есть вот такой материал по анализу соединений: viewtopic.php?f=39&t=1142

Автор:  nbelyh [ 28 авг 2017, 16:05 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Направление "по API" может не совпадать со стрелками. Например, на картинке ниже все стрелки, если на них смотреть "через API", будет одинаковы.
Изображение

Если у тебя всего один тип стрелок (и пользователь не может / не должен менять стрелки "руками"),
например, имеет "правильный" коннектор на стенсиле, то вообще не стоит со стрелками заморачиваться, и использовать то что дает API.
То есть, в этом случае НЕ НУЖНО АНАЛИЗИРОВАТЬ СТРЕЛКИ ВООБЩЕ, From - это From, To - это To, и все.
В Visio так работает 99% всех встроенных функций. Так что не усложняй себе жизнь, если нет на то необходимости.

В случае, если ты хочешь с этим возиться, см. мой пост выше..
Я думаю что код решает эту задачу (определение направлния TO/FROM "коннектора" по "стрелкам", а не по объектной модели).
Просто код нужно переписать на VBA (оформить в виде функции, принимающей шейп коннектора на входе).
Как-то так:
Код:
Public Enum Direction
   Direction_None = 0
   Direction_To = 1
   Direction_From = 2
   Direction_Both = 3
End Enum

Function GetArrowDirection(shp As Shape, side As Integer) As Direction
   Dim arrow_cell As Cell
   Set arrow_cell = shp.CellsSRC(visSectionObject, visRowLine, side)
   Dim arrow As Long
   arrow = CLng(arrow_cell.ResultStr(visNone))

   If 1 <= arrow And arrow <= 8 Then
    GetArrowDirection = Direction_To
   ElseIf 9 <= arrow And arrow <= 11 Then
    GetArrowDirection = Direction_From
   ElseIf 12 <= arrow And arrow <= 19 Then
    GetArrowDirection = Direction_To
   ElseIf 20 <= arrow And arrow <= 26 Then
    GetArrowDirection = Direction_From
   ElseIf 27 <= arrow And arrow <= 30 Then
    GetArrowDirection = Direction_To
   ElseIf 31 <= arrow And arrow <= 38 Then
    GetArrowDirection = Direction_From
   ElseIf 39 <= arrow And arrow <= 40 Then
    GetArrowDirection = Direction_To
   ElseIf 41 <= arrow And arrow <= 42 Then
    GetArrowDirection = Direction_From
   ElseIf 43 <= arrow And arrow <= 45 Then
    GetArrowDirection = Direction_To
   Else
    GetArrowDirection = Direction_None
   End If
End Function

Function GetDirection(conn As Shape) As Direction
    Dim src_arrow As Direction
    src_arrow = GetArrowDirection(conn, visLineBeginArrow)
    Dim dst_arrow As Direction
    dst_arrow = GetArrowDirection(conn, visLineEndArrow)

    If src_arrow <> Direction_None And src_arrow <> Direction_Both Then
      src_arrow = src_arrow Xor Direction_Both
    End If

    Dim dir As Direction
    GetDirection = src_arrow Or dst_arrow
End Function

Sub test()

    Debug.Print GetDirection(ActivePage.Shapes(1))  ' ==> 1, TO
    Debug.Print GetDirection(ActivePage.Shapes(2))  ' ==> 2, FROM
    Debug.Print GetDirection(ActivePage.Shapes(3))  ' ==> 0, NONE
    Debug.Print GetDirection(ActivePage.Shapes(4))  ' ==> 3, BOTH

End Sub


Вложения:
Drawing3.vsd [40.5 Кб]
Скачиваний: 112

Автор:  Гость [ 28 авг 2017, 16:27 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Спасибо !
Очень неожиданной оказалась структура, где объект типа Connect хранит признак начала и окончания соединенной с ним линии. Я ожидал нужную мне информацию в свойствах линии.
Еще раз спасибо!
Получилось.

Автор:  nbelyh [ 28 ноя 2021, 16:00 ]
Заголовок сообщения:  Re: В макросе нужно узнать наличие и параметры стрелки у линии

Если тебе нужны соединенные шейпы (к которым идут соединения), просто используй shape.ConnectedShapes
Она учитывает направление (по API), у нее есть для этого параметр.
Это намного проще чем .Connects и вся возня с ними.

vShape.ConnectedShapes

Пример использования там же, в MSDN.

Страница 1 из 1 Часовой пояс: UTC + 3 часа [ Летнее время ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/