Index out of range error in Powerpoint VBA - vba

My macro throws an "index out of range" error as it goes through ActiveWindow.Selection.shapeRange on one particular group of shapes only.
The specific presentation can be found at http://free-editable-worldmap-for-powerpoint.en.softonic.com (select any larger group of shapes, i.e. South America, and run the code to replicate error)
The code is below:
Dim shp As Shape
For Each shp In ActiveWindow.Selection.shapeRange
shp.Fill.Transparency = 0 'Or any other code
Next shp
I also tried using For loop with no success ('For i=1 To ActiveWindow.Selection.shapeRange.Count Step 1'). Notably, there is no particular index at which the error is thrown- sometimes it's i=3, sometimes i=35, sometimes more.

There are some msoLine shapes in this slide (shp.Type = 9). This will raise an error:
The specified value is out of range.
If you have inadvertently selected them. (I would expect an Object does not support this property or method error, since the msoLine does not have a .Fill member -- but sometimes the error messages are cryptic. In any case, this error can be trapped).
All of the other shapes on that slide are type 5 or 6, which support the .Fill.
I used this to debug, although I am unable to replicate your specific error (unless you simply mistyped the error description), perhaps it will be of some assistance to you. It attempts to set the Fill.Forecolor for all shapes in the slide, and will print some information about errors to the Immediate Window in the VBE.
Sub Test()
'Determine there are shapes which do not have a .Fill.ForeColor
Dim shp As Shape
For Each shp In ActivePresentation.Slides(1).Shapes
On Error Resume Next
shp.Fill.ForeColor.RGB = 43506
If Err.Number <> 0 Then
Debug.Print Err.Description & " >> " & _
shp.Name & " is shape type " & shp.Type
On Error GoTo 0
Else:
shp.Fill.Transparency = 0
shp.Fill.ForeColor.RGB = 12632256
End If
Next
End Sub

Related

Paste Special msoClipboardFormatPlainText creates unwanted line break on Mac

I'm trying to make my vba macros for PowerPoint work on a Mac, too. A lot of them do, but there are little things going wrong here or there.
One macro is for copying text from one selected shape to other selected shapes without formatting.
I use
.TextFrame2.TextRange.PasteSpecial msoClipboardFormatPlainText
The macro does as it should on Windows machines, and so it does on the Mac, only with one little problem: It creates an unwanted line break at the end of the text in the target shapes. Does anyone know a way to avoid this?
The option
.TextFrame2.TextRange.PasteSpecial msoClipboardFormatRTF
does not create this break, but it keeps the font color of the source shape, and same to
.TextFrame2.TextRange.PasteSpecial msoClipboardFormatNative
which keeps font color and font size of the source shape. The PlainText option is closest to my aim at the moment. But of course I wish I could have a perfect solution.
Any hint is appreciated. Thank you!
Edit: This is the complete code. After John's suggestion I added the Line starting with .text, but it made no difference on my Mac.
Sub DubTextOnly()
Dim shp As Shape
Dim shp1 As Shape
Dim i As Integer
On Error GoTo err
If ActiveWindow.Selection.ShapeRange.Count < 2 Then
MsgBox "Please select at least two shapes (no tables)"
Exit Sub
End If
Set shp1 = ActiveWindow.Selection.ShapeRange(1)
shp1.TextFrame2.TextRange.Copy
DoEvents
shp1.Tags.Add "Deselect", "yes"
For Each shp In ActiveWindow.Selection.ShapeRange
If shp.Tags("Deselect") = "yes" Then
Else
With shp
With .TextFrame
For i = 1 To 9
With .Ruler
.Levels(i).FirstMargin = 0
.Levels(i).LeftMargin = 0
End With
Next
End With
With .TextFrame2
With .TextRange
.ParagraphFormat.Bullet.Type = ppBulletNone
.PasteSpecial msoClipboardFormatPlainText
.Text = Replace(.Text, vbCr & vbCr, vbCr)
End With
End With
End With
DoEvents
End If
Next shp
For Each shp In ActiveWindow.Selection.ShapeRange
If shp.Tags("Deselect") = "yes" Then
shp.Tags.Delete "Deselect"
End If
Next shp
Exit Sub
err:
MsgBox "Please select at least two shapes (no tables)"
End Sub
You're seeing the effect of different line endings in macOS and Windows. Windows uses a carriage return plus a line feed (vbCrLf in VBA), while macOS uses only a line feed vbLf. When you paste into PowerPoint, the program translates both characters into separate paragraphs, with the second one being empty.
Give this code a try:
Sub PasteTest()
With ActivePresentation.Slides(1).Shapes(1).TextFrame2.TextRange
.PasteSpecial msoClipboardFormatPlainText
.Text = Replace(.Text, vbCr & vbCr, vbCr)
End With
End Sub
It shouldn't affect operations in Windows, because double returns aren't created there.

Excel VBA error handler not working for 'run-time error 13: type mismatch'

I am running the sub below for an Excel file containing about 10 worksheets, each containing a pivottable linked to the same data source. I have two versions of the 'Market' and 'Region' fields in my data (i.e. 'Market (SC)', 'Market (AN)', 'Region (SC)', 'Region (AN)'), and need to be able to switch between them easily. I set up the code to first bring the corresponding slicers to the front (they are superimposed so that will hide the other), then loop through each pivottable and swap the other 'Market' and 'Region' fields (maintaining the same position, etc.).
Since I'm using the property ".SourceName" to identify the field, the loop runs into an error when the "Values" PivotField is compared to my string. I've put in "On Error Goto next_fld" to tell it to skip to the next field when this occurs, but this only works for 8 of the 10 worksheets -- for the other two I get the error "Run-time error '13' Type Mismatch" and the debug screen highlights the " *** " line. If I use "On Error Resume Next", it assumes that the If statement was True and carries out a lot of unwanted actions (messes up various PivotTables).
I'm self-taught and do not have a complete understanding of the error handler, but from the resources I've come across to fix this error, the handler should be taking care of this (which it does work for 8/10 worksheets).
Here is my code:
Sub SwapMktRegFields()
Dim ws As Worksheet, shp As Shape
Dim i As Integer
Dim target As String, repl As String
target = Sheet5.Range("E3").value
'Identify current field, use other as repl(acement)
Select Case target
'AN slicers selected
Case Is = "AN"
target = "(AN)"
repl = "(SC)"
Sheet5.Range("E3").value = "SC"
'SC slicers selected
Case Is = "SC"
target = "(SC)"
repl = "(AN)"
Sheet5.Range("E3").value = "AN"
End Select
'Bring replacement slicers to front (some are in shape groups)
For Each ws In ThisWorkbook.Worksheets
For Each shp In ws.Shapes
Select Case shp.Type
Case Is = msoGroup
For i = 1 To shp.GroupItems.Count
If shp.GroupItems(i).Name Like "Market " & target & "*" Or shp.GroupItems(i).Name Like "Region " & target & "*" Then shp.GroupItems(i).ZOrder msoSendToBack
Next i
Case Else
If shp.Name Like "Market " & target & "*" Or shp.Name Like "Region " & target & "*" Then shp.ZOrder msoSendToBack
End Select
Next shp
Next ws
'Replace old PivotFields with replacement PivotFields
Dim pvt As PivotTable
Dim fld As PivotField
Dim orient As Long, pos As Long
' MY ERROR HANDLER
On Error GoTo next_fld
For Each ws In ThisWorkbook.Worksheets
For Each pvt In ws.PivotTables
For Each fld In pvt.PivotFields
' *** ERROR ON NEXT LINE WHEN fld IS 'VALUES'
If fld.SourceName = "Market " & target And fld.Orientation <> xlHidden Then
orient = fld.Orientation
pos = fld.Position
fld.Orientation = xlHidden
With pvt.PivotFields("Market " & repl)
.Orientation = orient
.Position = pos
End With
ElseIf fld.SourceName = "Region " & target And fld.Orientation <> xlHidden Then
orient = fld.Orientation
pos = fld.Position
fld.Orientation = xlHidden
With pvt.PivotFields("Region " & repl)
.Orientation = orient
.Position = pos
End With
End If
next_fld:
Next fld
Next pvt
Next ws
'A custom function to clear filters and re-apply a default
ResetPivotFilters
End Sub
The weirdest part is that the error is EXACTLY THE SAME as the other 8 sheets that work with this code. If I remove the error handler completely, I get the exact same pop-up and line highlighted for the other sheets... Any suggestions would be greatly appreciated! Thanks
Tim, this was very helpful and answered my question. I updated the end of my code to the following:
ResetPivotFilters
Exit Sub
err_handler:
Resume next_fld
End Sub
and updated my error handling enabling line to "On Error Goto err_handler". Working now. Thank you!

Access a Shape inside another one in VBA

I have big shapes on my worksheet (a group of shapes), and inside everyone of them others little shapes (the blue rectangles),
I made a for loop for inside each Big shape to fill automatically the little shapes, but how can I loop over the Big ones, because all the big shapes are similars, and they have the same names for the littles shapes inside ?
How can I acces the little shape from the big one ?
I tried this but didn't worked
ActiveSheet.Shapes.Range(gr).Select
ActiveSheet.Shapes.Range(Array(x)).Select
Selection.ShapeRange(1).TextFrame2.TextRange.Characters.Text = Format(Range(y_1).Value, "#,##0") & " k" & Chr(13) & Format(Range(y_2).Value, "#,##0.00") & " DT"
The "gr" variable takes every time the name of the big shapes (Graph_1 .. Graph_5)
and the x variable takes the name of the little shapes inside (rect_1 .. rect_21)
I think this code does not help because my approach it's like how to access a case in an array if I can say ?
For Each myshape In ActiveSheet.Shapes
You can access child shapes inside a group by using following example:
Sub test()
Dim shp As Shape
Dim shpChild As Shape
For Each shp In Sheet1.Shapes
If shp.Type = msoGroup Then
'/ Found a group. List all the child shapes here.
For Each shpChild In shp.GroupItems
Debug.Print "Child name :" & shpChild.Name & " Group name : " & shp.Name
Next
Else
'/ No group. Individual shape.
Debug.Print shp.Name
End If
Next
End Sub
Here... you should have figured it out yourself :)
Sub test()
Dim shp As Shape
Dim shpChild As Shape
For Each shp In Sheet1.Shapes
If shp.Type = msoGroup And shp.Name = "A" Then
'/ Found a group called "A". List all the child shapes here.
For Each shpChild In shp.GroupItems
If shpChild.Name = "X" Then
'/ Found X.
shpChild.TextFrame2.TextRange.Text = "Hello from VBA!!!"
End If
Next
Else
'/ No group. Individual shape.
Debug.Print shp.Name
End If
Next
End Sub

Is there a way to refresh/update the hyperlink in a shape when the hyperlink is clicked?

I have shapes in a diagram that represent processes in a data flow; the shapes are hyperlinked to process definitions located in another tab based on the text in the shape and shape name (e.g. shape named "Control ##" with text "ABC" links to a tab where ABC process is defined). Is there a way to automatcially update the hyperlink in that shape if I change the text in the shape to be "XYZ" - i.e. I want the hyperlink to then go to the "XYZ" definition? I tried SheetFollowHyperlink event procedure but nothing seems to happen. Code i have so far is below:
Sub AssignHyperlink()
Dim CallerShapeName As String
CallerShapeName = Application.Caller
With ActiveSheet
Dim CallerShape As Shape
Set CallerShape = .Shapes(CallerShapeName)
Dim RowVar As Integer
Err.Number = 0
On Error Resume Next
If InStr(CallerShapeName, "Control") = 1 Then
RowVar = Application.WorksheetFunction _
.Match(.Range("C2").Value & CallerShape.TextFrame2.TextRange.Text, _
Sheets("Control Point Log").Range("A1:A700"), 0)
If (Err.Number = 1004) Then
MsgBox "No match found for this shape text in the Control Point Log"
Exit Sub
End If
On Error GoTo 0
.Hyperlinks.Add Anchor:=CallerShape, _
Address:=ActiveWorkbook.Name & "#" & "'Control Point Log'!$C$" & RowVar
Else
RowVar = Application.WorksheetFunction _
.Match(.Range("C2").Value & CallerShape.TextFrame2.TextRange.Text, _
Sheets("Data Flow Glossary").Range("A1:A700"), 0)
If (Err.Number = 1004) Then
MsgBox "No match found for this shape text in the Data Flow Glossary"
Exit Sub
End If
On Error GoTo 0
.Hyperlinks.Add Anchor:=CallerShape, _
Address:=ActiveWorkbook.Name & "#" & "'Data Flow Glossary'!$C$" & RowVar
End If
End With
End Sub
1st. I assume that your goal is to navigate to range within your workbook after you click on the shape
2nd. The range to navigate to is named range.
3rd. The range to navigate equals the text in the shape.
My proposal is to use onAction trigger of shape (assign macro when right click of the shape)
4rd. We need the following procedure- one for all shapes.
Sub Hyperlink_Workaround()
On Error GoTo ErrorHandler
Dim curHL As String
curHL = ActiveSheet.Shapes(Application.Caller).TextFrame2.TextRange.Text
'which way do you define destination?
'this way you go to named range
Application.Goto Range(curHL), True
Exit Sub
ErrorHandler:
MsgBox "There is no range like " & curHL
End Sub
5th. Test, having the following shapes on the sheet with above macro assigned, after click on any of the shape we would move to either ABC or DEF Range within our workbook.
6th. I added handler for situation when you try to navigate to the range that doesn't exist.

How to Export a Table (Shape) as JPG from Powerpoint

I am able to export Charts as JPG files from Powerpoint, but haven't been able to do this with a table, which as far as I can tell is still a "Shape" which should be able to export.
This is a cleansed version of the code I use to export the Chart as JPG.
Const imgFilePath as String = "ChartImage.JPG"
Sub ExportChartJPG()
Dim cht as Variant 'this will hold the Chart/Shape object
Set cht = ActivePresentation.Slides(1).Shapes("Chart1").Chart
On Error Resume Next
Kill imgPath
On Error GoTo 0
cht.Export imgPath, "JPG"
End Sub
I figured this would be simple to modify, like:
Sub ExportChartJPG()
Dim cht as Variant 'this will hold the Chart/Shape object
Set cht = ActivePresentation.Slides(1).Shapes("Table1").Table
On Error Resume Next
Kill imgPath
On Error GoTo 0
cht.Export imgPath, "JPG"
End Sub
But this is throwing an error 13 Mismatch.
I have also tried dimensioning cht as a Shape instead of Variant, and setting cht = ActivePresentation.Slides(1).Shapes("Table1"), also unsuccessfully.
Although KazJaw's solution works, it was a bit cumbersome (copying takes additional time to process, I was getting errors I think as a result of not "waiting" long enough for the copy to complete, clipboard issues? etc.)
http://www.tech-archive.net/pdf/Archive/Office/microsoft.public.office.developer.vba/2006-10/msg00046.pdf
I open the object browser, right-click, and show hidden methods, which now allows me to use the Export method on a Shape.
Sub ExportShapeJPG()
Dim cht as Variant 'this will hold the Chart/Shape object
Set cht = ActivePresentation.Slides(1).Shapes("Table1") '<-- removed .Table and only pass the Shape itself
'Likewise, for charts, omit the .Chart:
' Set cht = ActivePresentation.Slides(1).Shapes("Chart1")
On Error Resume Next
Kill imgPath
On Error GoTo 0
cht.Export imgPath, ppShapeFormatJPG '<-- The export syntax is slightly different using ppShapeFormatJPG instead of "JPG"
End Sub
I have one quite weird idea. Look at the code where first part save a chart and second save table.
Sub ExportinChartAndTable()
Dim imgFilePath As String
imgFilePath = ActivePresentation.Path & "\chart"
Dim shp As Shape
Set shp = ActivePresentation.Slides(1).Shapes(1)
Dim shpChart As Chart
Set shpChart = shp.Chart
'exporting chart
On Error Resume Next
Kill imgFilePath
On Error GoTo 0
shpChart.Export imgFilePath & "chart.jpg", "JPG"
Stop
Dim chartPart As ChartData
Set chartPart = shpChart.ChartData
imgFilePath = ActivePresentation.Path & "\dataTable.jpg"
chartPart.Workbook.worksheets("arkusz1").Range("a1:c20").Copy
shpChart.Paste
shpChart.Shapes(1).Width = shp.Width
shpChart.Shapes(1).Height = shp.Height
On Error Resume Next
Kill imgFilePath
On Error GoTo 0
shpChart.Export imgFilePath, "JPG"
End Sub
You have to come up with idea how to check the range of the table. I hoped that CurrentRegion would work but it's not. You could use the possibility to count the amount of rows and columns in the table (it is possible). Or maybe you have fixed range so it would be easy. One more thing, you have to adjust dimension when table is resized.
EDIT due to David comment. I keep the above solution in place as could be useful for others (please refer to comments below)
Sub SolutionSecond()
Dim whereTo As String
whereTo = ActivePresentation.Path & "\table.jpg"
Dim shp As Shape
Set shp = ActivePresentation.Slides(1).Shapes(1)
Dim chrt As Shape
Set chrt = ActivePresentation.Slides(1).Shapes.AddChart
shp.Copy
'required due to excel opening proces
chrt.Select
chrt.Chart.Paste
'set dimensions here
chrt.Chart.Export whereTo, "JPG"
chrt.Delete
End Sub
This one base on the same logic. Copy table into chart which (the only kind of Shape) could be exported.