I hear quite often the question; “How do I do something in Visio programmatically?” Since many of those requests pertain to flowcharts and organizational charts, I thought I’d conjure up a fairly simple example that illustrates the creation of a flowchart with Visual Basic for Applications (VBA) code.
This isn’t the simplest example, because I thought it would be important to show how a decision-branch might be handled.
Nevertheless, it doesn’t stray too far from the core concepts that you’ll need to understand in order to automate Visio diagram creation:
- Open a template
- Get stencils and master objects
- Drop shapes on the page
- Set shape text and Custom Properties
- Connect the shapes
If you inspect the code, you’ll see that the program flow directly follows the outline above.
When you run the code, you’ll the code will create a simple flowchart that looks something like this:
The decision step is artificially created at step #3. By artificially, I mean that there is no data-source or supreme ethereal logic that dictates “that a decision should be here.” It’s simply the product of our defined constant:
Const DecisionStepNumber% = 3
which you can change at your leisure. Just be sure that it is at least 2 less than NumShapes, or you will run in to errors!
The more complicated bits involve the decision branch. This unfortunately required some If and Select Case blocks that clutter the code to some extent. These decision blocks control how the connections are programmed, to which shapes the connections are glued, how x- and y-offsets are specified, and what the text on the connectors should be. For instance, the “No” connector connects to the right-connection point of the Decision shape, whereas the rest of the connections connect dynamically to the shapes.
Hopefully the comments in the code will explain this more clearly. Below, I’ve included a link to a Visio diagram with more instructions, a convenient “Draw” button in place, and a ready-to-go VBA project that you can inspect and alter to your liking!
Here’s the code:
Sub CreateFlowchart() '// Step 1: get the flowchart template and stencil. '// ------------------------------------------------- '// Define some name-constants. '// We use 'universal names', which are usually U.S. '// english, or short filenames, and will work for '// non-english versions of Visio: Const FlowchartTemplateName$ = "Basic Flowchart.vst" Const FlowchartStencilName$ = "BASFLO_M.VSS" Const MasterProcessName$ = "Process" Const MasterDecisionName$ = "Decision" '// Open a new document: Dim doc As Visio.Document Dim docFlowTemplate As Visio.Document Dim docFlowStencil As Visio.Document Set docFlowTemplate = Visio.Documents. _ Add(FlowchartTemplateName) '// Search open documents for our flowchart stencil: For Each doc In Visio.Documents If (doc.Name = FlowchartStencilName) Then Set docFlowStencil = doc Exit For End If Next Set doc = Nothing '// Step 2: get the masters and connect. '// ------------------------------------------------ Dim mstProcess As Visio.Master Dim mstDecision As Visio.Master Dim conn As Variant '//...note - not a Visio.Master '// Get masters for Process and Decision: Set mstProcess = _ docFlowStencil.Masters.ItemU(MasterProcessName) Set mstDecision = _ docFlowStencil.Masters.ItemU(MasterDecisionName) '// Get the built-in connector object. Note, it's '// not typed as a master! Set conn = Visio.Application.ConnectorToolDataObject '// Step 3: Drop the masters '// ----------------------------------------------- Const NumShapes% = 7 '// Test case to illustrate adding a decision shape. '// Must be at least 2 less than NumShapes. Const DecisionStepNumber% = 3 Dim i As Integer Dim x As Double, y As Double '//...drop locations Const dx# = 1.5 Const dy# = 1 Dim pg As Visio.Page Dim shpNew As Visio.Shape Dim shpLast As Visio.Shape Dim shpConn As Visio.Shape Dim shpDec As Visio.Shape '// We'll draw on the first page of the document, '// which is probably the only page in the document! Set pg = docFlowTemplate.Pages.Item(1) '// Note: if we use auto-layout (see end of this '// procedure), then x- and y aren't super-critical. '// However, some rough positioning will help auto- '// layout to do a better job. '// Get the center, top of the page: x = pg.PageSheet.CellsU("PageWidth").ResultIU / 2 y = pg.PageSheet.CellsU("PageHeight").ResultIU - 1 For i = 1 To NumShapes '// Drop a new shape - either a Process or a '// Decision shape: If i = DecisionStepNumber Then Set shpNew = pg.Drop(mstDecision, x, y) shpNew.Text = i & "?" Set shpDec = shpNew '//...save dec. for later Else Set shpNew = pg.Drop(mstProcess, x, y) shpNew.Text = "Do Step " & i End If '// Set custom properties, illustrating '// two methods: ResultIU and Result: shpNew.Cells(& quot;Prop.Cost").ResultIU = i shpNew.Cells(& quot;Prop.Duration"). Result(Visio.VisUnitCodes.visElapsedHour) = i '// Connect shapes: If (i & lt;> 1) Then '// Drop a connector on the page: Set shpConn = pg.Drop(conn, 0, 0) '// Glue the connector to shpLast and shpNew: '// Note about glueing: By glueing to the PinX '// or PinY of a shape, we get 'Dynamic Glue' '// automatically. For the 'No' on the Decision '// shape, we specifically glue to the '// connection point on the right side of '// the shape. '// First, the Begin cell of the connector, '// glued conditionally to shpLast: If (i = DecisionStepNumber + 1) Then '// Glue to the right side: Call shpConn.CellsU(& quot;BeginX"). GlueTo(shpDec.CellsU(& quot;Connections.X2")) Else '// Glue dynamically: Call shpConn.CellsU(& quot;BeginX"). GlueTo(shpLast.CellsU(& quot;PinX")) End If '// Second, the End cell of the connector, '// glued dynamically to shpNew: Call shpConn.CellsU(& quot;EndX"). GlueTo(shpNew.CellsU(& quot;PinX")) End If '// Set-up variables for the next round. Set shpLast = shpNew '// x, y, and shpLast depend on our '// decision-branch: Select Case i Case DecisionStepNumber x = x + dx Case (DecisionStepNumber + 1) x = x - dx y = y - dy shpConn.Text = "No" Set shpLast = shpDec Case Else y = y - dy End Select Next i '// Step 4: Layout the shapes and deselect. '// ------------------------------------------------ '// Page-layout is one simple call, but look and '// see what our x and y drops have done first, '// then uncomment the next line: 'pg.Layout '// Deselect all shapes, so it looks better: Visio.ActiveWindow.DeselectAll '// Tile the windows so the user doesn't freak out! Call Visio.Windows. Arrange(Visio.visArrangeTileVertical) End Sub
Interesting flowchart links:
- CVF 3.0 Code Visual to Flowchart. A source-code flowcharting tool from Fatesoft.
- Fast Flowcharts An article from Mai-lan’s blog about using Visio’s mutli-form “Flowchart shapes” master.
- Unistep Software for animating process flow, uml sequence and other types of Visio flowcharts.
- John Marshall’s excellent collection of Visio 3rd Party links. Search for ‘flow’ and you’ll get lots of results!
- A nice user tutorial from Informit.com on creating Visio flowcharts and using custom properties, but also dabbles in ShapeSheet and report-generation.
Kunapa Sai says
Hi Visio Guy,
We are planning to generate a Visio file from Excel Macro Enabled file. Data is entered as per the guidelines from Microsoft and we can generate Visio file by exporting the data to Visio manually. However, when we tried to automate this process, its failing as Excel and Visio are expected to be On Focus while the operations are going on.
Please can you share your thoughts on how to handle this? Our requirement is to generate Visio files using this Macro Enabled Excel file data unattended at a server.
Thanks in advance,
Kunapa