Introduction to VA Programming In MicroStation® · 2013. 11. 7. · In a MicroStation dgn file we...

16
Copyright © 2013 Bentley Systems, Inc. Introduction to VBA Programming In MicroStation®

Transcript of Introduction to VA Programming In MicroStation® · 2013. 11. 7. · In a MicroStation dgn file we...

  • Copyright © 2013 Bentley Systems, Inc.

    Introduction to VBA Programming

    In

    MicroStation®

  • Copyright © 2013 Bentley Systems, Inc.

    On the Grid… Our Seminar today is intended to quickly introduce you to a number of concepts in MicroStation VBA.

    We will create a “Grid Maker” applet as a means of accomplishing this task. Along the way, we will be

    exploring MicroStation’s Integrated Development Environment (IDE); MicroStation’s API; various objects

    along with their methods and properties; and the VBA programming language.

    The “Grid Maker” is a simple applet we should be able to complete during the course of the seminar. It

    makes use of fundamental structures and syntax. Yet while simple, it contains a ”standard” module, a

    form and a class module.

    What are forms and modules? In a MicroStation dgn file we group elements into cells, layers and

    models according to their purpose. In a like manner we separate logical sections of a VBA project code

    into understandable sections. In some sense forms, modules and classes serve as containers that enable

    us to organize our code into logical bundles. The following is an overview of that structure:

    Module

    A module is a “container” for code. It contains lists of variables, functions and procedures or

    subroutines.

    Form

    A form is an object such a window or dialog box. Forms usually contain various controls which are

    referred to a child objects. Controls are items such as command buttons, check boxes, text boxes and

    scroll bars.

    A form has both graphical components and code components. Its code component is like a standard

    module. As you build a form graphically by adding various controls such as progress bars, buttons and

    labels, the events, methods and properties accompanying those controls (objects) become available for

    you as a programmer to utilize.

    Class Module

    The visual basic reference defines a Class in this manner: “The formal definition of an object. The class

    acts as the template from which an instance of an object is created at run time. The class defines the

    properties of the object and the methods used to control the object's behavior.”

    A class appears very similar to a standard module; however it has no real use/existence until it is

    instantiated. In the GridMaker program, a class is used as a means for MicroStation to talk to the

    program as if it were a native MicroStation command.

    Procedures (sub routines)

    Forms, Modules, and Class Modules are divided into functions or sub routines (procedures). Typically

    procedures, subs and functions are structured in manner similar to these outlined below:

  • Copyright © 2013 Bentley Systems, Inc.

    Private Sub DoSomething()

    Line of code…

    Line of code…

    Line of code…

    End Sub

    or

    Public Function FigureSomething(input_variable)

    Line of code…

    Line of code…

    Line of code…

    FigureSomething = n

    End Function

    The visual basic reference defines procedures in this manner: “A named sequence of statements

    executed as a unit. For example, Function, Property, and Sub are types of procedures. A procedure

    name is always defined at module level. All executable code must be contained in a procedure.

    Procedures can't be nested within other procedures.”

    Code Lines

    Whereas modules can be broken down into procedures, procedures are broken into lines of code. A few

    things to be aware of with lines as they appear in the VB editor:

    Words that appear in color (magenta) are reserved words that have preset meaning.

    Lines that begin with an apostrophe (‘) are comments and are not executed. These lines will

    display green text with a cyan highlight.

    Text in red is problematic code.

    A line ending in an underscore (_) is continued on the next line.

    A colon (:) is used to separate statements on a line. It acts like a new line.

    Syntax

    We will discuss syntax as the seminar progresses. Unfortunately we won’t have time to address all

    aspects of the VBA language. You will find, however, both Microsoft’s VBA and the MicroStation object

    model are well documented in the help files that ship with MicroStation.

    Getting Help

    In addition to the local help files, there are numerous online resources at your disposal. These include:

    The BE Communities - http://communities.bentley.com/

    Select Services - http://selectservices.bentley.com/en-US/

    The Microsoft Developer Network – www.msdn.com

    http://communities.bentley.com/http://selectservices.bentley.com/en-US/http://www.msdn.com/

  • Copyright © 2013 Bentley Systems, Inc.

    Explanation of GridMaker

    The following is an explanation of various elements and conventions found in the GridMaker applet.

    The applet code in its entirety is here, and is organized by module/form/class. Code appears in the blue

    boxes and again at the end of this document in “print-out” form.

    Startup Module

    Option Explicit

    Public Sub StartGridMaker()

    FrmGridMaker.Show

    End Sub

    FrmGridMaker Form Object

    The FrmGridMaker form (pictured below) contains two text boxes, two labels and a command button.

    The first text box is an object we have named TbRows .

    Option Explicit is a compiler directive that forces explicit

    declaration of variables. It is not a part of a procedure and

    resides at the beginning of a module.

    The Public Sub StartGridMaker procedure will be visible to

    the”outside world” as an executable macro. We use this to start

    the entire program.

    FrmGridMaker.Show causes the FrmGridMaker form to

    appear.

    End Sub is just that. It marks the end of our procedure.

    Form: “GridMakerForm”

    Labels

    Close Button

    Command Button: “CbPlaceGrid”

    Form Caption

    Text box: “TbRows”

    Text box: “TbCols”

  • Copyright © 2013 Bentley Systems, Inc.

    To refer to the text box “TbRows” from a module programmatically we would key in:

    FrmGridMaker.TbRows

    Notice the dot (period) between the form name (container object) and the text box name. The dot

    notation is how we show the “complete path” of an object, method or property. For instance if we

    wanted to programmatically set the background color of the aforementioned text box to red we would

    key in:

    mGridMaker.TbRows.BackColor = vbRed

    While the forgoing sample is something we might do when a

    program is running, we could also change the background color at

    design time through the properties dialog box in the IDE. This

    dialog is usually docked to the left side of the Microsoft Visual

    Basic window

    BackColor Property in properties dialog

  • Copyright © 2013 Bentley Systems, Inc.

    Private Sub TbCols_Exit(ByVal Cancel As MSForms.ReturnBoolean)

    TbCols = Int(Val(TbCols))

    If Val(TbCols) < 1 Then TbCols = 1

    End Sub

    Private Sub TbRows_Exit(ByVal Cancel As MSForms.ReturnBoolean)

    TbRows = Int(Val(TbRows))

    If Val(TbRows) < 1 Then TbRows = 1

    End Sub

    FrmGridMaker Form Code

    Option Explicit

    Private Sub UserForm_Initialize()

    ' pre-populate text fields with default values

    Me.TbRows = 4

    Me.TbCols = 4

    End Sub

    Option Explicit is a compiler directive that forces explicit

    declaration of variables. It is not a part of a procedure

    and resides at the beginning of a module.

    The Private Sub UserForm_Initialize() procedure is

    automatically executed as a result of calling the form’s

    show method in the procedure Startup.StartGridMaker.

    We will use this procedure to pre-populate the text

    fields. Note the procedure is Private. This means it will

    not be assessable from outside the form.

    Any text that appears after an apostrophe (‘) is

    considered a comment and is not compiled into

    executable code.

    MeTbRows = 4 sets the value/text to 4. When setting

    the text box to a string quotes are required e.g.

    MeTbRows = ”ABC”

    End Sub is just that. It marks the end of our procedure.

    The “Me.” statements refer to the object in which they

    appear—in this case the FrmGridMaker form. While not

    necessary “Me.” is helpful in locating objects that are

    children of the form. More to the point, typing “Me.”

    produces a list of the form’s methods, properties and

    child objects.

    These two nearly identical

    procedures respond to text box

    exit events. The exit event

    occurs when the text box loses

    the focus (e.g. the user clicks a

    different control).

    The logic in these procedures

    ensures useable data is entered.

    The Int function returns the

    integer portion of a number and

    the Val function returns a

    number from a string. Note

    these functions are nested.

    In this case, a numeric value is

    derived from the characters in

    the text box through the Val

    function. The Int function then

    removes the decimal portion of

    the number (if it exists).

    This statement ensures a

    number of 1 or greater exists in

    the text box.

  • Copyright © 2013 Bentley Systems, Inc.

    Private Sub CbPlaceGrid_Click()

    CommandState.StartPrimitive New ClsDrawGrid

    End Sub

    Option Explicit

    Implements IPrimitiveCommandEvents

    Dim points(0 To 1) As Point3d

    Dim ClickNumber As Integer

    Dim DM As MsdDrawingMode

    Private Sub IPrimitiveCommandEvents_Start()

    End Sub

    ClsDrawGrid Class Module

    This procedure is launched when the “Place Grid”

    button is pressed. Technically this procedure responds

    to the click event for the CbPlaceGrid command button.

    The CommandState.StartPrimitive New ClsDrawGrid

    statement “tells” MicroStation a new “primitive”

    command is starting and what the command is.

    An instance of the command class (ClsDrawGrid) is

    created and attached to MicroStation. MicroStation

    begins to send user input to the command class and

    program flow moves to the class (See ClsDrawGrid).

    The Implements IPrimitiveCommandEvents provides

    the necessary “connection points” MicroStation requires

    to interact with a command—In this case a command

    that is used to create geometry. The connection points

    are expressed as procedures that must be present--

    even if they don’t do anything.

    The complete list of procedures for

    IPrimitiveCommandEvents is as follows:

    1. IprimitiveCommandEvents_Cleanup() 2. IprimitiveCommandEvents_DataPoint() 3. IprimitiveCommandEvents_Dynamics() 4. IprimitiveCommandEvents_Keyin() 5. IprimitiveCommandEvents_Reset() 6. IprimitiveCommandEvents_Start() Dim statements are used to establish variables of various types.

    Since these Dim statements appear outside a procedure, the variables are visible to the entire module.

    Dim ClickNumber as Integer creates a variable of the type integer

    called “ClickNumber”.

    Dim points(0 to 1) as Point3d creates a (short) array of variables

    which may be reference by the name “points” and a number in

    parenthesis e.g. points(1)

    This procedure is not used in this case. Never-the-less, its presence is required.

    This procedure is called at beginning of the

    command. It might be used to set variables or

    adjust settings.

  • Copyright © 2013 Bentley Systems, Inc.

    Private Sub IPrimitiveCommandEvents_DataPoint(Point As Point3d, ByVal View As View)

    points(ClickNumber) = Point

    ClickNumber = ClickNumber + 1

    If ClickNumber = 1 Then CommandState.StartDynamics

    If ClickNumber = 2 Then DrawGrid points(0), points(1): PrimitiveCommandEvents_Reset

    DM = DrawMode

    DrawGrid points(0), Point

    End Sub

    The IprimitiveCommandEvents_DataPoint procedure is executed each time a data point is sent to MicroStation while our custom

    command is active. The coordinates of the data point as well as what view it was selected from are sent by MicroStation to this

    procedure. Here is what’s happening:

    1. An element of the “points” array is assigned the latest data point coordinates.

    2. The variable ClickNumber is incremented.

    3. Beginning after the first click, dynamics are turned on.

    4. With the second click the grid is drawn and a reset is programmatically executed.

    CommandState.StartDynamics causes MicroStation to

    continuously, with each change in mouse position, execute

    the IPrimitivecommandEvents_Dynamics procedure.

    The IprimitiveCommandEvents_Dynamics procedure is executed whenever the MicroStation cursor is moved. We use this procedure to

    “undraw” and redraw elements to the screen dynamically. The DrawMode variable determines if the element is being erased or

    redrawn. In our example here the DrawGrid procedure is being called with the first data point and the current location of the cursor.

    The effect is a grid the dynamically resizes.

  • Copyright © 2013 Bentley Systems, Inc.

    Private Sub IPrimitiveCommandEvents_Reset()

    CommandState.StopDynamics

    ClickNumber = 0

    End Sub

    Private Sub IPrimitiveCommandEvents_Keyin(ByVal Keyin As String)

    End Sub

    Private Sub IPrimitiveCommandEvents_Cleanup()

    End Sub

    The IprimitiveCommandEvents_Reset procedure is

    executed when the user enters a reset (usually a right

    mouse click).

    CommandState.Stopdynamics halts the calling of

    IprimitivecommandEvents_Dynamics procedure.

    This procedure is not used in

    this case. Never-the-less, its

    presence is required.

    This procedure is not used in

    this case. Never-the-less, its

    presence is required.

    This procedure is called at end

    of the command. It is used to

    take care of “housekeeping”

    matters.

  • Copyright © 2013 Bentley Systems, Inc.

    Sub DrawGrid(LL As Point3d, UR As Point3d)

    Dim Startpt As Point3d

    Dim Endpt As Point3d

    Dim Dif As Point3d

    Dim c As Integer

    Dim Spacing As Double

    Dif = Point3dSubtract(UR, LL)

    'column lines

    Spacing = Dif.X / FrmGridMaker.TbCols

    Startpt.Y = LL.Y

    Endpt.Y = UR.Y

    For c = 0 To FrmGridMaker.TbCols

    Startpt.X = LL.X + (Spacing * c)

    Endpt.X = Startpt.X

    DrawLine Startpt, Endpt

    Next

    'row lines

    Spacing = Dif.Y / FrmGridMaker.TbRows

    Startpt.X = LL.X

    Endpt.X = UR.X

    For c = 0 To FrmGridMaker.TbRows

    Startpt.Y = LL.Y + (Spacing * c)

    Endpt.Y = Startpt.Y

    DrawLine Startpt, Endpt

    Next

    End Sub

    DrawGrid contains the logic for determining the

    locations of the grid lines. It does not actually

    draw the elements to the screen or to the

    MicroStation model—that is handled by the

    DrawLine procedure.

    DrawGrid requires two points be passed to it by

    a calling statement. The points have been

    named LL (Lower Left) and UR (Upper Right).

    Note: It is not critical the points be entered by

    the user in that order.

    Variable declarations.

    The Point3DSubtract function subtracts the

    coordinates of two vectors or points.

    Comments are preceded by an apostrophe(‘).

    In this line we take the x ordinate of the point

    “Dif” and divide it by the value TbCols text box

    found on the form “FrmGridMaker”.

    For – Next Loop

    The contents of this loop is repeated until the

    value ‘c’ is equal to the value in the

    FrmGridMaker.TcCols text box. The starting

    value of c is 0 and it is incremented each time

    the loop is executed.

    This section of code is nearly identical to the

    preceding section that calculated the column

    lines.

  • Copyright © 2013 Bentley Systems, Inc.

    Sub DrawLine(Startpt As Point3d, Endpt As Point3d)

    Dim oLine As LineElement

    Set oLine = CreateLineElement2(Nothing, Startpt, Endpt)

    If ClickNumber = 2 Then

    ActiveModelReference.AddElement oLine

    Else

    oLine.Redraw DM 'Used with dynamics

    End If

    End Sub

    Creation and display of lines

    happens here in the DrawLine

    procedure. Statements that call

    this procedure must pass it two

    points.

    Declare oLine as a Line element

    object

    Object elements need to be Set

    before that can be used. Here we

    use CreateLineElement2 to

    instantiate oLine.

    The block If-then-else statement

    checks the ClickNumber. If it is 2

    the line (part of the grid) is

    added to the current

    MicroStation model, If the value

    is not 2 then the element is

    earthier drawn or undrawn to

    the screen. The variable DM

    controls the draw mode and is

    set by the

    IPrimitivecommandEvents_

    Dynamics procedure.

  • Copyright © 2013 Bentley Systems, Inc.

    Terms The following is a list of terms used in this case study. It is in no way exhaustive. Most of this

    information is available in the “Standard” Visual Basic Reference help or the MicroStation-specific VBA

    reference which will display when searching for help on a particular member in the object browser.

    Control

    An object you can place on a form that has its own set of recognized properties, methods, and

    events. You use controls to receive user input, display output, and trigger event procedures. You

    can manipulate most controls using methods. Some controls are interactive (responsive to user

    actions), while others are static (accessible only through code). – Visual Basic Reference

    Standard controls are readily available from the toolbox in the VBA editor. Other controls may

    be added from the Tools pull-down menu.

    Class Module

    A module that contains the definition of a class, including its property and method definitions. – Visual Basic Reference

    Event

    An event is an action recognized by an object, such as clicking the mouse or pressing a key, and

    for which you can write code to respond. Events can occur as a result of a user action or

    program code, or they can be triggered by the system. – Visual Basic Reference

    Form

    A window or dialog box. Forms are containers for controls. A multiple-document interface (MDI)

    form can also act as a container for child forms and some controls. – Visual Basic Reference

    Method

    A procedure that acts on an object. – Visual Basic Reference

    Module (standard module)

    A module containing only procedure, type, and data declarations and definitions. Module-level

    declarations and definitions in a standard module are Public by default. A standard module is

    referred to as a code module in earlier versions of Visual Basic. – Visual Basic Reference

    Model Reference

    All graphical elements in MicroStation are in models. A Visual Basic program has to access a

    model to be able to save or retrieve graphical elements. A MicroStation session may access

    many models. The models may be in different design files. The same model may be referenced

    different ways. For example, a model may be in use as the active model. There may also be

  • Copyright © 2013 Bentley Systems, Inc.

    different views of the model mapped into the same view. The MicroStation object model treats

    each of these references as a ModelReference object.

    MVBA

    File extension for a MicroStation Visual Basic Project (filename.mvba)

    Procedure

    A named sequence of statements executed as a unit. For example, Function, Property, and Sub

    are types of procedures. A procedure name is always defined at module level. All executable

    code must be contained in a procedure. Procedures can't be nested within other procedures. – Visual Basic Reference.

    Scope

    Defines the visibility of a variable, procedure, or object. For example, a variable declared as

    Public is visible to all procedures in all modules in a directly referencing project unless Option

    Private Module is in effect. When Option Private Module is in effect, the module itself is private

    and therefore not visible to referencing projects. Variables declared in a procedure are visible

    only within the procedure and lose their value between calls unless they are declared Static. –

    Visual Basic Reference.

    String

    A variable that contains a series of letters, sentences paragraphs or entire documents. When

    we need to work with text we use strings

    Sub procedure

    A procedure that performs a specific task within a program, but returns no explicit value. A Sub

    procedure begins with a Sub statement and ends with an End Sub statement. – Visual Basic Reference.

    VBA Visual Basic for Applications

  • Copyright © 2013 Bentley Systems, Inc.

    Launching a MicroStation VBA Macro

    Macros may be launched from MicroStation by selecting the Utilities>Macros>Project Manager menu

    item, loading the project (if necessary) and selecting the “Macros” button.

    When using MicroStation’s command browser, Custom tool or other method that implements Key-ins,

    use one of the following:

    VBA RUN [project name]module_name.subprocedure

    VBA execute subprocedure

    Or VBA execute module_name.subprocedure

    Visual Basic for Applications Configuration Variables

    The following table lists the configuration variables that affect Visual Basic for Applications. Each

    configuration variable expects a valid value. An invalid value will not override a setting. You do not need

    to close and restart in order for the configuration variable change to take effect.

    Variable "Short name" Description

    MS_VBASAVEONRUN "Automatically save VBA

    project"

    If set to 1, automatically saves modified VBA projects every

    time it starts running a VBA program.

    MS_VBAAUTOLOADPROJECTS "Names of standard

    projects"

    Names of the projects that are opened when the VBA dialog is

    opened.

    MS_VBASEARCHDIRECTORIES "Directories to search for

    VBA projects"

    Directories that are searched when opening an existing VBA

    project.

    MS_VBANEWPROJECTDIRECTORY "Directory for new projects" Directory that is used when a new project is created.

    Loads and Runs a Macro

    Runs a visible sub

    procedure that has

    already been loaded.

  • Copyright © 2013 Bentley Systems, Inc.

    Command Button:

    “CbPlaceGrid”

    Text box: “TbRows”

    Text box: “TbCols”

    Startup Module Code

    Option Explicit

    Dim Test As String

    Public Sub StartGridMaker()

    FrmGridMaker.Show

    End Sub

    FrmGridMaker Form Code

    Option Explicit

    Private Sub UserForm_Initialize()

    ' pre-populate text fields with default values

    Me.TbRows = 4

    Me.TbCols = 4

    End Sub

    Private Sub TbCols_Exit(ByVal Cancel As MSForms.ReturnBoolean)

    TbCols = Int(Val(TbCols))

    If Val(TbCols) < 1 Then TbCols = 1

    End Sub

    Private Sub TbRows_Exit(ByVal Cancel As MSForms.ReturnBoolean)

    TbRows = Int(Val(TbRows))

    If Val(TbRows) < 1 Then TbRows = 1

    End Sub

    Private Sub CbPlaceGrid_Click()

    CommandState.StartPrimitive New ClsDrawGrid

    End Sub

    ClsDrawGrid Class Module Code

    Option Explicit

    Implements IPrimitiveCommandEvents

    Dim points(0 To 1) As Point3d

    Dim ClickNumber As Integer

    Dim DM As MsdDrawingMode

    Private Sub IPrimitiveCommandEvents_Start()

    End Sub

    Private Sub IPrimitiveCommandEvents_DataPoint(Point As Point3d, ByVal View As View)

    points(ClickNumber) = Point

    ClickNumber = ClickNumber + 1

    If ClickNumber = 1 Then CommandState.StartDynamics

    If ClickNumber = 2 Then DrawGrid points(0), points(1): IPrimitiveCommandEvents_Reset

  • Copyright © 2013 Bentley Systems, Inc.

    End Sub

    Private Sub IPrimitiveCommandEvents_Dynamics(Point As Point3d, ByVal View As View, ByVal DrawMode

    As MsdDrawingMode)

    DM = DrawMode

    DrawGrid points(0), Point

    End Sub

    Private Sub IPrimitiveCommandEvents_Reset()

    CommandState.StopDynamics

    ClickNumber = 0

    End Sub

    Private Sub IPrimitiveCommandEvents_Keyin(ByVal Keyin As String)

    End Sub

    Private Sub IPrimitiveCommandEvents_Cleanup()

    End Sub

    Sub DrawGrid(LL As Point3d, UR As Point3d)

    Dim Startpt As Point3d

    Dim Endpt As Point3d

    Dim Dif As Point3d

    Dim c As Integer

    Dim Spacing As Double

    Dif = Point3dSubtract(UR, LL)

    'column lines

    Spacing = Dif.X / FrmGridMaker.TbCols

    Startpt.Y = LL.Y

    Endpt.Y = UR.Y

    For c = 0 To FrmGridMaker.TbCols

    Startpt.X = LL.X + (Spacing * c)

    Endpt.X = Startpt.X

    DrawLine Startpt, Endpt

    Next

    'row lines

    Spacing = Dif.Y / FrmGridMaker.TbRows

    Startpt.X = LL.X

    Endpt.X = UR.X

    For c = 0 To FrmGridMaker.TbRows

    Startpt.Y = LL.Y + (Spacing * c)

    Endpt.Y = Startpt.Y

    DrawLine Startpt, Endpt

    Next

    End Sub

    Sub DrawLine(Startpt As Point3d, Endpt As Point3d)

    Dim oLine As LineElement

    Set oLine = CreateLineElement2(Nothing, Startpt, Endpt)

    If ClickNumber = 2 Then

    ActiveModelReference.AddElement oLine

    Else

    oLine.Redraw DM 'Used with dynamics

    End If

    End Sub