Coordinates of a textframe in PowerPoint via VBA - vba

I want to take all the articles in Word document and transform them into PowerPoint Presentation.
1 article = 1 slide (if the text does not fit shrink it, else create a new slide).
I managed to recognize each part of the article by its Style in Word. I get text by its style and insert it into a slide and so forth. I retrieve text by paragraphs (Selection.StartOf and EndOf didn't work).
I didn't find a way to avoid overlaying one text over the other.
Maybe I can get what I need by the coordinates of the textframes?
What I have got so far:
For Each StyleInWord In ActiveDocument.Paragraphs
If StyleInWord.Style = "NAME_OF_THE_ARTICLE" Then
wordText0 = StyleInWord.Range
Set pptLayout = pptPres.SlideMaster.CustomLayouts.Add(ppLayoutBlank)
Set pptSlide = pptPres.Slides.AddSlide(1, pptLayout)
If pptPres.Slides(1).Shapes(1).HasTextFrame Then
pptPres.Slides(1).Shapes(1).Delete
End If
With pptPres.PageSetup
.SlideSize = ppSlideSizeCustom
.SlideHeight = CentimetersToPoints(21.008)
.SlideWidth = CentimetersToPoints(28.011)
End With
Set mySlide = pptPres.Slides(1).Shapes.AddTextbox(msoTextOrientationHorizontal, CentimetersToPoints(1.31), CentimetersToPoints(3.73), CentimetersToPoints(24.34), CentimetersToPoints(12.57))
With mySlide.TextFrame.TextRange
.Text = wordText0
With .Font
.Size = 11 ' points
.Name = "Arial"
.Bold = msoTrue
End With
End With
End If
If StyleInWord.Style = "DESCRIPTION_OF_THE_ARTICLE" Then
wordText1 = StyleInWord.Range
Set mySlide = pptPres.Slides(1).Shapes.AddTextbox(msoTextOrientationHorizontal, CentimetersToPoints(1.31), CentimetersToPoints(5.73), CentimetersToPoints(24.34), CentimetersToPoints(12.57))
With mySlide.TextFrame
With .TextRange
.Text = wordText1
With .Font
.Size = 11 ' points
.Name = "Arial"
.Bold = msoTrue
End With
End With
End With
End If
If StyleInWord.Style = "MAIN_TEXT_OF_THE_ARTICLE" Then
Set mySlide = pptPres.Slides(1).Shapes.AddTextbox(msoTextOrientationHorizontal, CentimetersToPoints(1.31), CentimetersToPoints(7.73), CentimetersToPoints(24.34), CentimetersToPoints(12.57))
wordText2 = StyleInWord.Range
With mySlide.TextFrame
With .TextRange
.Text = wordText2
With .Font
.Size = 11 ' points
.Name = "Arial"
.Bold = msoTrue
End With
End With
End With
End If
Next StyleInWord
'Here i change the order, so the first slide i create will stay the first by the end of the forEachLoop
i = 1
For i = 1 To pptPres.Slides.Count
pptPres.Slides(i).MoveTo 1
Next i

Each time you add a textbox you set the top position to simply be 2cm lower than the previous one. This takes no account of the height of the previous text box.
There is a very simple solution to this. A text box has properties for both top and height, so just store those in variables. That way you can add each new text box directly below the previous one.
Your code also needs some improvement as some of the presentation setup you are doing should be outside the loop. You should also rename mySlide as pptTextBox so that the variable has a logical name that is consistent with the others.
Set pptLayout = pptPres.SlideMaster.CustomLayouts.Add(ppLayoutBlank) doesn't do what you think it does and is unnecessary. The presentation will already contain a blank layout, helpfully named "Blank", so all you need to do is set a pointer to it, again outside the loop.
'do presentation setup outside the loop
With pptPres.PageSetup
.SlideSize = ppSlideSizeCustom
.SlideHeight = CentimetersToPoints(21.008)
.SlideWidth = CentimetersToPoints(28.011)
End With
'a presentation will already include a blank layout so there is no need to create one
For Each pptLayout In pptPres.SlideMaster.CustomLayouts
If pptLayout.Name = "Blank" Then Exit For
'pptLayout now points to the Blank layout
Next
For Each StyleInWord In ActiveDocument.Paragraphs
If StyleInWord.Style = "NAME_OF_THE_ARTICLE" Then
wordText0 = StyleInWord.Range
Set pptSlide = pptPres.Slides.AddSlide(1, pptLayout)
If pptPres.Slides(1).Shapes(1).HasTextFrame Then
pptPres.Slides(1).Shapes(1).Delete
End If
Set pptTextBox = _
pptPres.Slides(1).Shapes.AddTextbox(msoTextOrientationHorizontal, _
CentimetersToPoints(1.31), CentimetersToPoints(3.73), _
CentimetersToPoints(24.34), CentimetersToPoints(12.57))
With pptTextBox
With .TextFrame.TextRange
.Text = wordText0
With .Font
.Size = 11 ' points
.Name = "Arial"
.Bold = msoTrue
End With
End With
textBoxTop = .Top
textBoxHeight = .Height
End With
End If
If StyleInWord.Style = "DESCRIPTION_OF_THE_ARTICLE" Then
wordText1 = StyleInWord.Range
Set pptTextBox = _
pptPres.Slides(1).Shapes.AddTextbox(msoTextOrientationHorizontal, _
CentimetersToPoints(1.31), textBoxTop + textBoxHeight, _
CentimetersToPoints(24.34), CentimetersToPoints(12.57))
With pptTextBox
With .TextFrame.TextRange
.Text = wordText1
With .Font
.Size = 11 ' points
.Name = "Arial"
.Bold = msoTrue
End With
End With
textBoxHeight = textBoxHeight + .Height
End With
End If
If StyleInWord.Style = "MAIN_TEXT_OF_THE_ARTICLE" Then
Set pptTextBox = _
pptPres.Slides(1).Shapes.AddTextbox(msoTextOrientationHorizontal, _
CentimetersToPoints(1.31), textBoxTop + textBoxHeight, _
CentimetersToPoints(24.34), CentimetersToPoints(12.57))
wordText2 = StyleInWord.Range
With pptTextBox
With .TextFrame.TextRange
.Text = wordText2
With .Font
.Size = 11 ' points
.Name = "Arial"
.Bold = msoTrue
End With
End With
textBoxHeight = textBoxHeight + .Height
End With
End If
Next StyleInWord
'Here i change the order, so the first slide i create will stay the first by the end of the forEachLoop
i = 1
For i = 1 To pptPres.Slides.Count
pptPres.Slides(i).MoveTo 1
Next i

Related

Powerpoint VBA - How to add text box to multiple slides

So I'm using the following code to add a text box to the header of several slides:
Set myDocument = ActivePresentation.Slides.Range(Array(4, 5, 6))
Set newTextBox = myDocument.Shapes.AddTextbox(msoTextOrientationHorizontal, _
260, Top:=30, Width:=541.44, Height:=43.218)
With newTextBox.TextFrame.TextRange
.Text = "Test Text"
.Font.Size = 17
.Font.Name = "Arial"
End With
When I run this code I get an automation error and it doesn't work. If I do it on a single slide it does work. Does anyone know why? What I'm attempting to do is add headers to specific slides. So I will be using the same method to add different headers to other slides as well.
You can go through all the slides with numbers from the array you set:
Sub slideTextBoxes()
For Each myDocument In ActivePresentation.Slides.Range(Array(4, 5, 6))
Set newTextBox = myDocument.Shapes.AddTextbox(msoTextOrientationHorizontal, _
260, Top:=30, Width:=541.44, Height:=43.218)
With newTextBox.TextFrame.TextRange
.Text = "Test Text"
.Font.Size = 17
.Font.Name = "Arial"
End With
Next
End Sub
Slides don't have headers. But here is code that will work:
Sub AddTextBoxes()
Dim oSlide As Slide
Dim oShape As Shape
For Each oSlide In ActivePresentation.Slides
If oSlide.SlideIndex = 4 Or oSlide.SlideIndex = 5 Or oSlide.SlideIndex = 6 Then
Set oShape = oSlide.Shapes.AddTextbox(msoTextOrientationHorizontal, Left:=260, Top:=30, Width:=541.44, Height:=43.218)
With oShape.TextFrame.TextRange
.Text = "Test Text"
.Font.Size = 17
.Font.Name = "Arial"
End With
End If
Next oSlide
End Sub

vba powerpoint for mac creating unwanted blank line

I am trying to use a PowerPoint macro written for Windwos on a Mac (Microsoft 365 for Mac). Most of it is working well, but there are two strange things. The major issue: The Mac creates unwanted blank lines.
TextFrame2.TextRange.Text = "Text 1" & vbCrLf & "Text 2" & vbCrLf & "Text 3"
& vbCrLf & creates just a break on Windows PPT, but an additional blank line on the Mac. Any ideas how I can avoid that?
There is a minor issue, too:
I thought it's better to use TextFrame2 instead of TextFrame all time, but on the Mac I get a compiling error, when trying to use it with the ruler function close to the end of the code. If anyone has a solution for this, I would be happy, too.
Private Sub ParameterColumnBodyStandard()
Dim shp As Shape
Dim i As Integer
Set shp = ActiveWindow.Selection.ShapeRange(1)
With shp
.Fill.Visible = msoFalse
.Line.Visible = msoFalse
With .TextFrame2
.TextRange.Text = "Text 1" & vbCrLf & "Text 2" & vbCrLf & "Text 3"
.VerticalAnchor = msoAnchorTop
.MarginBottom = 5.6692878
.MarginLeft = 5.6692878
.MarginRight = 5.6692878
.MarginTop = 5.6692878
.WordWrap = msoTrue
With .TextRange
.Font.Size = 16
.Font.Name = "Arial"
.Font.Fill.ForeColor.RGB = RGB(0, 0, 0)
.Font.Bold = msoFalse
.Font.Italic = msoFalse
.Font.UnderlineStyle = msoNoUnderline
.ParagraphFormat.SpaceAfter = 6
.ParagraphFormat.Alignment = ppAlignLeft
.ParagraphFormat.Bullet.UseTextColor = msoFalse
.ParagraphFormat.Bullet.UseTextFont = msoFalse
.ParagraphFormat.Bullet.Font.Fill.ForeColor.RGB = RGB(0, 0, 0)
.Characters(1, 6).Font.Bold = msoFalse
For i = 2 To 3
With .Paragraphs(i).ParagraphFormat.Bullet
.Visible = msoTrue
End With
Next
With .Paragraphs(2)
.ParagraphFormat.IndentLevel = 2
.ParagraphFormat.Bullet.Character = 8226
.ParagraphFormat.Bullet.RelativeSize = 1
End With
With .Paragraphs(3)
.ParagraphFormat.IndentLevel = 3
.ParagraphFormat.Bullet.Character = 8226
.ParagraphFormat.Bullet.RelativeSize = 1
End With
End With
End With
With .TextFrame
With .Ruler
.Levels(2).FirstMargin = 14.173219
.Levels(2).LeftMargin = 28.346439
.Levels(3).FirstMargin = 28.346439
.Levels(3).LeftMargin = 42.519658
End With
End With
End With
End Sub

How to obtain which part of chart is selected?

I have some vsto add-in to PowerPoint.
I need to know which part of chart is selected by user (series, title, charta area, plot area, legend etc.). Is it possible to get such information?
I know, of course, how to get selected chart.
My add-in is written in VBA, but I think the below will help you. The PPT object model doesn't support this, so my hacky solution was to apply Strikethrough font as an ExecuteMSO command (i.e., Strikethrough is applied to whatever is selected), then I go through every element of the chart and look for Strikethrough. When we find it, we can tell what the user had selected, apply whatever rules we want, and remove the Strikethrough.
In my case, I wanted to rewrite the Bold command so that we could apply a different font weight to the user's selection, rather than using the native faux-bolding. Here is part of my solution:
First, this is the sub that's called when the selection contains shapes. Note how we handle the chart scenario:
Private Sub commandBoldSelectedShapes(mySelection As Selection)
Debug.Print "IN_commandBoldSelectedShapes"
Dim oShp As Shape
Dim oSmrtArt As SmartArt
Dim oTable As Table
Dim oChart As Chart
Dim oCell As Cell
Dim i As Long
Dim j As Long
Dim ctr As Long
Dim oFont As Font
For ctr = 1 To mySelection.ShapeRange.Count
Set oShp = mySelection.ShapeRange(ctr)
If oShp.Type = msoGroup Then
RefontTypoGroup oShp, mySelection
ElseIf oShp.HasSmartArt Then
Set oSmrtArt = oShp.SmartArt
DoEvents
Application.CommandBars.ExecuteMso ("Strikethrough")
DoEvents
RefontTypoSmartArt oSmrtArt
ElseIf oShp.HasTable Then
Debug.Print "Seeing a table!"
Set oTable = oShp.Table
If ctr = 1 And mySelection.ShapeRange.Count = 1 Then
With oTable
For i = 1 To oTable.Rows.Count
For j = 1 To oTable.Columns.Count
Set oCell = oTable.Rows(i).Cells(j)
If oCell.Selected Then
Set oFont = oCell.Shape.TextFrame.TextRange.Font
checkBoldsNoStrikethrough oFont
End If
Next
Next
End With
Else
For i = 1 To oTable.Rows.Count
For j = 1 To oTable.Columns.Count
Set oCell = oTable.Rows(i).Cells(j)
Set oFont = oCell.Shape.TextFrame.TextRange.Font
checkBoldsNoStrikethrough oFont
Next
Next
End If
' Charts are highly problematic because the VBA Selection object
' doesn't allow you to figure out which element(s) in a chart the user
' may have selected. You can only see that the full shape containing a chart
' has been selected. So my solution was to run an
' ExecuteMso - Strikethrough command. Then, separate macros
' go through the whole chart looking for strikethoughs and replace them
' with bolded/unbolded text and the correct font weight.
ElseIf oShp.HasChart Then
Debug.Print "Seeing a chart!"
Set oChart = oShp.Chart
If ctr = 1 And mySelection.ShapeRange.Count = 1 Then
DoEvents
Application.CommandBars.ExecuteMso ("Strikethrough")
DoEvents
RefontTypoChart oChart
Exit Sub
' If there is more than one shape selected, including a chart,
' and that chart is not the first shape selected, we know that
' the whole chart has been selected. As a result, we can simply
' apply bolding to the whole chart.
Else
With oChart.ChartArea.Format.TextFrame2.TextRange.Font
If GlobalSettings.IsBoldPressed = False Then
.Bold = False
.Name = FontsSettings.ActiveFonts.bodyFont
Else
.Bold = True
.Name = FontsSettings.ActiveFonts.headingFont
End If
End With
End If
ElseIf oShp.HasTextFrame Then
If oShp.TextFrame.HasText Then
Set oFont = oShp.TextFrame.TextRange.Font
checkBoldsNoStrikethrough oFont
End If
End If
Next
End Sub
And there is the sub that starts going through the chart elements. Most checks are outsourcing the Strikethrough hunt to yet another sub:
Sub RefontTypoChart(chrt As Chart)
On Error GoTo Errhandler
' Dim s As Series
Dim A As axis
' Dim scnt As Integer
Dim i As Integer
Dim oShp As Shape
Dim oTxtRange2 As TextRange2
Dim oTickLabels As TickLabels
Dim oLegendEntries As LegendEntries
Set oTxtRange2 = chrt.Format.TextFrame2.TextRange
If oTxtRange2.Font.Strikethrough = msoTrue Then
RefontTypoChartShapeRange oTxtRange2
Exit Sub
End If
If chrt.HasLegend Then
Set oLegendEntries = chrt.Legend.LegendEntries
For i = 1 To oLegendEntries.Count
With oLegendEntries(i).Font
If GlobalSettings.IsBoldPressed = False Then
If .Strikethrough = True Then
.Bold = False
.Name = FontsSettings.ActiveFonts.bodyFont
.Strikethrough = False
End If
Else
If .Strikethrough = True Then
.Bold = True
.Name = FontsSettings.ActiveFonts.headingFont
.Strikethrough = False
End If
End If
End With
Next
With chrt.Legend.Format.TextFrame2.TextRange.Font
If GlobalSettings.IsBoldPressed = False Then
If .Strikethrough = True Then
.Bold = False
.Name = FontsSettings.ActiveFonts.bodyFont
.Strikethrough = False
End If
Else
If .Strikethrough = True Then
.Bold = True
.Name = FontsSettings.ActiveFonts.headingFont
.Strikethrough = False
End If
End If
End With
End If
If chrt.HasTitle Then
Set oTxtRange2 = chrt.ChartTitle.Format.TextFrame2.TextRange
RefontTypoShapeRange oTxtRange2
End If
If chrt.HasAxis(xlCategory, xlPrimary) Then
Set A = chrt.Axes(xlCategory, xlPrimary)
If A.HasTitle = True Then
Set oTxtRange2 = A.AxisTitle.Format.TextFrame2.TextRange
RefontTypoShapeRange oTxtRange2
End If
Set oTickLabels = A.TickLabels
RefontTypoTickLabels oTickLabels
End If
If chrt.HasAxis(xlCategory, xlSecondary) Then
Set A = chrt.Axes(xlCategory, xlSecondary)
If A.HasTitle = True Then
Set oTxtRange2 = A.AxisTitle.Format.TextFrame2.TextRange
RefontTypoShapeRange oTxtRange2
End If
Set oTickLabels = A.TickLabels
RefontTypoTickLabels oTickLabels
End If
If chrt.HasAxis(xlValue, xlPrimary) Then
Set A = chrt.Axes(xlValue, xlPrimary)
If A.HasTitle = True Then
Set oTxtRange2 = A.AxisTitle.Format.TextFrame2.TextRange
RefontTypoShapeRange oTxtRange2
End If
Set oTickLabels = A.TickLabels
RefontTypoTickLabels oTickLabels
End If
If chrt.HasAxis(xlValue, xlSecondary) Then
Set A = chrt.Axes(xlValue, xlSecondary)
If A.HasTitle = True Then
Set oTxtRange2 = A.AxisTitle.Format.TextFrame2.TextRange
RefontTypoShapeRange oTxtRange2
End If
Set oTickLabels = A.TickLabels
RefontTypoTickLabels oTickLabels
End If
RefontTypoChartLabels chrt
If chrt.Shapes.Count > 0 Then
For Each oShp In chrt.Shapes
If oShp.HasTextFrame Then
If oShp.TextFrame.HasText Then
Set oTxtRange2 = oShp.TextFrame2.TextRange
RefontTypoShapeRange oTxtRange2
End If
End If
Next
End If
Exit Sub
Errhandler:
Debug.Print "Error: " & Err.Description
End Sub
Here is the sub that looks for most of the Strikethroughs:
Public Sub RefontTypoShapeRange(oTxtRange2 As TextRange2)
Dim i As Long
With oTxtRange2
For i = .Runs.Count To 1 Step -1
With .Runs(i).Font
If GlobalSettings.IsBoldPressed = False Then
If .Strikethrough = True Then
.Bold = False
.Name = FontsSettings.ActiveFonts.bodyFont
End If
Else
If .Strikethrough = True Then
.Bold = True
.Name = FontsSettings.ActiveFonts.headingFont
End If
End If
End With
Next
.Font.Strikethrough = False
End With
End Sub
You may notice that in the second sub posted, there are references to a few different subs that are specialized for certain chart elements. This is because TickLabels don't have a TextRange2 object and therefore need their own checker sub (one which passes along a TickLabels object). Also, there's a distinction made between chart elements that can have more than one formatting Run, and those that can't -- looking for Runs in the TextRange2 object of chart elements that don't support more than 1 run will cause a crash.
Public Sub RefontTypoChartShapeRange(oTxtRange2 As TextRange2)
Debug.Print "IN_RefontTypoChartShapeRange"
With oTxtRange2.Font
If GlobalSettings.IsBoldPressed = False Then
If .Strikethrough <> msoFalse Then
.Bold = False
.Name = FontsSettings.ActiveFonts.bodyFont
End If
Else
If .Strikethrough <> msoFalse Then
.Bold = True
.Name = FontsSettings.ActiveFonts.headingFont
End If
End If
.Strikethrough = False
End With
End Sub
Chart data labels are a small nightmare too, as they will become disconnected from the data if we don't massage the .Autotext property as seen below.
Sub RefontTypoChartLabels(oChrt As Chart)
Dim i As Integer
Dim j As Integer
Dim seriesVar As Series
Dim dataLabelsVar As DataLabels
Dim dataLabelVar As DataLabel
Dim pointVar As Point
Dim oTxtRange2 As TextRange2
Dim isAutoText As Boolean
For i = 1 To oChrt.SeriesCollection.Count
Set seriesVar = oChrt.SeriesCollection(i)
If seriesVar.HasDataLabels = True Then
Set dataLabelsVar = seriesVar.DataLabels
If dataLabelsVar.Format.TextFrame2.TextRange.Font.Strikethrough <> msoFalse Then
Set oTxtRange2 = dataLabelsVar.Format.TextFrame2.TextRange
RefontTypoChartShapeRange oTxtRange2
Else
For j = 1 To seriesVar.Points.Count
Set pointVar = seriesVar.Points(j)
If pointVar.HasDataLabel = True Then
Set dataLabelVar = seriesVar.DataLabels(j)
isAutoText = dataLabelVar.AutoText
Set oTxtRange2 = dataLabelVar.Format.TextFrame2.TextRange
RefontTypoChartShapeRange oTxtRange2
dataLabelVar.AutoText = isAutoText
End If
Next
End If
End If
Next
End Sub
Hopefully you're able to adapt some of this to your needs and avoid pulling out your hair. You can also use Shadow instead of Strikethrough if you think someone somewhere might need to use Strikethrough font inside a chart.
The PowerPoint object model doesn't provide any property or method for that.

Error 5941 The requested member of the collection does not exist

Good day! So its quiet a simple logic i want to add a picture as a default background for different sections. Like A3 portrait format has one, Landscape another, and so on. I keep on getting the 5941 Error in the code section below. Apologies for the code arrangement as it keeps on formatting it.
Application.Templates.LoadBuildingBlocks
Dim objDocument As Document
Dim objSection As Section
For i = 1 To Selection.Information(wdActiveEndPageNumber) Step 1
Set objDocument = ActiveDocument
For Each objSection In objDocument.Sections
With objSection.PageSetup
If .Orientation = wdOrientPortrait Then
'A4 portrait
If .PageHeight > CentimetersToPoints(22) And .PageHeight < CentimetersToPoints(30) And .PageWidth < CentimetersToPoints(30) Then
'In this portion, below, my code is highlighted. however if I change i to any digit, it seems working just fine. I want it to an iteration but FOR loop does not work, where did i go wrong?
Set MyImage1 = **ThisDocument.Sections(i)**.Headers(wdHeaderFooterPrimary) _
.Range.InlineShapes.AddPicture(ImagePath1).ConvertToShape
MyImage1.WrapFormat.Type = wdWrapBehind
With MyImage1
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Top = wdShapeTop
.Left = wdShapeLeft
.Height = CentimetersToPoints(29.7)
.Width = CentimetersToPoints(21)
End With
'A3 portret
ElseIf .PageHeight > CentimetersToPoints(30) And .PageWidth < CentimetersToPoints(30) Then
Set MyImage7 = ThisDocument.Sections(i).Headers(wdHeaderFooterPrimary) _
.Range.InlineShapes.AddPicture(ImagePath7).ConvertToShape
MyImage7.WrapFormat.Type = wdWrapBehind
With MyImage7
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Top = wdShapeTop
.Left = wdShapeLeft
.Height = CentimetersToPoints(42)
.Width = CentimetersToPoints(29.7)
End With
ElseIf .Orientation = wdOrientLandscape Then
' A4 landscape
ElseIf .PageHeight < CentimetersToPoints(22) And .PageWidth < CentimetersToPoints(30) Then
Set MyImage3 = ThisDocument.Sections(i).Headers(wdHeaderFooterPrimary) _
.Range.InlineShapes.AddPicture(ImagePath3).ConvertToShape
MyImage3.WrapFormat.Type = wdWrapBehind
With MyImage3
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Top = wdShapeTop
.Left = wdShapeLeft
.Height = CentimetersToPoints(21)
.Width = CentimetersToPoints(29.7)
End With
'A3 landscape
ElseIf .PageHeight > CentimetersToPoints(30) And .PageWidth > CentimetersToPoints(30) Then
Set MyImage6 = ThisDocument.Sections(i).Headers(wdHeaderFooterPrimary) _
.Range.InlineShapes.AddPicture(ImagePath6).ConvertToShape
MyImage6.WrapFormat.Type = wdWrapBehind
With MyImage6
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Top = wdShapeTop
.Left = wdShapeLeft
.Height = CentimetersToPoints(29.7)
.Width = CentimetersToPoints(42)
End With
End If
End If
End With
Next
Next
Your code seems rather confused and contains several undeclared variables.
You start off with a loop stepping though a counter of the pages in
the selection. This is unnecessary and should be removed because
there is no connection between the number of pages and the number of
sections in a document.
You are setting objDocument within the initial loop. This means
that objDocument is reset at each pass through the loop. Set
objDocument = ActiveDocument should be moved to the beginning of
your code before the loop begins.
You then loop through the sections in objDocument. This is the only
loop you need in your code.
When you come to adding the image you suddenly switch from
objDocument to ThisDocument. Depending on where the code modules
are located ThisDocument may not be the same document as
objDocument.
You then introduce a further potential source of error with
ThisDocument.Sections(i). As the counter you are using is not
related to the number of sections it is highly likely that
ThisDocument.Sections(i) doesn't exist. You should replace this
with objSection.

How to move shapes in Word to a bookmark position

I have a shape in a Word document that I need to move to a bookmark location.
I tried to use the "left" and "top" properties, however, this does not work because to my knowledge, bookmark does not have "left" and "right properties.
I have tried to use cut and paste, but this does not work for shapes.
The following is the code to create the shape:
Set shp = ActiveDocument.Content.InlineShapes.AddOLEControl("Forms.CommandButton.1")
With ActiveDocument.InlineShapes(1).OLEFormat.Object
.Caption = "Test"
.Height = 30
.Width = 44
End With
With ActiveDocument.InlineShapes(1).ConvertToShape
.Name = "Test1"
.ZOrder (msoBringInFrontOfText)
End With
Instead of using a bookmark could you use an Absolute Position on the document somewhere?
Dim Test1 As Shape
Set Test1 = ActiveDocument.Shapes("Test1")
With Test1
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Left = InchesToPoints(6.889)
.Top = InchesToPoints(0.374)
End With
End Sub
This is a very old thread, but the basic premise is still valid, and it is possible to insert a control at a bookmarked location (here a bookmark named 'bmShape') using VBA as shown below.
Dim oRng As Range
Dim oShp As InlineShape
Set oRng = ActiveDocument.Bookmarks("bmShape").Range
oRng.Text = ""
Set oShp = oRng.InlineShapes.AddOLEControl("Forms.CommandButton.1")
oRng.End = oRng.End + 1
oRng.Bookmarks.Add "bmShape"
With oShp.OLEFormat.Object
.Caption = "Test"
.Height = 30
.Width = 44
End With
With oShp.ConvertToShape
.Name = "Test1"
.WrapFormat.Type = wdWrapSquare
.WrapFormat.Side = wdWrapBoth
End With