I'm adding some shapes to the slide and group them together with the code provided.
' Inserting shapes like this
Set sld = Application.ActiveWindow.View.Slide
Set sDesc = sld.Shapes.AddTextbox(msoTextOrientationHorizontal, startX, picStartY, boxWidth, 20)
[...]
' Group shapes together
sld.Shapes.Range(Array(sBox.Name, sLogo.Name, sDesc.Name)).Group
But if there is a placeholder for shapes (see picture, not sure what the correct term is) on the slide I get an error saying that it can't be grouped. It seems like the shapes replace this placeholder and the error appears.
Any suggestions?
Run-time error '-2147024891 (80070005)':
Grouping is disabled for the selected shapes
It's exactly as the error message states (which may well be a first for VBA error messages!). You cannot group placeholders with other shapes.
I battled with this - I was generating shapes and needed to group the ones I had generated.
Using shape names is really the only viable approach I could find.
ZOrderPosition looked good (and is the index number) but the number of shapes returned from ThisSlide.Shapes is not a full indexed collection of all the shapes (I think because the Shapes collection returned treats a shape with type group as a single shape and does not include its underlying shapes). E.g. the ZOrderPosition I got for a generated shape was 103 but the ThisSlide.Shapes collection only returned 57 shapes so indexing that for 103 threw an out of bounds exception.
I initially solved the problem by adding a generated shape number to the shape name which worked as long as I didn't run the routine twice (it was a VSTO add in) which ended up generating duplicate shape names.
The solution I found was to make every name unique by adding the shapes' .Top property as an integer to the shape name - e.g.
GeneratedShape.name = "added_" & cint(GeneratedShape.top) & AddedShapeNo
Related
I wrote some macro code in Word (Office 365) to set the color of a shape outline to one of the theme colors. The code for doing that to a shape looks like this:
shape.line.foreColor.ObjectThemeColor = wdThemeColorAccent2
By assigning a 'wdXX' color to the ObjectThemeColor field, the color of the line around the shape will automatically change when the document ColorTheme is changed.
My problem (or the first weirdness) is that when I assign Accent2 with the code above and then do: select the shape, Menu, Format, Shape Outline, and hover over the color box with a red outline (which marks the active line color), the tooltip says "Turquoise, Accent 1" not "Accent 2."
I would have expected the wdThemeColorAccent2 color to be called Accent 2 in the tooltip, but it is not.
The second problem is that there is apparently no way for me to assign the last color shown in the menu using macro code. Because of the offset (Accent 2 in code = Accent 1 in the menu), I would need to use wdThemeColorAccent7 in code to assign the last color shown in the menu (labeled Accent 6 in the tooltip).
I'm wondering if this is a bug in Word (it sure looks like it to me), or if I am doing something wrong. To reproduce the situation, I created a simple empty rectangle, selected it, and ran the line of code above to change the outline color of the shape. Here's a little subroutine that illustrates the problem (select your shape before running the subroutine).
Sub TestAccent()
Dim shp As Shape
Set shp = selection.ShapeRange(1)
shp.line.foreColor.ObjectThemeColor = wdThemeColorAccent4
shp.line.Weight = 0.5
shp.line.Visible = True
End Sub
I believe the colors in the "theme scale" (see image below) don't correspond to the names of the WdThemeColorIndex, but rather to the underlying numerical value. If you look in the VBA Editor's Object Browser (F2), and search wdThemeColorAccent you'll get the full list. Click on a member in the list and at the bottom you'll see the numerical value.
The value 0 is assigned to MainDark1 and isn't recognized by VBA. Values 1, 2 and 3 are assigned to MainLight1, MainDark2 and MainLight2 which are black, white and the first entry in the image (These colors repeat in the last four enumerations for background and text). Values 4 (wdThemeColorAccent4) through 9 (wdThemeColorAccent6) correspond to the remainder of the colors in the image below. (Note: more discussion after image!)
So, no, I don't think it's a bug, just your expectations don't match what the developers were thinking when they assigned the numerical enumeration to the enumeration names. Or maybe the people who designed the color schemes changed their minds after the VBA code was locked down... And I imagine the names you see in the tooltips are another step removed from the VBA. You might find the information in this article helpful.
If you use the values, rather than the names, things could be less confusing. Or, define your own Enum:
Public Enum ColorSchemeAccents
Accent1 = 3
Accent2 = 4
Accent3 = 5
Accent4 = 6
Accent5 = 7
Accent6 = 8
Accent7 = 9
Accent8 = 10
End Enum
Sub TestAccent()
Dim shp As Shape
Set shp = Selection.ShapeRange(1)
shp.Line.ForeColor.ObjectThemeColor = ColorSchemeAccents.Accent8
shp.Fill.ForeColor = RGB(250, 250, 250)
shp.Line.Weight = 2
shp.Line.Visible = True
End Sub
Although the ColorFormat object's .ObjectThemeColor is defined as a wdThemeColorIndex in fact the value depends on context.
If it is a Word object - such as text, then you should use the wdThemeColorIndex constants, but if it is an Office object - such as shape, then you have to use the msoThemeColorIndex constants. These are weirdly NOT the same - mostly the mso constants are one more than the wd constants, but not for the Background1&2 and Text1&2 cases - Text1&2 are the same in both cases, but for Background1&2 mso is two more than wd.
A side effect of this is that it appears impossible in VBA to set the Background2 colour, as its mso value is 16 and so out-of-range BUT if you use the native GUI to set it, it can be set to 16!
Looks really poor design/implementation that needs cleaning up!
I am looking to write a generalized PowerPoint macro to group specific shapes together. The problem is I do not know the specific shape names ahead of time as my slidedeck changes slighty each time. Here is my situation: I have a collection of PowerPoint shapes whose names start with the prefix "rc". For example they could be "rc48", "rc49","rc50","rc51". They are always in increasing numerical order and the only "rc" named shapes on the slide. Following these shapes, I have a collection of shapes with the prefix "tx" (they are not the only "tx" shapes in the slide but they do always follow the "rc" shapes) and there are always an equivilant number of "tx" objects following the "rc" objects. So in this example I would have "tx52", "tx53","tx54","tx55".
What I would like to do is group these pairs of objects together. So group1 would be ("rc48","tx52"). group2 would be ("rc49","tx53") and so on.
I know very little about coding in VBA, but my approach in other programming languages would be to find the positions of the "rc" shapes in the sequential shape names vector and then count length(rcshapes_vector) past the "rc" positions to find the "tx" shapes I need and then loop over these pairs.
I realize this is a complicated question, but any help would be greatly appreciated.
Working with vba code in PowerPoint is really painful because you don't have a lot of functions such as Excel vba but I hope the following ideas can help you:
You can validate the type of Shape like If oShp.Type = msoTextBox Then or If oShp.Type = msoPicture Then.
Also for each Shape you can validate the top or left property to find the position in the slide.
If you are sure your shapes have those names, maybe you can try with:
Dim oShp As Shape
For Each oShp In ActivePresentation.Slides(SldNumber).Shapes
If oShp.Name = "rc49" Then
Do Something
End If
next
I need to know is selected shape word art or not.
Shape has property "Type" (returns enum MsoShapeType).
When I insert word art and check this property - it returns msoAutoShape instead of msoTextEffect (with AutoShapeType==msoShapeRectangle).
How can I check that spae is word art (not usual rectangle with textbox) ?
Thanks!
If you select either the overall smartart shape or click into text within the smartart shape or select one of the shapes within the smart art, ActiveWindow.Selection.ShapeRange(1) will return the smartart shape.
So
If ActiveWindow.Selection.ShapeRange(1).HasSmartArt Then
Debug.Print "It's smart art"
End if
[edited]
But as you've pointed out, this is for smartart, not word art. My error, sorry.
There isn't a WordArt shape as such; it's more like any shape that has had WordArt formatting applied to the shape as a whole or to text within the shape. That'd include formatting like glow, reflection, shadow and so on, or could be one of the WordArt presets, pre-selected combinations of these different effects. I've added an example that'll help identify shapes or ranges of text within shape that have these presets applied. I don't see any simple way of checking for user-applied WordArt formats other than looking at each run and each text box for each of the various properties (glow, reflection etc) that might be applied. Unfortunately, there's no WordArtFormat = None to tell us we can ignore it. It's either going to be one of the presets or -2, which can mean any of several things.
Sub WordArtist()
Dim oSh As Shape
Dim oRng As TextRange2
' Has word art formatting been applied to
' entire shape?
Set oSh = ActiveWindow.Selection.ShapeRange(1)
Debug.Print oSh.TextFrame2.WordArtFormat
' Has it been applied to individual chunks of
' text within the shape
For Each oRng In oSh.TextFrame2.TextRange.Runs
Debug.Print oRng.Font.WordArtFormat
Next
' Note:
' A result of -2 for the entire shape could mean
' - No text in the shape; not really word art
' - Mixed formatting
' - Text/shape has had glow/shadow/reflection etc applied
' rather than one of the preset WordArt selections
End Sub
I have a Visio drawing and I want to be able to Select shapes from it and paste them to other sheets depending on certain variables.
What is the code for selecting the different shapes on the page. I am trying this but it is not working.
Dim vsoSelection As Visio.Selection
vsoSelection.Select Visio.Shape(1), visSelect
What am I missing here?
and also is it possible to get the strings entered into text boxes into Visio?
I am assuming you're getting an error because your vsoSelection object is nothing. So you need to do:
Set vsoSelection = ActiveWindow.Selection
I have a report that is generated in PowerPoint, and underneath many of the graphs, there is text that tells the reader to refer to pages in the appendix. I would like to be able to dynamically reference these slides.
For example, under a graph I might have the text "Please see appendix page 54", but I need the 54 to be linked to a slide so that if I insert another slide it will say 55.
Is this possible to do in VBA? I do not expect somebody to write my code for me, I would just like to know if this is a reasonable thing to do before I spend hours attempting to do it.
Side note: I feel horrible asking a question about MS Office on here, but since I believe it would need to be implemented in VBA (I don't think this functionality is built in by default) I think that it is a relevant question.
No need to feel horrible asking this here.
How one might do this:
In PPT, shapes, slides and even the presentation itself can have an associated tag collection; named string values. For example, assuming a reference to the shape in oSh, you can do:
oSh.Tags.Add "AssociatedSlideId", "293"
In this case, you'd apply this tag to your graph; the 293 would be the SlideID of the slide you want to reference. Each slide has a unique SlideID assigned when it's created; the SlideID won't change when you move the slide around/add/delete slides.
To read the tag from the shape:
Debug.Print oSh.Tags("AssociatedSlideId")
In this case, that'd return "293". Feed that to FindBySlideID to get the SlideIndex of the slide (ie, the ordinal position of the slide in the presentation). Or ask it for SlideNumber if you want the number of the slide that'll appear in number placeholders (usually, but not always the same as slide index).
Debug.Print ActivePresentation.Slides.FindBySlideID(clng("293")).SlideIndex
You might also tag the textbox or other shape that you want to use to hold the reference, then write a function along the lines of:
Function ShapeTaggedWith(oSl as Slide, sTagName as String, sTagValue as String) as Shape
This would iterate through the shapes on slide oSl looking for one with a tag named sTagName, value = sTagValue and return it to the caller if found.
Now you can find the shape that's nominated as your caption for the graph, let's call it, and change its text to match the SlideIndex (or SlideNumber) of the slide the chart's supposed to reference.
Hope that's all moderately clear; if not, that's why the StackOverflow gods gave us comments.