Community Pick: Many members of our community have endorsed this article.
Editor's Choice: This article has been selected by our editors as an exceptional contribution.

Programming PowerPoint with VBA to add random shapes to a slide

Jamie Garroch (MVP)PowerPoint Technical Consultant
CERTIFIED EXPERT
Eating, sleeping, breathing PowerPoint and VBA at BrightCarbon
Published:
Updated:

Setting the Scene

PowerPoint is a creative tool in the right hands but it also includes a much underutilised programming dimension. In this beginner level article, we're going to show you some of some key elements of programming PowerPoint using the VBA (Visual Basic for Applications) editor that's included with Microsoft Office.

We're going to build a small project that is fairly arbitrary in order to demonstrate several key elements of VBA programming. The project will add a user-defined number of random shapes to a given slide.

What is Covered?

We're going to look at the following elements when building a simple macro to add a sequence of randomly sized, randomly positioned and randomly coloured shapes:


  1. The two types of procedures Sub and Function
  2. Constants, Variables and Arrays
  3. Selected PowerPoint object model properties
  4. User input
  5. Random numbers
  6. Shape creation
  7. Shape formatting

When you've completed the project, you will be able to create the arbitrary random slide like the one shown below in less than a second!

Random-PowerPoint-Shapes.png

Prerequisites

You will need any version of PowerPoint (including Mac) that uses the latest graphics engine and theme design model. This includes 2013 (which we will use), 2010, 2007 and 2011 for the Mac. Your version of PowerPoint must also have the VBA environment enabled (it is installed by default but your IT administrator may have disabled it).

Getting Started

The first thing to do is to recognise that you will be working in two windows, the PowerPoint slide view that you will be familiar with as a PowerPoint content author and the VBE (Visual Basic Editor). You can either Alt+Tab between the two windows, set them up on a different displays if you have a multi-monitor setup or use the Windows snap feature to show them side-by-side on your desktop.

Opening the VBE

To start the VBE:


  1. Open PowerPoint and create a new blank presentation
  2. Press Alt+F11 to open the VBE window:
    VBE---new-project.png
  3. Pretty boring right? Well, that's because there is no content VBA project yet so the first thing to do is to add a code module to the VBA Project. From the VBE menu, click Insert followed by Module:
    VBE---new-module.png
  4. Now we have a code module, we can start adding code. Code is separated into Procedures and each one has a start and and an end as shown in the procedure of type Sub: (the name "mySub" is arbitrary and you can choose whatever you want)
    VBE---Sub-start-and-end.png
  5. Once a procedure is defined, you "just" have to write the code lines within it and we'll start with a really basic single line macro:
    VBE---Hello-World.png
  6. This is now a complete macro and we can run it by pressing the green Run arrow in the toolbar or pressing F5 when the cursor is somewhere within the procedure. Note that we can also run it from the main PowerPoint window by pressing Alt+F8 and selecting the macro myFirstCode but this only works if the procedure is (a) of type Sub (b) not declared as Private (c) does not have any paramaters in the parenthesis. When run, this macro simply displays a message for the user:
    Hello-World-msgbox.png

Getting Stuck In

Now that you know how to create a VBA project, let's step back and think about what we need our program to do:


  1. We want to define a subset of shapes from the large library that PowerPoint supports
  2. We need to ask the user how many shapes to add
  3. We need to get the current slide and add a shape of a random size in a random position and then fill it with a random colour from the presentation theme
  4. We need to repeat #3 the number of times requested by the user input in #2

It is good practice to start every code module with the line Option Explicit. What this does is to force the VBA compiler to check that variables have been declared. While this isn't strictly necessary, it will save a lot of debugging issues as your projects get larger and you make the inevitable typos with variables in your code.

Option Explicit

Next, we are going to define a couple of constants to set the minimum and maximum size of the random shapes, which are available globally to any procedure in the project. These are defined outside of procedures:


Public Const ShapeMinSize = 50
Public Const ShapeMaxSize = 200

Now, VBA provides a nice random number generator function called Rnd which generates numbers between 0 and 1 (but not 1 itself). We want to be able to generate integer numbers between different lower and upper limits so instead of repeating the same code multiple times, we're goign to create a function procedure. A function can optionally accept one or more input parameters and optionally returns a single value, string or object.

This is our function to create a random number within provided limits:

Function GetRandomInt(Lower As Integer, Upper As Integer) As Integer
  Dim number As Single
  
  ' Initialize the random-number generator with a seed based on the system timer
  Randomize
  
  Do
    ' Get a random number between 0 and < 1
    number = Rnd()
    ' Scale it up to the upper limit
    number = number * Upper
  Loop While number < Lower ' Repeat until the number is above the lower limit
  
  ' Set the value returned by the function
  GetRandomInt = number
End Function

It's worth pointing out at this stage that it's also good practice to add comments to your code and these are made in VBA by prefixing your comment with a apostrophe.

The function accepts two integer parameters for the Lower and Upper limits and returns a value as an Integer.

The next step is to create our main macro procedure of type Sub:

Sub AddRandomShapes()

End Sub

Checking back on our list of things to do, we need to define the shapes we want to use. Shape types in PowerPoint are defined using an enumeration. Enumerations allow human readable names to be associated with integer values. For example, we could create a custom enumaeration for fruit:


Public Enum Fruit
  Apple
  Orange
  Pear
End Enum

This would assign value of 0 to 2 for the three fruit types which we could then refer to in code by the fruit names. In the same way, Microsoft has defined enumerations for many aspects of the PowerPoint object model. There are over 150 different pre-defined shapes such as rectangle, oval, stars etc. and they are defined by the enumeration msoAutoShapeType. You can check the values in the VBE for enumerations by opening the Object Model with F2 and searching for enumerations, properties, methods and more. We have decide to use the various star shapes in our macro and because the values are not contiguous, we put them in an array so that we can refer to them with our random number generator:


Sub AddRandomShapes()
  Dim ShapeIDArray(1 To 10) As Integer

  ' Shape types are defined with the enumeration msoAutoShapeType
  ' Stars (points) : 149 (10), 150 (12), 94 (16), 95 (24), 96 (32), 91 (4), 92 (5), 147 (6), 148 (7), 93 (8)
  
  ' Load with star shapes
  ShapeIDArray(1) = msoShape10pointStar
  ShapeIDArray(2) = msoShape12pointStar
  ShapeIDArray(3) = msoShape16pointStar
  ShapeIDArray(4) = msoShape24pointStar
  ShapeIDArray(5) = msoShape32pointStar
  ShapeIDArray(6) = msoShape4pointStar
  ShapeIDArray(7) = msoShape5pointStar
  ShapeIDArray(8) = msoShape6pointStar
  ShapeIDArray(9) = msoShape7pointStar
  ShapeIDArray(10) = msoShape8pointStar

So, calling ShapeIDArrary(3) will return the enumerated value for a 16 point star.

We now need to declare variables for the shape position and size:

  Dim shpTop As Single, shpLeft As Single, shpWidth As Single, shpHeight As Single

And because the user could be using a 16:9 slide, a 4:3 slide or any other slide size, we need to declare variables for the slide height and width:


  Dim sldWidth As Single, sldHeight As Single

Finally, we need variables for a loop counter, the number of shapes the user wants to add and an object declaration for the shape that we will add in each occurence of our loop:


  Dim counter As Integer
  Dim NumShapes As Integer
  Dim oShp As Shape

When the macro starts, we need to find out the slide dimensions and we use the SlideWidth and SlideHeight properties in the cascading object model. These properties belong to PageSetup which in turn belongs to the ActivePresentation (the presentation currently in view). The VBA object model is hierarchical and each level is separated with a dot, so these are the two lines we need to get the dimensions saved into our variables:


  sldWidth = ActivePresentation.PageSetup.SlideWidth
  sldHeight = ActivePresentation.PageSetup.SlideHeight

You'll notice that when you type a dot at the end of a valid property, if it has any children, the Microsoft system called IntelliSense will show you permitted child properties and methods. This makes self-discovery of the object model much easier.

Next we need to get the number of shapes to be added by the user and we use the InputBox function for this:


  NumShapes = Val(InputBox("How many random shapes to you want to add to this slide?", _
    "Macro by youpresent.biz", 100))

Note that we've split this line in two to make it easier to read. You can do this with any line of code by adding a space plus an underscore at the point where you want to break the line and then press return.

Now we need to set up the main loop in which the shapes will be added to the slide:

  For counter = 1 To NumShapes

  Next

Within this loop, we need to calculate the shape size and position and we call our random number generator function GetRandomInt to do this:


    shpWidth = GetRandomInt(ShapeMinSize, ShapeMaxSize)
    shpHeight = shpWidth
    shpLeft = GetRandomInt(-shpWidth, CInt(sldWidth))
    shpTop = GetRandomInt(-shpWidth, CInt(sldHeight))

We're now going to use the very useful With statement. What this does is allow us to shorten our code by eliminating the need to repeat long object model statements. We want to do something the the collection of shapes in the current slide in view so this line sets that up for us:


    With ActivePresentation.Slides(ActiveWindow.View.Slide.SlideIndex).Shapes

And the thing we want to do is add a shape. We could just add the shape and forget about it but because we want to adjust the formatting of the shape after it's been added to the slide, we need to Set a reference to the new shape object:


      Set oShp = .AddShape(ShapeIDArray(GetRandomInt(1, 10)), _
        shpLeft, shpTop, shpWidth, shpHeight)

We're going to set a random fill colour from the 6 accent colours of the presentation theme, set a transparnecy of 70%, turn on the outline and make it white:


      With oShp
        .Fill.ForeColor.ObjectThemeColor = GetRandomInt(5, 10)
        .Fill.Transparency = 0.7
        .Line.Visible = msoTrue
        .Line.ForeColor.RGB = RGB(255, 255, 255)
      End With


Putting It All Together

Adding the closing lines to loops, we end up with our completed code:


Option Explicit

Public Const ShapeMinSize = 50
Public Const ShapeMaxSize = 200

Sub AddRandomShapes()
  Dim ShapeIDArray(1 To 10) As Integer
  Dim shpTop As Single, shpLeft As Single, shpWidth As Single, shpHeight As Single
  Dim sldWidth As Single, sldHeight As Single
  Dim counter As Integer
  Dim NumShapes As Integer
  Dim oShp As Shape
  
  ' Shape types are defined with the enumeration msoAutoShapeType
  ' Stars (points) : 149 (10), 150 (12), 94 (16), 95 (24), 96 (32), 91 (4), 92 (5), 147 (6), 148 (7), 93 (8)
  
  ' Load with star shapes
  ShapeIDArray(1) = msoShape10pointStar
  ShapeIDArray(2) = msoShape12pointStar
  ShapeIDArray(3) = msoShape16pointStar
  ShapeIDArray(4) = msoShape24pointStar
  ShapeIDArray(5) = msoShape32pointStar
  ShapeIDArray(6) = msoShape4pointStar
  ShapeIDArray(7) = msoShape5pointStar
  ShapeIDArray(8) = msoShape6pointStar
  ShapeIDArray(9) = msoShape7pointStar
  ShapeIDArray(10) = msoShape8pointStar
  
  sldWidth = ActivePresentation.PageSetup.SlideWidth
  sldHeight = ActivePresentation.PageSetup.SlideHeight
  
  NumShapes = Val(InputBox("How many random shapes to you want to add to this slide?", _
    "Macro by youpresent.biz", 100))
  
  For counter = 1 To NumShapes
    shpWidth = GetRandomInt(ShapeMinSize, ShapeMaxSize)
    shpHeight = shpWidth
    shpLeft = GetRandomInt(-shpWidth, CInt(sldWidth))
    shpTop = GetRandomInt(-shpWidth, CInt(sldHeight))
    With ActivePresentation.Slides(ActiveWindow.View.Slide.SlideIndex).Shapes
      Set oShp = .AddShape(ShapeIDArray(GetRandomInt(1, 10)), _
        shpLeft, shpTop, shpWidth, shpHeight)
      ' Choose a random colour from the theme accent colours 1 to 6 (which are enumerations 5 to 10)
      With oShp
        .Fill.ForeColor.ObjectThemeColor = GetRandomInt(5, 10)
        .Fill.Transparency = 0.7
        .Line.Visible = msoTrue
        .Line.ForeColor.RGB = RGB(255, 255, 255)
      End With
    End With
  Next
  
End Sub

Function GetRandomInt(Lower As Integer, Upper As Integer) As Integer
  Dim number As Single
  
  ' Initialize the random-number generator with a seed based on the system timer
  Randomize
  
  Do
    ' Get a random number between 0 and < 1
    number = Rnd()
    ' Scale it up to the upper limit
    number = number * Upper
  Loop While number < Lower ' Repeat until the number is above the lower limit
  
  ' Set the value returned by the function
  GetRandomInt = number
End Function

When we run the AddRandomShapes procudure (or macro in this case), we are asked how many shapes we want to add (with a default set to 100) and then they are added to the current slide.

File Format

In closing, you will want to save your completed project. To do this, you need to save it in one of the macro-enabled formats, the most common being .pptm but you can also save as macro-enabled templates and slide shows.

Download

The complete project may be downloaded in the macro-enabled PowerPoint pptm format but because Experts Exchange does not yet support the PPTM format, you will need to change the extension to .pptm before opening the file:

Random-Shapes-VBA-Macro-by-YOUpresent.pp

1
6,232 Views
Jamie Garroch (MVP)PowerPoint Technical Consultant
CERTIFIED EXPERT
Eating, sleeping, breathing PowerPoint and VBA at BrightCarbon

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.