FT-V03

Diagramming FoxPro: Visio Automation

Andrew MacNeill
AKSEL

What Is Visio?

Microsoft Visio is a drawing and diagramming tool that has been around for quite a few years. It was one of the first non-Microsoft products to incorporate support for automation and it has kept up its support for automation to such a degree that Visio is not only part of Microsoft Office, it is also a key component of the Microsoft BizTalk. This session discusses Visio from both a business diagramming and then automation perspective.

A Visio document is similar to an Excel workbook in that it can have different pages. Each page, in turn, contains shapes. Shapes are created from stencils. All of these items (documents, pages, shapes and stencils) may be controlled in code, starting from the application layer.

Unlike a drawing program like Paint, a typical Visio session (see below) contains a document and a stencil. Stencils contain shapes specifically designed for a purpose. Visio Professional for example includes stencils specifically for network diagrams, project management and organization charts. The shapes on stencils are very similar to classes in Visual FoxPro. They create a shape on a document that can then be manipulated in the same way a class may be instantiated as an object on a form.

Shapes may then be linked to each other with connectors. Connectors may be “hooked” onto individual nodes of a shape. Shapes can also have custom properties (just like an Outlook folder) and custom actions. It is in these custom properties where Visio has taken some major leaps and bounds in terms of application development. A custom property may be used to store information about a shape or real-world information about what that shape represents.

 

The Visio software document with stencils for project management.

Database Modelling Tools

The Visio Database Tool provides the ability to reverse engineer and to refresh existing databases. Unfortunately, it does not provide a means for creating the database. From the File menu, select Database Model diagram from the New database submenu. A blank page along with two stencils appear. The stencils include shapes for Entity Relationship diagrams or Object Relationship diagrams. Both stencils have Entity, View, and relationship shapes, all of which are standard parts of a database model. The real benefit of using Visio is the Database menu that appears along with the blank page. You can reverse engineer any ODBC database by selecting Reverse Engineer. Visio reads in the tables of a FoxPro database and identifies indexes and primary keys. The downside of Visio's ability to reverse engineer a FoxPro database is that it only reads the tables and the indices. It stops short of reading the views and relationships. As a result, you have to manually create them yourself.

Another downside of the Visio database model is the reporting benefits are limited. While it generates a beautiful set of web pages or hard-copy layouts, there is little in the way of database documentation. Visio stores all the right information but it doesn't let you export it, which makes it fairly limited.

So why use it? One of the great features of the database modeling in Visio is its ability to change how it appears with just a few mouse-clicks (figure 2 shows two different views of the same database). By changing the Documenting Options, you can select between different modeling symbol sets, determine what should be displayed and make it easy to display to users. Another reason is the level of detail that is stored in the model itself. When an entity is created, either from scratch or reverse engineering, the shape itself has user-defined properties, detailing the table structure. When a relationship is created between two entities, its properties help define the relationship for both database development use and for display purposes

The information that Visio collects is a great way of sharing database-related information with non-developers.

Another example of Visio's focus on software development is its software modeling diagrams. Visio provides templates for almost all of the different symbols one might use: Booch OOD, Yourdon and Coad, Rumbaugh OMT, Jacobsen Use Cases as well as some fairly generic ones such as COM and OLE and Windows Interface Design. It also provides a "Fusion" templates that combines stencils from several of them (see figure 4).

Figure 4 – Mix and match modeling symbols. Visio's Fusion set combines symbols from Booch, Jacobson and Rumbaugh to provide less formalized but more useful symbols for diagramming.

 

Automating Visio

Just as Visio’s user interface is similar to Excel’s, its object model is similar to Excel’s in how much customization can be done at each level. The Application object is primarily a placeholder for accessing documents, menus and configurations. The real meat of a Visio solution is in the document and the shapes contained within.  Here are just a handful of the objects accessible via the Viso interface.

Key pieces of the Visio Object Model. The Blue items are Collections; the yellow items are objects.

Here is how to create a new Visio document using one of the pre-defined templates.

loVisio = CREATEOBJECT("Visio.Application")

loDoc = loVisio.Documents.Add("Flowchart\Basic Flowchart.vst")

Call the Open method to open an existing document.

loDoc = loVisio.Documents.Open("\My Documents\Diagram.vsd")

Visio installs several templates into a Solutions folder. The TemplatePath property of the Application object returns the name of the folder containing the templates. Refer to the Path property of the Application object to identify where Visio is installed. If the VST file (Visio Template) is located somewhere else, pass it the full pathname of the file. Pass an empty string to the Add method to create a blank document.

The Documents collection refers to all documents and stencils open in the Visio session. The Basic Flowchart document contains 3 stencils (backgrounds, basic flowchart shapes and borders/titles). Therefore, the Count property of loDoc returns 4: one for the main document and one for each stencil open.

As the Documents collection contains separate documents, each document is made up of pages. A stencil only contains a single page. Pages in turn, contain shapes.

The only exception to this is with stencils. Stencils are made up of "master shapes", which basically describes a shape and its attributes. Every Visio document contains a Masters collection, which refers to the various "master shapes" that are used on it. The Masters collection for a document will contain all of the "master shapes" in that document.

This code goes through each open document and displays the master shapes in it.

FOR EACH loDoc IN loVisio.Documents

   FOR EACH loMaster IN loDoc.Masters

      ? loMaster.Name

   ENDFOR

ENDFOR

Since Visio opens up many documents, it is critical to be able to refer to them easily. A document may be referred to by an index number or by its name. When referring to a stencil, you must include the ".VSS" extension. The ActiveDocument property of the Application object also refers to the currently active document.

** Refers to a basic document

? loVisio.Documents("Drawing5").Masters.Count

** Refers to the basic flowchart stencil

? loVisio.Documents("basic flowchart shapes.vss").Masters.Count

Creating a Shape

All work done with shapes is done on a Page. Use the Draw methods to draw shapes that are not related to master shapes (see below). There are a few Draw methods that make use of arrays. These methods are unavailable to FoxPro developers as arrays must be passed in a format that FoxPro cannot create. These methods are DrawBezier, DrawPolyLine and DrawSpline.

 

Method

Description

DrawLine(x1,y1,x2,y2)

Draws a line from the coordinates at x1,y1 and x2,y2.

DrawOval(x1,y1,x2,y2)

Draws an oval shape from the upper left coordinates at x1,y1 to x2,y2.

DrawRectangle(x1,y1,x2,y2)

Draws a rectange from the lower left coordinates of x1,y1 to x2,y2.

Drawing basic shapes. Although Visio deals mostly with stencils, use the Draw methods to create basic shapes.

Unlike Visual FoxPro, coordinates in Visio are not based on Left and Top. Visio uses a geometrical format where points 0,0 are the lower left hand corner of the page. Since Visio uses a page interface, the coordinates are done in terms of the page size, usually in inches.

** Create a pointer to the current page

loPage = loDoc.Pages(1)

** Creates a rectangle that goes 1 inch

** to the right and 5 inches to the top

loRect = loPage.DrawRectangle(0,0,1,5)

 

Once a shape has been created, it can be referenced via the Shapes collection. Set the Name property of the shape to make it more accessible. Set the Text property of the shape to have text appear with the object.

loRect.Name = "MyRect"

loPage.Shapes("MyRect").Text = "My Rectangle"

 

Call the Drop method to create a shape based on a stenciled or "master" shape. The Drop method takes 3 parameters: a pointer to the master shape, and the x and y coordinates.

The Decision shape is contained on the "Basic Flowchart Shapes" stencil.

** Grab a pointer to the shape stencil

loStencil = loVisio.Documents("basic flowchart shapes.vss")

** Grab a pointer to the Decision shape

loShape = loStencil.Masters("Decision")

** Drop the object into position 2,5

loDecision = loPage.Drop(loShape,2,5)

Some Basic Needs

The pleasure of dealing with Visio is the simplicity of its calls. There are not 20 different parameters to a call. Nowhere is this clearer than with file handling and printing.

Once you've built your document, call the Print method of the Page or Document to print it. There are no parameters as it will use the default printer.

** Print the current page

loPage = loVisio.ActivePage

loPage.Print()

** Print the entire document

loDoc = loVisio.ActiveDocument

loDoc.Print()

Call the SaveAs method to save a document. Once a document has been saved initially, call the Save method to make any subsequent saves. The SaveAs method takes only one parameter which is the name of the file you want to save.

loDoc = loVisio.ActiveDocument

loDoc.SaveAs("C:\My Documents\Diagram.vsd")

Working with Shapes

Shapes are like people – they come in all kinds of sizes and with all kinds of different information. One of the benefits of Visio is that a shape may have properties that are specific to it. For example, in the Project Management template, the Task Bar shape has a start date, end date and a duration attribute associated with it. A basic shape such as a rectangle doesn't have those same attributes. Likewise, a Decision shape in our flowchart may have other attributes. As a result, Visio places this information into what it calls a "ShapeSheet".

The ShapeSheet is basically a worksheet that is broken into different sections (see table below). The Section refers to the type of information. Each section has Rows and Columns. Columns change depending on the section you are working with. For example, the columns for the connection point section are related to points. The columns for user-defined properties are Prompt, Label, Format, Sortkey, Type and Value. Visio provides up to 254 columns, although in most cases, they are not used.

Section Index

Description

1 – Object

Cells related to information not found elsewhere.

3 – Character

Character related properties such as font and style.

4 – Paragraph

Paragraph formatting properties such as indents and alignment of paragraph.

5 – Tab

Properties related to tab alignment.

6 – Scratch

Scratch properties used for temporary storage of information.

7 – Connection Points

Properties related to how other shapes can connect to the current shape.

8 – Text field

Properties related to the text displayed in a shape.

9 – Controls

Properties related to control handles which are used for connecting shapes.

240 – Action

Actions that appear when the user right-clicks on the shape.

241 – Layer

Layer-related information.

242 – Custom user properties

Properties defined by an external solution.

243 – Properties

User-defined properties.

244 – Hyperlinks

Links to other objects.

The ShapeSheet breaks details about a shape into sections and then stores information as row and column.

Moving shapes is a great introduction to the concept of the shapesheet.

Contents of the ShapeSheet are accessed through a shape's Cells property. A cell is an object that contains a number of different properties. The value of the cell is stored in the ResultIU property.

Property

Description

Column

The column number of the cell.

ContainingRow

A pointer to the row object that contains the cell.

Formula

The formula value of the cell. A formula might be a calculated value such as Min(Width/Height) * 5

IsInherited

Logical value indicating if the Cell is inherited from a master or a style. This behaviour is similar to checking if a property is the default value.

Name

The name of the cell.

Result(lnUnit)

The value of the cell, returned based on the value of lnType. The main reason to pass lnType is to convert a result into another format (such as between inches to feet, etc). Some of the more common types are:

32 – Numeric

40 – Date

65 – Inches

66 - Feet

69 – Centimeters

252 – No Cast

To enter the value entered is returned, use 252.

ResultIU

The value of the cell, returned in Visio's internal units. This is the ideal property for returning integer values. Use the ResultSTR property for returning strings.

ResultStr (lnUnit)

The value of the cell, returned as a string. lnUnit  must be passed just like the Result property.

Row

Row index of the cell.

Section

Section index of the cell.

Units

The unit type of the cell. The value is similar to that of lnUnit, described above.

Understanding Cells.  A single cell contains information that may be used for a variety of purposes.

Two dimensional shapes, like rectangles and stenciled shapes, are handled differently than one dimensional shapes, like lines. To move a line, change the BeginX, EndX or BeginY and EndY cell values. To move a shape, change the PinX and PinY cells.

** Move the decision tree to the right by five

loDecision.Cells("PinX").ResultIU = loDecision.Cells("PinX").ResultIU + 5

This example shows cells as being an essential part of a shape's position. But cells may also be used to store non-descript information, such as properties about a shape. The Decision shape for example, contains custom properties indicating cost, duration and resources. These properties may be found in the user-defined properties section.

** Return cost of decision

? loDecision.Cells("Prop.Cost").ResultStr(252)

Cells may be referred to by their name but if you are exploring an existing diagram, you may not know the name. To learn about these entries, you can refer to them by the section and row using the CellSRC property.

The following code goes through each of the rows and cells in the user-defined properties.

FOR lnRow = 1 TO loDecision.Section(243).Rows.Count

   ? loDecision.Section(243).Rows(lnRow-1).Name

   lc = loDecision.CellsSRC(243,lnRow-1,1).Name

   ** Returns the result string in string format

   ? loDecision.Cells(lc).ResultSTR(252)

ENDFOR

You can also call the CellExists method of the shape to verify that a cell does, in fact, exist. This is very important because if you attempt to access a cell that does not exist, Visio returns an ambiguous message that says "End of File". The CellExists method takes two parameters: the first is the name of the cell, the second is a logical value indicating if the search should be local to the shape or if it should include inherited cells. You must pass the second parameter in order to return a value.

IF loDecision.CellExists("MyName",.T.) = 0

   MESSAGEBOX("The Cell MyName does not exist.")

ENDIF

Visio is first and foremost a diagramming application. As such, it also provides valuable functions for block functions on shapes. The Rotate90 method rotates a shape 90 degrees counterclockwise. Call FlipHorizontal or FlipVertical to quickly change the orientation of a shape. To completely reverse a shape, call the ReverseEnds method.

Connecting Shapes

Once a document has several shapes on it, it is possible to connect them. The GlueTo method ensures that a connection is attached to the shapes so that it if the user moves them, the connection moves to.

loResult = loPage.Drop(loShape,7,7)

loLine = loPage.DrawLine(5,5,6,7)

loLine.Cells("BeginX").GlueTo(loDecision.Cells("Connections.X4"))

loLine.Cells("EndY").GlueTo(loResult.Cells("Connections.X3"))

Working Interactively with Users

Part of the benefits of working with Visio is that the solution can be interactive. The ActiveWindow or Window object points to the view that the user currently sees.

The Selection property of the Window object returns a collection of objects that are currently selected by the user.

loWin = loVisio.ActiveWindow

IF loWin.Selection.Count = 0

   MESSAGEBOX("Nothing has been selected.")

ELSE

   FOR EACH loItem IN loWin.Selection

      ? loitem.name

   ENDFOR

ENDIF

Call the Select method of the ActiveWindow object to select or deselect a shape. The first parameter to this method is the object itself. The second is either 1 to de-select or 2 to select.

IF loWin.Selection.Count>0

   ** Get pointer to object

   loShape = loWin.Selection.Item(1)

   ** De-select object

   loWin.Select(loShape, 1)

   ? loWin.Selection.Count

   loWin.Select(loShape, 2)

   ? loWin.Selection.Count

ENDIF

This works very well for selecting individual shapes. Call the SelectAll method of the window object to select all of the shapes. Call DeSelectAll to remove it.

Conclusion

In this session, I’ve attempted to show how Visio can be used in a variety of ways. While some of its more “design-oriented” templates don’t offer developers much automation, Visio can be used for more than just automating work. If you can build some stencils, you will find that Visio can be the perfect way of giving diagramming to your users and to your development group.