Вырезать и вставить форму Visio в макро - PullRequest
0 голосов
/ 04 января 2019

Я пытаюсь написать макрос VBA, который строит базовую диаграмму из данных и определенных шаблонных форм (хранится на отдельной странице). Несмотря на то, что я могу успешно вырезать и вставлять, я, похоже, не могу ссылаться на новую форму после того, как я это сделаю. Я могу переместить форму, прежде чем вырезать и вставить ее, но если я попытаюсь что-либо сделать после этого, я получу ошибку во время выполнения. Существуют различные причины, по которым мне может понадобиться перемещать / обновлять объекты позже, поэтому я должен иметь возможность впоследствии ссылаться на них.

Мой код выглядит следующим образом:

Dim Shape as Visio.Shape
Dim ShapeID as Integer
 
‘copy shape from template page 2, ID 12
Set Shape = Application.ActiveDocument.Pages.ItemU("Page-2").Shapes.ItemFromID(12).Duplicate
 
ShapeID = Shape.ID
MsgBox ("Created shape ID: " & ShapeID)
      
'Now relocate the shape appropriately
currentX = startX + (Count * xSpacing)
currentY = startY
       
Shape.CellsSRC(visSectionObject, visRowXFormOut, visXFormPinX).FormulaForceU = "" & currentX & " mm"
Shape.CellsSRC(visSectionObject, visRowXFormOut, visXFormPinY).FormulaForceU = "" & currentY & " mm"
 
Shape.Cut
   
 'Now go to page 1 and paste the object
 
Application.ActiveDocument.Pages.ItemU("Page-1").Paste

‘*** THE FOLLOWING LINE THAT DOESN’T WORK ***
Set Shape = Application.ActiveDocument.Pages.ItemU("Page-1").Shapes.ItemFromID(ShapeID)
 
Shape.CellsSRC(visSectionObject, visRowXFormOut, visXFormPinX).FormulaForceU = "" & currentX & " mm"
Shape.CellsSRC(visSectionObject, visRowXFormOut, visXFormPinY).FormulaForceU = "" & currentY & " mm"

Если я выполню вышеприведенное, я получаю ошибку «Неверный идентификатор листа» в выделенной строке (форма успешно вставлена). Если я обрежу эту строку, я получу «исключение произошло» в следующей строке, так что похоже, что я потерял свою ссылку на объект.

Ответы [ 3 ]

0 голосов
/ 05 января 2019

Идентификатор фигуры уникален только для ее страницы, поэтому новая фигура, вставленная на страницу 1, получит новый идентификатор и, следовательно, полученную ошибку. Хотя метод Duplicate возвращает ссылку на форму для новой формы, Paste не делает этого, поэтому вам нужно получить ссылку на нее другими способами - либо предполагая что-то о выборе окна (согласно ответу Суррогата), либо по индексу:

Dim shp As Visio.Shape
Dim pag As Visio.Page

Set pag = ActivePage 'or some alternative reference to Page-1
Set shp = pag.Shapes.ItemU(pag.Shapes.Count)
Debug.Print shp.Index

Более обычным рабочим процессом будет генерирование мастеров (в документе трафарета), а затем отбрасывание этих мастеров, а не копирование и вставка между страницами, но ваш сценарий может потребовать другого подхода.

Я добавлю эту ссылку как полезную ссылку для работы со свойствами индекса и идентификатора:

[Update]

@ Комментарий Джона Фурнье, приведенный ниже, совершенно прав, что вышесказанное делает предположения. Например, если ячейка DisplayLevel в исходной фигуре меньше самой верхней фигуры, она будет вставлена ​​в коллекцию фигур страницы с соответствующим индексом, поэтому счетчик не вернет правильную форму. ID. * * +1021

Альтернативным подходом может быть прослушивание события ShapeAdded на страницах (или страницах). Ниже приведена небольшая адаптация примера IsInScope в документах с кодом, размещенным в ThisDocument. Это позволяет вам добавлять и добавлять код в пару идентификаторов области событий, которую вы можете проверить при обработке события ShapeAdded:

Private WithEvents vPags As Visio.Pages
Private pastedScopeID As Long

Public Sub TestCopyAndPaste()

    Dim vDoc As Visio.Document
    Set vDoc = Me 'assumes code is in ThisDocument class module, but change as required

    Dim srcPag As Visio.Page
    Set srcPag = vDoc.Pages.ItemU("Page-2")

    Dim targetPag As Visio.Page
    Set targetPag = vDoc.Pages.ItemU("Page-1")

    Dim srcShp As Visio.Shape
    Set srcShp = srcPag.Shapes.ItemFromID(12)

    Set vPags = vDoc.Pages

    pastedScopeID = Application.BeginUndoScope("Paste to page")

    srcShp.Copy
    targetPag.Paste

    Application.EndUndoScope pastedScopeID, True

End Sub

Private Sub vPags_ShapeAdded(ByVal shp As IVShape)
    If shp.Application.IsInScope(pastedScopeID) Then
        Debug.Print "Application.CurrentScope " & Application.CurrentScope
        Debug.Print "ShapeAdded - " & shp.NameID & " on page " & shp.ContainingPage.Name
        DoSomethingToPastedShape shp
    Else
        Debug.Print "Application.CurrentScope " & Application.CurrentScope
    End If
End Sub

Private Sub DoSomethingToPastedShape(ByVal shp As Visio.Shape)
    If Not shp Is Nothing Then
        shp.CellsU("FillForegnd").FormulaU = "=RGB(200, 30, 30)"
    End If
End Sub
0 голосов
/ 05 января 2019

Я не нашел отличный способ справиться с этим. У меня есть метод, который вставляет буфер обмена на страницу и возвращает все новые фигуры, перечисляя все идентификаторы фигур до и после вставки, а затем возвращая новые фигуры.

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

0 голосов
/ 05 января 2019

Конечно, вы получаете ошибку «Неверный идентификатор листа»! Потому что в «Page-1» вы можете иметь форму с ShapeID , который вы определили для формы, помещенной в «Page-2».

Вы можете вставить форму и после этого шага определить выбранную форму.

Application.ActiveDocument.Pages.ItemU("Page-1").Paste

' You can define this variable as shape which is selected
Set Shape = Application.ActiveWindow.Selection.PrimaryItem

Почему вы используете переменную два раза?

...