1
votes

Couper et coller une forme Visio dans une macro

J'essaie d'écrire une macro VBA qui construit un diagramme de base à partir de données et de certaines formes de modèle (conservées sur une page séparée). Bien que je puisse couper et coller avec succès, je semble être incapable de référencer la nouvelle forme après avoir fait cela. Je peux déplacer la forme avant de la couper et de la coller, mais si j'essaye de faire quoi que ce soit après coup, je rencontre une erreur d'exécution. Il y a plusieurs raisons pour lesquelles je pourrais avoir besoin de déplacer / mettre à jour les objets plus tard, donc je dois être en mesure de les référencer par la suite.

Mon code est le suivant:

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"

Si j'exécute ce qui précède, j'obtiens l'erreur "Identificateur de feuille non valide" à la ligne en surbrillance (la forme est collée avec succès). Si je coupe cette ligne, j'obtiens "une exception s'est produite" sur la ligne suivante, il semble donc que j'ai perdu ma référence à l'objet.


0 commentaires

4 Réponses :


1
votes

Bien sûr, vous obtenez l'erreur "Identificateur de feuille invalide"! Parce qu'à "Page-1", vous pouvez avoir une forme avec ShapeID , que vous avez défini pour la forme placée à "Page-2".

Vous pouvez coller la forme et après cette étape définir la forme sélectionnée.

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

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

Pourquoi utilisez-vous la variable deux fois?


4 commentaires

Peut-être que je ne comprends tout simplement pas comment ces méthodes fonctionnent, mais ce que je pensais se produisait ici (et semble fonctionner) est 1. Sélectionnez l'élément (sur la page 2). 2. Dupliquez l'élément (sur la page 2) et stockez l'ID dans ShapeID. 3. Coupez l'article. 4 Collez l'élément sur la page 1. Tout fonctionne dans le code ci-dessus, mais ce que je veux faire est de déplacer la forme que j'ai collée sur la page 1. Si je supprime la ligne de problème, Shape ne contient pas de référence du tout (il semble le perdre à la pâte). Si je le mets, je veux qu'il trouve celui que j'ai collé.


Désolé, je n'ai pas vu que vous aviez également modifié le code. L'élément collé sera donc celui sélectionné? Si c'est le cas, cela a du sens, mais je ne comprends pas très bien pourquoi mon code n'aurait pas fonctionné également. Un ID de forme change-t-il si je le déplace d'une page à l'autre?


Oui, l'ID de la forme a changé lorsque vous le collez dans une autre page. ID en général, est le numéro correspondant à l'ordre d'ajout des formes à la page! Veuillez en savoir plus sur Propriété Shape.ID , regardez Remarques


Droite. C'est la grande chose qui me manquait. Le vote positif en tant qu'explication a maintenant un sens pour moi et vous avez fourni du code pour résoudre le problème. Merci beaucoup!



2
votes

L'ID d'une forme est uniquement unique à sa page, donc la nouvelle forme que vous collez dans la page 1 recevra un nouvel ID et donc l'erreur que vous recevez. Bien que la méthode Duplicate renvoie une référence de forme à la nouvelle forme, Paste ne le fait pas, vous devez donc y faire référence par d'autres moyens - soit en supposant quelque chose à propos de la sélection de la fenêtre (selon la réponse de Surrogate) ou par index:

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

Un flux de travail plus habituel serait de générer des masques (dans un document gabarit) puis de supprimer ces masques plutôt que de copier et coller entre les pages, mais votre scénario peut nécessiter une approche différente.

Je vais ajouter ce lien comme référence utile pour traiter les propriétés d'index et d'ID:

[Update

Le commentaire de @Jon Fournier ci-dessous est tout à fait exact que ce qui précède fait des suppositions. Par exemple, si le DisplayLevel dans la forme source est inférieure à la forme la plus haute, elle sera collée dans la collection de formes de la page à l'index correspondant et donc count ne retournera pas l'ID de forme correct.

Une autre approche pourrait consister à écouter le événement ShapeAdded sur les pages (ou page). Ce qui suit est une légère adaptation de IsInScope exemple dans la documentation, avec le code placé ThisDocument. Cela vous permet de compléter et de terminer votre code dans une paire d'ID d'étendue d'événement que vous pouvez inspecter lors de la gestion de l'événement ShapeAdded:

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


3 commentaires

Je ne me souviens pas quand, mais je me suis brûlé en supposant que la forme collée était la dernière dans la collection de formes


Merci. Le plus important pour moi a été de découvrir que ce n'est pas la même référence sur différentes pages. Cela clarifie vraiment ce qui se passe.


Oui, bon point @Jon. Avoir une réponse mise à jour avec une approche alternative.



1
votes

Je n'ai pas trouvé de moyen efficace de gérer cela. J'ai une méthode qui va coller le presse-papiers sur une page et renvoyer toutes les nouvelles formes, en listant tous les identifiants de forme avant et après le collage, puis en renvoyant de nouvelles formes.

Si la vitesse est un gros problème pour moi, je vais généralement coller sur une page masquée vide, faire tout ce que je dois sur cette page, puis couper et coller sur la page de destination. Si vous avez besoin de coller avec d'autres formes, cela ne fonctionnera pas vraiment, mais quand cela a du sens, j'utilise cette logique.


1 commentaires

Heureux que ce ne soit pas seulement moi qui ai le problème. La vitesse n'est pas un problème car l'idée était d'écrire un script qui prenait une description du flux que je voulais, puis de le créer une fois (j'en ai beaucoup à dessiner et les exigences changent tous les jours, donc c'était une idée qui économisait du travail. ). La solution ci-dessous donne un moyen d'identifier l'élément collé, il semble donc que j'ai une solution, mais votre solution de contournement est également valide pour mes besoins.



0
votes

Au lieu de Dupliquer et couper et coller, utilisez simplement Drop:

Dim srcShape, dstShape as Shape
Set srcShape = ActiveDocument.Pages("Page-2").Shapes("srcShape")
Set dstShape = ActiveDocument.Pages("Page-1").Drop(srcShape, 0, 0)

Après ce qui précède, vous pouvez accéder à dstShape et en faire ce que vous voulez.

p>


0 commentaires