Visio Guy

Visio Discussions => Programming & Code => Topic started by: AhmedAl on July 21, 2019, 12:55:15 PM

Title: Struggling when transforming VBA code to Python using win32com module
Post by: AhmedAl on July 21, 2019, 12:55:15 PM
Hello everyone,


Thanks to everyone contributing to this forum, it's really helping me !

I recently started generating visio files using Python and I have problems with many aspects of visio generation : filling the shapes with specific color, setting the page scale, setting particular font style ....
Can you help me please ?

Right now, I'm stuck with this code (for shapes filling):

objVapp = win32com.client.Dispatch("Visio.Application")
# objVapp = win32com.client.gencache.EnsureDispatch("Visio.Application")
# objVapp.Interactive = False

objVdProc = objVapp.Documents.Add("")

Rect = objVdProc.Pages("PdG").DrawRectangle(1, Coord_y,1 , 1)
Rect.CellsSRC(visSectionObject, visRowXFormOut, visXFormPinX).FormulaU = Coord_x
Rect.CellsSRC(visSectionObject, visRowXFormOut, visXFormWidth).FormulaU = Largeur
Rect.CellsSRC(visSectionObject, visRowXFormOut, visXFormHeight).FormulaU = Hauteur

Rect.Cells("FillPattern").FormulaU = "1"
Rect.Cells("FillForegnd").FormulaU = "THEMEGUARD(RGB(%s,%s,%s))" %(R_Fond, V_Fond, B_Fond)
Rect.Cells("FillBkgnd").FormulaU = "THEMEGUARD(SHADE(FillForegnd,LUMDIFF(THEME(""FillColor""),THEME(""FillColor2""))))"

I have the following error caused by the line just before the last one:
com_error: (-2147352567, 'An exception has occured.', (0, 'Dessin2 - Visio Professionnel', '\n\n#NAME?', None, 0, -2032466907), None)

And even when I'm trying to set a particular font style for the text, I'm getting a similar error, here is my code (error in the 1st line):

Rect.CellsSRC(visSectionCharacter, 0, visCharacterStyle).FormulaU = Carac_Police
Rect.Cells("Char.size").FormulaU = "96 pt"#Taille_Police
Rect.CellsSRC(visSectionCharacter, 0, visCharacterUnderline).FormulaU = True
Rect.CellsSRC(visSectionCharacter, 0, visCharacterColor).FormulaU = "THEMEGUARD(RGB(%s,%s,%s))" %(R_police, V_police, B_police)
Rect.CellsSRC(visSectionCharacter, 0, visCharacterFont).FormulaU = "4" #equivalent to "Arial"

Thanks :)
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Yacine on July 21, 2019, 01:58:28 PM
Hello Ahmed,

  Rect.Cells("FillForegnd").FormulaU = "THEMEGUARD(RGB(%s,%s,%s))" %(R_Fond, V_Fond, B_Fond)

The a.m. line worked fine for me. I had of course to define the "xx_Fond" variables first.
You may check whether it's a visio or a python thing, but replacing the formula by one with constants. eg:
  Rect.Cells("FillForegnd").FormulaU = "THEMEGUARD(RGB(100,100,100))"

Cordialement,
Y.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: AhmedAl on July 22, 2019, 12:35:37 PM
Thanks Yacine, It worked, it looks like I was getting it wrong.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: AhmedAl on July 24, 2019, 11:38:40 AM
Hello,

it's me again !

Right now, I'm stuck with this code (inserting jpg images into a shape):

Rect = objVdProc.Pages("PdG").DrawRectangle(1, Coord_y,1 , 1)
Rect.CellsSRC(visSectionObject, visRowXFormOut, visXFormPinX).FormulaU = Coord_x

Rect.CellsSRC(visSectionObject, visRowXFormOut, visXFormWidth).FormulaU = Largeur
Rect.CellsSRC(visSectionObject, visRowXFormOut, visXFormHeight).FormulaU = Hauteur

Rect.Cells("LineColor").FormulaU = "THEMEGUARD(RGB(255,255,255))"
filePath = "C:/Users/aallali/Documents/EDF rédaction de consignes/Logo_edf(1).jpg"
Rect.Import(filePath)

It gave me this error:
  File "C:/Users/aallali/Documents/EDF rédaction de consignes/Notebooks/Génération_Visio_1.0.1.py", line 2652, in <module>
    Rect.Import(filePath)

com_error: (-2147352567, 'An exception has occured.', (0, 'Dessin2 - Visio Professionnel', '\n\nObjet Inappropriate target for this operation.', None, 0, -2032465762), None)

Thanks
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: vojo on July 24, 2019, 05:30:49 PM
Not an expert but I believe the problem is that Rect defines a rectangle...I dont think you can import a picture into a rectangle.   You may want different kind of object to manage the JPG

Could just turn on Macros and do a copy and paste of an image to see what kind of object is used.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Yacine on July 25, 2019, 05:13:11 AM
I agree with Vojo, that a shape can't be a target for an import operation, although the method is available and documented ... Strange!

2 Methodes to get pictures in Visio:
- choose a page as target. eg activepage.import ...
- create a fill pattern with the image, then apply it to the desired shape.

PS: in VBA in calls to subs the arguments are written without parenthesis. --> activepage.import filePath
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: metuemre on July 25, 2019, 06:46:47 AM
An example in VBA http://visguy.com/vgforum/index.php?topic=7960.30 (http://visguy.com/vgforum/index.php?topic=7960.30)
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: AhmedAl on July 30, 2019, 09:51:50 AM
Thanks everyone, and thanks metuemre for the last file :)

In fact, I tried only a small step (just importing a random image in empty visio file) and I got com_error as usual, I'm growing frusturated with this ...

This is my code:


import pandas as pd
import sys, win32com.client
import time
from win32com.client import constants

# Visio must be open and I used a "Basic Diagram" template
objVapp = win32com.client.Dispatch("Visio.Application")
# objVapp = win32com.client.gencache.EnsureDispatch("Visio.Application")
# objVapp.Interactive = False

objVdProc = objVapp.Documents.Add("")
objVdProc.Pages(1).Name = "PdG"

objVdProc.Pages(1).Background = False # pas arrière plan donc 1er plan
objVdProc.Pages(1).BackPage = ""

filePath = "C:/Users/myPC/Documents/EDF rédaction de consignes/Logo_edf(1).jpg"

objVapp.ActivePage.Import(filePath)

The error was:

com_error: (-2147352567, 'An exception has occured.', (0, 'Dessin2 - Visio Professionnel',"\n\nAn error has occured. Impossible to keep importing.", None, 0, -2032466039), None)

Please find the image in the attachements
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: vojo on July 30, 2019, 12:13:42 PM
again...in visio, turn macro recording on and do the paste.   Then look at the resulting macro to see the VBA involved.

As far as python goes, I think you only have to values of VBA objects
I.e. do whatever you want in native Python then use the win32, shape, cell, formula to plug in values to visio.

Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Nikolay on July 30, 2019, 02:25:43 PM
Visio was designed with VBA in mind, not Python. Not sure why you have chosen python to work with Visio; you get all sorts of problems, starting with configuration, lack of code samples, obscure error messages, lack of intellisense (auto-completion), and finally performance issues.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Paul Herber on July 30, 2019, 02:36:18 PM
Quote from: AhmedAl on July 30, 2019, 09:51:50 AM
The error was:

com_error: (-2147352567, 'An exception has occured.', (0, 'Dessin2 - Visio Professionnel',"\n\nAn error has occured. Impossible to keep importing.", None, 0, -2032466039), None)

Please find the image in the attachements

I can almost foresee the day when computers could be powerful enough to convert -2147352567 and -2032466039 into something more human readable.
(-0x7FFDFFF7 and -0x7924F877 respectively.)
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: AhmedAl on July 30, 2019, 03:02:03 PM
@Nikolay because I work on a machine learning project where the output of would be a visio file, and when you say machine learning you say Python & R (but not VBA).
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Nikolay on July 30, 2019, 03:18:23 PM
You could use SVG as output maybe? That has much better support in python.
Note that you can open SVG with Visio.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Yacine on July 31, 2019, 10:30:17 AM
Hello Ahmed,
Please find below a code sample that imports an image and makes some basic manipulations with it.
import win32com.client
from win32com.client import constants

def mm2in(x):
    return x / 25.4
def in2mm(x):
    return x * 25.4

# Preparation
template = 'BASICD_M.VSTX' # That's my basic template. Replace by your own.
vApp = win32com.client.Dispatch("Visio.Application")
vApp.Visible = 1
vDoc = vApp.Documents.Add(template)
vPg = vDoc.Pages.Item(1)
vWin = vApp.ActiveWindow

vPg.Name = 'PdG'
vPg.PageSheet.CellsU('DrawingResizeType').FormulaU = '2'

# Importing the image
img_path = 'C:\\Users\\aallali\\Documents\\EDF rédaction de consignes\\Logo_edf(1).jpg'
vImg = vPg.Import(img_path)

# Resizing the image
# Locking the aspect ratio doesn't really lock it when manipulating directly the height and the width by code
img_h = 20
hw_ratio = vImg.CellsU('Height').ResultIU / vImg.CellsU('Width').ResultIU
vImg.CellsU('Height').FormulaU = str(mm2in(img_h))
vImg.CellsU('Width').FormulaU = str(vImg.CellsU('Height').ResultIU  / hw_ratio)

# Positioning the image on the top right corner
margin = 10 # mm

w = in2mm(vPg.PageSheet.CellsU('PageWidth').ResultIU)
h = in2mm(vPg.PageSheet.CellsU('PageHeight').ResultIU)
print(x,y)

vImg.CellsU('LocPinX').FormulaU = 'Width * 1'
vImg.CellsU('LocPinY').FormulaU = 'Height * 1'

x = w - 2 * margin
y = h - 2 * margin
print(x,y)


vImg.CellsU('PinX').FormulaU = str(x) + 'mm'
vImg.CellsU('PinY').FormulaU = str(y) + 'mm'

# duplicate the image
vImg2 = vImg.Duplicate()

# Position it in the left top corner
vImg2.CellsU('LocPinX').FormulaU = 'Width * 0'
x = margin
vImg2.CellsU('PinX').FormulaU = str(x) + 'mm'
vImg2.CellsU('PinY').FormulaU = str(y) + 'mm'

Keep in mind to use the macro recorder to get the syntax of the commands to use.
The supplied code is just a quick demo. Ideally you would re-write it as set of functions to make it re-usable. Have a look at the library I built for myself. It's an IPython notebook though.

Rgds,
Y.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: AhmedAl on August 01, 2019, 02:56:34 PM
It worked, thank you Yacine.

I started using the macro recorder, so hoepfully I'll get less issues.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Yacine on August 02, 2019, 08:13:56 AM
de rien ;)
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: AhmedAl on August 19, 2019, 10:06:19 AM
Hi everyone,

Right now, I'm trying to inset a stencil in an empty visio file.
I'm hesitating between literally copying and pasting this stencil in my empty visio (my preferred option) or reproducing the shape by myself directly in my visio (I consider this as my last option).

I tried to the copy/paste option using macro recording but it didn't work in python.
Below the recorded macro, the stencil is in the attachements:

Sub Macro1()

    'Enable diagram services
    Dim DiagramServices As Integer
    DiagramServices = ActiveDocument.DiagramServicesEnabled
    ActiveDocument.DiagramServicesEnabled = visServiceVersion140 + visServiceVersion150

    Application.ActiveWindow.Page.Paste

    'Restore diagram services
    ActiveDocument.DiagramServicesEnabled = DiagramServices

End Sub


Did anyone try this copy/paste procedure ?

Thanks  :)
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Paul Herber on August 19, 2019, 11:46:23 AM
You can't copy and paste stencils into a Visio document, you need to use the ActiveDocument.Open or .OpenEx methods.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Yacine on August 19, 2019, 12:13:48 PM
Hi Ahmed,

I think you want to drop a master from a stencil on your drawing, isn't it?

The recorder would produce:
Sub Makro1()

    'Enable diagram services
    Dim DiagramServices As Integer
    DiagramServices = ActiveDocument.DiagramServicesEnabled
    ActiveDocument.DiagramServicesEnabled = visServiceVersion140 + visServiceVersion150

    Application.Windows.ItemEx("Zeichnung1").Activate
    Application.ActiveWindow.Page.Drop Application.Documents.Item("C:\Users\  ...  \Downloads\Gabarit1.vssx").Masters.ItemU("Gd Op.E-V.112"), 9.027862, 7.677165

    'Restore diagram services
    ActiveDocument.DiagramServicesEnabled = DiagramServices

End Sub

Most of the code is useless, you need to strip it down.

    'Enable diagram services
    Dim DiagramServices As Integer
    DiagramServices = ActiveDocument.DiagramServicesEnabled
    ActiveDocument.DiagramServicesEnabled = visServiceVersion140 + visServiceVersion150


    Application.Windows.ItemEx("Zeichnung1").Activate
     Application.ActiveWindow.Page.Drop Application.Documents.Item("C:\Users\  ...  \Downloads\Gabarit1.vssx").Masters.ItemU("Gd Op.E-V.112"), 9.027862, 7.677165

    'Restore diagram services
    ActiveDocument.DiagramServicesEnabled = DiagramServices


It's the blue text you were after (drop)

The red code translates simplier to "activepage"

The green code is the name of your stencil - with or without path, depending on whether you saved it to your stencils folder or somewhere else.

The purple code is the name of the master to drop

and finally the 2 numbers are the coordinates where to preform the drop

You can google all these parameters.

In VBA you will get:
ActivePage.Drop Application.Documents.Item(stencil_name).Masters.ItemU(master_name), x, y

In Python you would just modify the parantheses, and because you have some preparation work, there won't be directly an activepage - you would have stored it in variable.
visio_page.Drop(visio_app.Documents.Item(stencil_name).Masters.ItemU(master_name), x, y)
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: AhmedAl on August 20, 2019, 04:04:26 PM
Thanks Yacine & Paul.

Actually, a stencil has exactly the characteristics of a shape i.e. you can modify its background/foreground color, dimensions, color ... (beginner's discoveries ;D )

Here is the small script for stencils:

objVdProc = objVapp.Documents.Add("")
objVdProc.Pages(1).Name = "PdG"

stencilpath = "C:\\Users/........................\\Gabarit1.vssx"
objVapp.Documents.Open(stencilpath)

objVapp.Windows.ItemEx("Dessin1").Activate
Forme= objVdProc.Pages("PdG").Drop(objVapp.Documents.Item("Gabarit1.vssx").Masters.ItemU("Gd Op.E-V.112"), 8.46875, 8.06664)

Forme.CellsSRC(constants.visSectionObject, constants.visRowXFormOut, constants.visXFormWidth).FormulaU = "117.7644 pt"
Forme.CellsSRC(constants.visSectionObject, constants.visRowXFormOut, constants.visXFormHeight).FormulaU = "127.5781 pt"

Forme.CellsSRC(constants.visSectionObject, constants.visRowXFormOut, constants.visXFormPinX).FormulaU = "609.75 pt"
Forme.CellsSRC(constants.visSectionObject, constants.visRowXFormOut, constants.visXFormPinY).FormulaU = "555.0 pt"

Forme.CellsSRC(constants.visSectionObject, constants.visRowFill, constants.visFillForegnd).FormulaU = "THEMEGUARD(RGB(%s,%s,%s))" %(R_Fond1, V_Fond1, B_Fond1)
Forme.CellsSRC(constants.visSectionObject, constants.visRowFill, constants.visFillPattern).FormulaU = "1"

Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: wapperdude on August 20, 2019, 04:27:37 PM
Think you're missing Paul's point, and, you're mixing terms.

Stencil is a collection of shapes.
Shapes are the objects that get placed upon a drawing page.  They may be 2-D shapes, e.g,. square, circle, or 1-D shapes, e.g., lines, connectors, or other items, e.g., picture, Excel worksheet.

So, when you you use those terms interchangeably, gets quite confusing for both us and for you.

For example, your code line: Forme= objVdProc.Pages("PdG").Drop(objVapp.Documents.Item("Gabarit1.vssx").Masters.ItemU("Gd Op.E-V.112"), 8.46875, 8.06664) is dropping  shape GD O.E-V.112, from stencil Gabarit1.vssx.  And, yes, you can do some shape editing while it still resides on the stencil.

Hope this clears up the difference in the terms.  It'll make communication easier and less confusing.


Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Yacine on August 20, 2019, 04:50:14 PM
To add to Paul's and Wapperdude's notes, there's a very good article from our host, definitely worth reading: http://www.visguy.com/2008/02/25/edit-visio-masters-programmaticallythe-right-way/
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Remko on May 21, 2021, 12:44:01 PM
Application.Documents.Item("C:\Users\  ...  \Downloads\Gabarit1.vssx")

How would one go about to change the path so it points to the Document Stencil? (Master?)

so that when you rename the visio file its still works
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Paul Herber on May 21, 2021, 01:03:24 PM
The document stencil doesn't exist as a stencil entity that you can create a path to.
You can access it via the Masters object.
Title: Re: Struggling when transforming VBA code to Python using win32com module
Post by: Remko on May 21, 2021, 01:31:39 PM
I cant find out how. im not a programmer.

this is my current working code:

ThisDocument.Application.Windows(ThisDocument.Index).Activate
Application.ActiveWindow.Page.Drop Application.Documents.Item("Template.vsdm").Masters.ItemU("Titleblock_01"), 0, 0#


How would it look when one take out the Template.vsdm and how then call on the master?