Managing presentations and slides
When you open PowerPoint through Automation, it doesn t automatically pop open and ask the user whether he wants to open an existing presentation or create a new presentation. That s your job. PowerPoint comes up and sits there with a nice, gray screen (that is, if you ve set the Visible property to true), until you tell it what to do. First, you create a Presentation object (using the Add method of the Presentations collection), and then you add Slide objects (using the Add method of the Slides collection).
Presenting: the Presentation object
The Presentations collection is an array of Presentation objects. Think of a Presentation object as a reference to a single presentation file (PPT).
When you instantiate the PowerPoint Application object with CreateObject(), it opens without any active presentations. Most often, you want to add a blank presentation. Use the Add method of the Presentations collection:
oPresentation = oPowerPoint.Presentations.Add()
oPresentation is now a reference to a Presentation object. Add takes an optional parameter that determines whether the window containing the new presentation is visible. The default is .T., so the window defaults to visible, as long as the Application object is visible. There are several ways of accessing the new Presentation object. First is the variable name that you set when you added the presentation oPresentation. The Application object has an ActivePresentation property; use oPowerPoint.ActivePresentation to return a reference to the active presentation. Beware: if you try to access the ActivePresentation property when no presentations are open or if the Application is not visible, an error occurs. Check the value of oPowerPoint.Presentations.Count and oPowerPoint.Visible to ensure that it is greater than zero before accessing ActivePresentation.
Like other collections, Presentations offers two ways of accessing its contents. The first uses an index number corresponding to the order in which the presentations were opened in this case, oPowerPoint.Presentations[1]. The second uses the name of the presentation (found in the Name property). For example, a presentation saved as "MyPresentation.PPT" can be referenced as oPowerPoint.Presentations("MyPresentation.PPT"). The path is not included, and presentation names are not case-sensitive.
Note that the Name property for presentations is read-only. When a presentation is added, the Name is "PresentationX," where "X" is a numeral corresponding to the number of files created during this session but not yet saved. Once the file is saved, the Name property reflects the filename and extension (but not the path) of the file saved on the disk. (The FullName property provides the name plus path of the stored file, and the Path property holds just the path.)
Opening an existing presentation
To open an existing presentation, use the Open method. The syntax of the Open method is as follows:
oPowerPoint.Presentations.Open( cFileName, [lReadOnly], [lUntitled],
[lWithWindow] )
cFileName | Character | The filename of the presentation. Be sure to include the full path. |
lReadOnly | Logical | .T. to open read-only. Default is Read/Write (.F.). (Optional) |
lUntitled | Logical | .T. to open without a title. Default is .F., and the title defaults to the filename. (Optional) |
lWithWindow | Logical | .T. opens a visible window, which is the default. .F. hides the opened presentation. (Optional) |
So if you issue the command:
oWayCool = oPowerPoint.Presentations.Open("c:\My Documents\WayCool.PPT")
you open the WayCool.PPT presentation in a new window. The window title defaults to "WayCool.PPT," and you can reference this presentation object as oPowerPoint.Presentations( "WayCool.PPT" ) or oPowerPoint.ActivePresentation or oWayCool.
As noted in Chapter 3, "Visual FoxPro as an Automation Client," an alternative method to open a presentation is with the GetObject() function. The following is the syntax:
oPresentation = GetObject("c:\My Documents\WayCool.PPT")
Used with only a filename as a parameter, GetObject() returns a reference to the Presentation object (not the Application object, as CreateObject() does). If PowerPoint was not running (or was running but not visible), you need to make the application visible to see it:
oPresentation.Application.Visible = .T.
The Presentation is open and available for editing. However, it does not yet have a window, and is therefore not displayed. The document opened by GetObject() respects the setting of the Application s Visible property at the time the Document object is instantiated. If the Application was not Visible (which would be the case if you use the GetObject() syntax to open a document without PowerPoint being active), you must make the document visible by giving it a window. Incidentally, this same behavior occurs when you use the Open method with the lWithWindow parameter set to False. You must use the NewWindow method to put the presentation in a window:
oPresentation.NewWindow()
Opening Presentations without making them visible can be used to your advantage. If you build the presentation when it is not visible, you see performance gains of about 30 percent. To close an open window without closing the Presentation, issue the following code:
oPowerPoint.ActiveWindow.Close()
You still have access to the Presentation, but it is not displayed in a window, so your Presentation builds significantly faster. The GetObject() function has an alternate syntax that allows you to prevent multiple occurrences of an object. If you are programming Office 97, this may be an important issue. You may want to use an open instance of PowerPoint to avoid using more memory for another instance. One of the changes in Office 2000 is that there is only one instance of the application; the Office application itself provides better memory management. However, the GetObject() syntax still works for PowerPoint 2000 (and opens the application if it is not already open). Issuing:
oPowerPoint = GetObject(,'PowerPoint.Application')
opens PowerPoint and returns a reference to the Application. Note that the syntax to open a filename returns a reference to the Presentation.
For the rest of this section, we ll assume that there is a reference to an open presentation, and that the reference is called oPresentation.
Adding slides
A PowerPoint presentation is comprised of slides. Individual slides are Slide objects belonging to a Slides collection (just like Presentation objects belonging to a Presentations collection). Add a Slide object to the presentation with the Add method:
oSlide = oPresentation.Slides.Add(nIndex, nLayout)
nIndex | Numeric | The index number of the slide. |
nLayout | Numeric | One of the ppSlideLayout constants to choose one of the 29 predefined slide layout options. |
Learning what options are available for the nLayout parameter is easy when you understand that the Layouts correspond to the dialog box that appears when a slide is added manually in PowerPoint, as shown in Figure 2. As you click on the slide layout thumbnails, the name in the lower right corner changes, and it loosely corresponds to the constant name.
Figure 2
. The New Slide dialog box in PowerPoint. This dialog gives a visual reference to the predefined slide layouts.The constants for some of the most common styles are ppLayoutTitle (1), ppLayoutText (2), ppLayoutTable (4), and ppLayoutBlank (12).
The slide index represents that slide s position in the slide show. An index of 1 inserts the new slide at the beginning of the presentation. An index of 5 inserts the new slide after slide 4 and increments the indices of the following slides. Providing an index greater than one more than the total number of slides generates an error. Use oPresentation.Slides.Count to ensure that the value you pass isn t too big.
#DEFINE ppLayoutTitle 1
* Add a title slide to the beginning of the presentation.
oSlide = oPresentation.Slides.Add(1, ppLayoutTitle)
* Add a "blank" slide to the end of the presentation.
oSlide = oPresentation.Slides.Add(oPresentation.Slides.Count + 1,;
ppLayoutTitle
)Like the Presentation object, there are several ways to access a slide. You can use the variable (oSlide, in the preceding example). You can also use the Slides property, passing either the index or the slide name, as in oPresentation.Slides[1] or oPresentation.Slides["Slide1"]. Note that there is no ActiveSlide property. You can access the active slide object with oPowerPoint.Windows[1].View.Slide, but only if the Application object is visible. There doesn t seem to be a way to determine the active slide if the Application object is invisible.
When you add a slide, its Name property defaults to the word "Slide" followed by an integer, which is the next available slide number in the slide show. If you are writing an application that goes back and edits the slides, it s prudent to set the Name property to something that is easier to remember.
There is also a SlideRange collection object, which represents a range of slides. According to the Help file, you can use the Slide collection s Range method to select a series of slides. Help says the Range method can accept an index number, a slide name, or a series of indices and slide names in a VBA array. However, arrays from FoxPro are incompatible with VBA arrays, so they will not work. You can pass a single index or a single character string representing the slide name to Range, and work on one slide. However, the syntax:
oPresentation.Slides["Slide3"]
is easier to read (and executes a little faster) than:
oPresentation.Slides.Range("Slide3")
So why did we bring it up? Because the macro recorder generates lots of statements using the Range method. There is a similar Range method for Shapes and Notes, too, and it is frequently used by the macro recorder. So if you generate code from the macro recorder, be sure to remove any references to multiple slides, and you can also remove the Range method keyword, too.
Saving the presentation
Looking quickly through the Presentation object methods, we come to Save. Instinct tells us to use just oPresentation.Save, which works, but not like you think. Remember that the Presentation s Name defaults to "PresentationX." PowerPoint saves the file in the directory from which PowerPoint was started, as "PresentationX.PPT." Perhaps not quite what you or your users wanted! The Save method does not accept parameters.
The not-so-intuitive solution is to use the SaveAs method. Fortunately, this tidbit of information is documented for the Save method, so when you forget it, you can find it in the Help file. The syntax of the SaveAs method is:
oPresentation.SaveAs(cFileName, [nFileFormat], [lEmbedFonts])
cFileName | Character | The fully qualified filename for the presentation. |
nFileFormat | Numeric | Use one of the ppSaveAs constants to choose one of the supported formats. If not included, the presentation is saved in the format of the current presentation. (Optional) |
lEmbedFonts | Logical | Use .T. if you want to embed the font information in the file. The default is .F. (Optional) |
Remember to use the fully qualified filename. Just because FoxPro s default directories are set the way you want them and you re issuing commands from VFP doesn t mean that PowerPoint knows about those defaults.
Be aware that PowerPoint does not know anything about FoxPro s SET SAFETY setting. Issuing this command will overwrite an existing file without any notice.
There are ppSaveAs constants for every supported format that appears in the interactive Save As dialog box. Office 2000 supports 18 formats, including graphical formats (BMP, GIF, and JPG), previous versions of PowerPoint, data exchange formats (RTF, MetaFile), HTML, and others (Office 97 supports seven formats, which are mostly previous versions or RTF). Commonly used constants and their values are ppSaveAsPresentation (1), ppSaveAsHTML (12) (not available in Office 97), ppSaveAsShow (7), and ppSaveAsTemplate (5). So how do you know when to use SaveAs instead of Save? When you open a new document, its name is "PresentationX." Check the Name property to see if it has the name you want to use, or if it resembles the default. You may want to compare the Name property to your filename (without path) instead of the example shown:
#DEFINE ppSaveAsPresentation 1
IF LEFT(oPresentation.Name, 12) == "Presentation"
oPresentation.SaveAs("C:\MyDocs\MyPresentation.PPT", ppSaveAsPresentation)
ELSE
oPresentation.Save()
ENDIF
Closing presentations
You can close a presentation at any time, whether it s saved or not, by using the Close method. The Close method takes no parameters.
oPresentation.Close()
There is no warning if you close an unsaved presentation. To check whether it s saved before you close it, examine the Saved property, which contains 0 if the presentation has changed since it was created or last saved, and 1 if it s unchanged.
#DEFINE ppSaveAsPresentation 1
* Check to see if the presentation is saved before closing it
IF oPresentation.Saved = 0
* Better save this presentation. Be sure it's saved with the proper name
IF LEFT(oPresentation.Name, 12) == "Presentation"
oPresentation.SaveAs("C:\MyDocs\MyPresentation.PPT", ppSaveAsPresentation)
ELSE
oPresentation.Save()
ENDIF
ENDIF
oPresentation.Close()
Closing the application object
To shut down PowerPoint, call the Application object s Quit method:
oPowerPoint.Quit()
This severs the connection with the PowerPoint Application object. All presentations are closed (without saving) unless there are any variables pointing to object references in PowerPoint. If there is such a reference, none of the open presentations are closed, and the object references that exist are valid. When you close the last presentation (or release all object references), all remaining presentations are then closed.
This is one instance where PowerPoint 2000 has changed the object model slightly. In PowerPoint 2000, there can be one and only one instance of a PowerPoint Application object; CreateObject() references an already running instance of PowerPoint, and creates another reference to it. In PowerPoint 97, each call to CreateObject() creates a new instance of an Application. An additional difference is that PowerPoint 97 closes without caring whether there are any open variables pointing to an instance of PowerPoint.
To examine PowerPoint 2000 s Quit behavior, run the code shown in Listing 1. It is saved as PPTQuit.PRG in the Developer Download files available at
www.hentzenwerke.com.Listing 1
. The quirks of quitting PowerPoint 2000. As in Visual FoxPro, be sure to release all your object references to successfully close the server application.* Create the Application instance
oPowerPoint = CreateObject("PowerPoint.Application")
oPowerPoint.Visible = .T.
WITH oPowerPoint
* Create the first presentation
oPresentation1 = .Presentations.Add()
* Create the second presentation
oPresentation2 = .Presentations.Add()
ENDWITH
= MESSAGEBOX("Alt-Tab to PowerPoint, and manually open a new presentation.")
* You might put in a SUSPEND here, to allow you to Alt-Tab
* to PowerPoint. Manually open a new presentation to see
* what happens to it if you don't have an object reference.
= MESSAGEBOX("Press OK to close Presentation2")
oPresentation2.Close()
= MESSAGEBOX("Press OK to close the Application Object." + CHR(13) + ;
"Notice nothing happens.")
oPowerPoint.Quit()
= MESSAGEBOX("Press OK to close Presentation1")
oPresentation1.Close()
= MESSAGEBOX("The Application, and any presentations you manually " + ;
"opened are still there! Press OK to release oPowerPoint.")
RELEASE oPowerPoint && Office 97 successfully terminates here.
= MESSAGEBOX("It's still there! Now press OK to release oPresentation1.")
RELEASE oPresentation1
= MESSAGEBOX("It's still there! Now press OK to release oPresentation2.")
RELEASE oPresentation2
= MESSAGEBOX("It's gone--and so are the presentations you manually " + ;
"opened." + CHR(13) + ;
"Remember to release ALL your variables!")
Just as with FoxPro forms, you need to release all the references to objects before you can destroy the instance of the main object (in PowerPoint 2000 only).
Making it look good for the users
Before moving on to adding content to the slides, let s explore some of the properties and methods that allow us to make the process of building the presentation more attractive to the user. We ve already discussed Visible, Left, Top, Width, and Right. These control whether the user sees PowerPoint, and where the PowerPoint window appears on the screen. If the position and size of the window are not set in code, the PowerPoint window displays where and how the user last had it it could be maximized, minimized, or normal anywhere on the screen.
During development, we like to have FoxPro in a normal window the full height of the screen and taking up about two-thirds of its width on one side, then forcing PowerPoint to come up two-thirds of the width on the opposite side. This way, the results of code that runs are easy to see. Users also like this arrangement for the first little while it s quite cool to watch. They soon tire of it, though, just about the time they complain about performance (a sure sign that the novelty has worn off). Then you can add the feature to give the user the option of not seeing the final presentation until the end. It also runs approximately 30 percent faster (depending on hardware configuration and the types of slides that are built), which makes you look like a hero for being so responsive to their needs.
While PowerPoint is visible, there are reasons to bring PowerPoint in front of your application, especially if the users are attempting to watch it while it builds. This is accomplished through the Presentation s Activate method:
oPowerPoint.Activate()
This method brings the current presentation window to the top of all running Windows applications. In this situation, you ll also want to display slides as you work on them. Use Slide s Select method to bring a slide to the front:
oPresentation.Slides[1].Select()
A note to PowerPoint 97 users: the preceding line will cause an error. Use the following line, instead:
oPresentation.ActiveWindow.View.GoToSlide(2)
Just when do you show that slide? Do you issue the Select method just after you add it? If users are watching, it gives a very nice demonstration of exactly what s going on. The users can really relate to the "hard work" the computer is doing. However, after watching it a few times, users can get a little bored and wish it would run faster. To gain some performance (generally about a 15 20 percent increase), wait until the slide is completely drawn, then issue the Select method. Adding and formatting shapes on a hidden slide avoids time-consuming redraws, and your slides appear to pop up on the screen. If your users really complain, don t make the Application object visible until the end, and use a progress bar to indicate relative time remaining, instead.
Copyright 2000 by Tamar E. Granor and Della Martin All Rights Reserved