Pivot Chart Title to Display Multiple Selected Items - excel

I have a pivotchart that when the selected filter (work center) is changed, it updates the chart title to display that work center name. However, if I check the box to allow multiple selections, the chart title simply shows "All" instead of showing each of the actual selected items. I haven't found a way to get it to show what I'm looking for. Below is the code that I'm using to update the chart title as well as the code for the filter change event that fires it off
Option Explicit
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
On Error Resume Next
Application.Run "'Prod_Tools.xlam'!gPTWCChange", Target.PivotFields("WorkCenter").CurrentPage
On Error GoTo 0
End Sub
Sub gPTWCChange(ByVal WC As String)
Dim wb1 As Workbook
Dim CPWB1 As Workbook
For Each wb1 In Workbooks
If InStr(1, wb1.Name, "Capacity Planning Rep", vbTextCompare) > 0 Then
Set CPWB1 = Workbooks(wb1.Name)
Exit For
End If
Next wb1
On Error Resume Next
CPWB1.Charts("Workcenter By Week").ChartTitle.Text = "Work Center: " & WC
On Error GoTo 0
End Sub
What I would like is when multiple items are selected, have the chart title look like "Data for: Workcenter_A, Workcenter_B, Workcenter_F"

Here's your adapted sub. Notice that its parameter has changed.
Public Sub gPTWCChange(ByVal pfWC As Excel.PivotField)
Const sSEPARATOR As String = ", "
Dim sChartTitle As String
Dim oPivotItem As Excel.PivotItem
Dim lVisibleCount As Long
'... Your original code ...
Dim wb1 As Workbook
Dim CPWB1 As Workbook
For Each wb1 In Workbooks
If InStr(1, wb1.Name, "Capacity Planning Rep", vbTextCompare) > 0 Then
Set CPWB1 = Workbooks(wb1.Name)
Exit For
End If
Next wb1
'... New code to compute the chart title ...
If pfWC.EnableMultiplePageItems Then
'Build the chart title from the visible items in the PivotField.
lVisibleCount = 0
For Each oPivotItem In pfWC.PivotItems
If oPivotItem.Visible Then
lVisibleCount = lVisibleCount + 1
sChartTitle = sChartTitle & sSEPARATOR & oPivotItem.Caption
End If
Next
'Drop the leading separator.
sChartTitle = Mid$(sChartTitle, Len(sSEPARATOR) + 1)
'Manage plural.
sChartTitle = "Work Center" & IIf(lVisibleCount > 1, "s", "") & ": " & sChartTitle
Else
sChartTitle = "Work Center: " & pfWC.CurrentPage
End If
'... Your original code ...
On Error Resume Next
CPWB1.Charts("Workcenter By Week").ChartTitle.Text = sChartTitle
On Error GoTo 0
End Sub
And call your sub as follows:
Application.Run "'Prod_Tools.xlam'!gPTWCChange", Target.PivotFields("WorkCenter")
The principle is to send your sub a reference to the PivotField object, and from there, check its EnableMultiplePageItems property.

Related

Vba, Programatically assign a macro to a "Shape" inside shapegroup

Thanks in advance, not sure why this wouldn't work.
I want to assign a macro to each button inside a shape group on load.
Inside Module:
Private Const SideNavName As String = "SideNav"
Public Sub SetSideNavigationOnAllSheets()
Dim ws As Worksheet
Dim oShape As Shape
For Each ws In ActiveWorkbook.Sheets
'check to see if sidenav shape/group exists in sheet
If Common.ShapeExists(ws, SideNavName) Then
' get side nav
For Each oShape In ws.Shapes(SideNavName).GroupItems
' only need the nav buttons not container
If Left(oShape.Name, 3) = "Nav" Then
Debug.Print ws.Name, oShape.Name
oShape.TextFrame.Characters.Text = "btn 1" ' pull from DB
oShape.OnAction = "'" & ActiveWorkbook.Name & "'!FolderSelectorButton" ' ERRORS OUT HERE
End If
'
Next
End If
Next
End Sub
Public Sub FolderSelectorButton()
Debug.Print 1
End Sub
Seems VBA doesn't like setting the OnAction property for Shapes that have been grouped. Solution is to store details of the group, ungroup it, update the OnAction property then re-create the group.
Replace your two lines setting the TextFrame and OnAction of the oShape object with the following:
' save then ungroup the Shapes
Dim oShpGrp As Shape, sShapeNames() As String, i As Long
Set oShpGrp = ws.Shapes(SideNavName)
ReDim sShapeNames(1 To oShpGrp.GroupItems.Count)
For i = 1 To oShpGrp.GroupItems.Count
sShapeNames(i) = oShpGrp.GroupItems.Item(i).Name
Next i
oShpGrp.Ungroup
' update Shape
oShape.TextFrame.Characters.Text = "btn 1" ' pull from DB
oShape.OnAction = "'" & ActiveWorkbook.Name & "'!FolderSelectorButton" ' ERRORS OUT HERE
' re-group the Shapes
Set oShpGrp = oShpGrp.Parent.Shapes.Range(sShapeNames).Group
oShpGrp.Name = SideNavName
This assumes that the group is a single-level group (ie it is not a group embedded within another group)

Is it possible to loop through excel worksheets and run slightly different code on each one?

I would like to loop through 4 certain worksheets in a workbook.
Bulk of the code I am running is the same in each sheet.
I am also opening and linking different cells from other workbooks and these will be different on each sheet, hence why my code will be slightly different as it will change variables.
The problem I have is It's working but ignores the rest of my if statements except the first so doesn't run the way I want it to. Example below
Sub CompleteSummary()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim x As Workbook
Dim sht As Worksheet
Dim Sshts As Variant
Dim Ssht As Variant
Dim i As Integer
Set x = Workbooks.Open(s, ReadOnly:=True)
If Application.Calculation = xlCalculationAutomatic Then
Else: Application.Calculation = xlCalculationAutomatic
End If
Sshts = Array("First1", "Second1", "Third1", "Fourth1")
For i = 0 To UBound(Sshts)
Set sht = x.Worksheets(Sshts(i))
Debug.Print "print me " & Sshts(i)
If sht.Name = "First1" Then
Debug.Print "opened 1st"
ElseIf sht.Name = "Second1" Then
Debug.Print "opened 2nd"
ElseIf sht.Name = "Third1" Then
Debug.Print "opened 3rd"
ElseIf sht.Name = "Fourth1" Then
Debug.Print "opened 4th"
End If
Debug.Print "Complete"
Next i
The output result is as follows:
print me First1
opened 1st
Complete
print me Second1
Complete
print me Third1
Complete
print me Fourth1
Complete
What I would like it to do is this:
print me First1
opened 1st
Complete
print me Second1
opened 2nd
Complete
print me Third1
opened 3rd
Complete
print me Fourth1
opened 4th
Complete
As you can see it just takes the first if condition throughout the loop and ignores the rest despite it cycling through all of the sheets.
Any ideas or even if there is a better way than a loop and if conditions?
I think this would be an easier approach:
Dim wb As Workbook: Set wb = ThisWorkbook
Dim x As Workbook
Dim sht As Worksheet
Set x = Workbooks.Open(s, ReadOnly:=True)
Application.Calculation = xlCalculationAutomatic 'just do it...
For Each sht In x.Worksheets
Debug.Print "Checking: " & sht.Name
Select Case sht.Name
Case "First1": Debug.Print "opened 1st"
Case "Second1": Debug.Print "opened 2nd"
Case "Third1": Debug.Print "opened 3rd"
Case "Fourth1": Debug.Print "opened 4th"
End Select
Debug.Print "Done checking"
Next sht
For extra robustness compare the lower-cased names.
By your description you don't need an Ifs or Elses. Instead just call a sub that has the repetitive code and feed it arguments that make up the difference. Here is a schematic example.
Option Explicit
Sub CompleteSummary()
' 113
Dim Wb As Workbook
Dim WsName() As String
Dim i As Integer
If Application.Calculation = xlCalculationAutomatic Then
Application.Calculation = xlCalculationManual
Else
Application.Calculation = xlCalculationAutomatic
End If
Set Wb = ThisWorkbook
WsName = Split("First1,Second1,Third1,Fourth1", ",")
For i = 0 To UBound(WsName)
If DoTheWork(WsName(i)) Then Debug.Print "Complete"
Next i
Application.Calculation = xlCalculationAutomatic
End Sub
Private Function DoTheWork(WsName As String) As Boolean
' 113
On Error Resume Next
Debug.Print "Opened " & WsName
DoTheWork = (Err.Number = 0) ' no error occurred
Err.Clear
End Function
If there are different workbooks to be opened depending upon which worksheet is being worked on you can make this choice either in the main procedure or the sub. In the latter case you would pass 2 parameters instead of the one in my example. I think you could pass up to 255 arguments.
I developed the sub as a function which returns True or False depending upon whether the action was executed without error. You could also let the function return another value, such as the result of a calculation which is slightly different for each set of arguments and that you may use to continue whatever the Main procedure is doing.
Multiple Worksheets
I suspect what happened was that your last three worksheets had slightly different names i.e. their case was different.
The First Procedure CompleteSummary
The contents of the Sheet Names Array demonstrate the opposite of the previous case: the worksheet names are intentionally written in a different case to show that case doesn't matter when accessing a worksheet (or opening a workbook).
The use of the Opened Array allows us to avoid the If clause and therefore avoid checking the worksheet names.
With the With statements we can avoid using additional variables.
The first Debug.Print line will print the actual worksheet names and the names in the Sheet Names Array in parentheses.
The second Debug.Print line further shows how the If clause is avoided.
The Second Procedure StringCompare
When comparing strings where there might be a difference in case, you can use one of the ways presented in this procedure.
Most often I have seen the use of LCase or UCase, but I prefer StrComp whose only purpose is to compare two strings.
In your particular case, for all comparisons you could have e.g. used one of the following options:
If LCase(sht.Name) = LCase("First1") Then
If UCase(sht.Name) = UCase("First1") Then
If StrComp(sht.Name, "First1", vbTextCompare) = 0 Then
etc.
Additionally there is an option of using Option Compare Text right after Option Explicit i.e. before any procedure. Then you could safely use your solution without any changes.
The Code
Option Explicit
'Option Compare Text
Sub CompleteSummary()
Const wbPath As String = "F:\Test\2020\64688445\Test.xlsm"
Dim SheetNames As Variant
SheetNames = Array("FiRst1", "SecOnd1", "ThiRd1", "FouRth1")
Dim Opened As Variant
Opened = Array("1st", "2nd", "3nd", "4th")
Dim n As Long
With Workbooks.Open(Filename:=wbPath, ReadOnly:=True)
For n = LBound(SheetNames) To UBound(SheetNames)
With .Worksheets(SheetNames(n))
Debug.Print "print me " & .Name & " (" & SheetNames(n) & ")"
Debug.Print "opened " & Opened(n)
Debug.Print "Complete"
End With
Next n
' Since each workbook was only read from we can safely close it.
'.Close SaveChanges:=False
End With
End Sub
Sub StringCompare()
Debug.Print "Assign: ", "A" = "a"
Debug.Print "Like: ", "A" Like "a"
Debug.Print "StrComp0:", StrComp("A", "a") = 0
Debug.Print
Debug.Print "LCase: ", LCase("A") = LCase("a")
Debug.Print "UCase: ", UCase("A") = UCase("a")
Debug.Print "StrComp1:", StrComp("A", "a", vbTextCompare) = 0
Debug.Print "StrCpmvL:", StrConv("A", vbLowerCase) _
= StrConv("a", vbLowerCase)
Debug.Print "StrConvU:", StrConv("A", vbUpperCase) _
= StrConv("a", vbUpperCase)
Debug.Print
End Sub

Run a Power point macro code for other PPTs

I have a macro code named "KillSpecificSlide" for power point. This codes is run behind ppt.If I want to copy the same code to some another ppt or if I want to run the code from One PPT to some other different PPTs then How to do this?
My code is given below:
Sub KillSpecificSlide()
Dim oSld As Slide
Dim oShp As Shape
Dim L As Long
For L = ActivePresentation.Slides.Count To 1 Step -1
Set oSld = ActivePresentation.Slides(L)
For Each oShp In oSld.Shapes
If oShp.HasTextFrame Then
Select Case UCase(oShp.TextFrame.TextRange)
Case Is = "Q4", "CJ"
oSld.Delete
Case Else
'not found
End Select
End If
Next oShp
Next L
End Sub
This is saved in Module 1 of a PPT named BOX.pptm..I want to run the same code for other ppt files by browsing it.
Sub PPTTest()
Dim PPT As Object
Set PPT = CreateObject("PowerPoint.Application")
PPT.Presentations.Open "D:\Us\70\Desktop\Shaon\BOD.pptx", , , False
' Note that the file name and the module
' name are required to path the macro correctly.
PPT.Run "BOD.pptx!Module1.KillSpecificSlide"
End Sub
Option Explicit
Sub listOpenPresentations()
Dim myPpt As Presentation
Debug.Print "Open ppt's : "; Application.Presentations.Count & vbCrLf
For Each myPpt In Application.Presentations
Debug.Print myPpt.Name
Call Add_and_Delete_Slide(myPpt)
Next myPpt
End Sub
Sub Add_and_Delete_Slide(locPPT As Presentation)
Dim pptSlide As Slide
Dim pptLayout As CustomLayout
Dim actWindow As Variant
For Each actWindow In Windows
If actWindow.Caption = locPPT.Name Then actWindow.Activate
Next actWindow
Set pptLayout = ActivePresentation.Slides(1).CustomLayout
Set pptSlide = ActivePresentation.Slides.AddSlide(2, pptLayout)
MsgBox "Slide 2 added in """ & ActivePresentation.Name & """"
ActivePresentation.Slides(2).Delete
MsgBox "Slide 2 deleted in """ & ActivePresentation.Name & """"
End Sub

Powerpoint: Manually set Slide Name

Context:
A PowerPoint slide in C# has a property Slide.Name (usually contains an arbitrary string value).
In my C# application I would like to use this property to identify slides (the slide order is to unreliable).
Question:
How can I manually set the Slide.Name property in the PowerPoint Application?
My problem is very like to the: “How to name an object within a PowerPoint slide?” but just on the slide level.
Any help would be appreciated.
There is no built-in functionality in PowerPoint that allows you to edit the name of a slide. As Steve mentioned, you have to do it using VBA code. The slide name will never change due to inserting more slides, and it will stay the same even if you close PowerPoint; the slide name set in VBA code is persistent. Here's some code I wrote to allow you to easily view the name of the currently selected slide and allow you to rename it:
'------------------------------------------------------------------
' NameSlide()
'
' Renames the current slide so you can refer to this slide in
' VBA by name. This is not used as part of the application;
' it is for maintenance and for use only by developers of
' the PowerPoint presentation.
'
' 1. In Normal view, click on the slide you wish to rename
' 2. ALT+F11 to VB Editor
' 3. F5 to run this subroutine
'------------------------------------------------------------------
Sub NameSlide()
Dim curName As String
curName = Application.ActiveWindow.View.Slide.name
Dim newName As String
retry:
newName = InputBox("Enter the new name for slide '" + curName + "', or press Cancel to keep existing name.", "Rename slide")
If Trim(newName) = "" Then Exit Sub
Dim s As Slide
' check if this slide name already exists
On Error GoTo SlideNotFound
Set s = ActivePresentation.Slides(newName)
On Error GoTo 0
MsgBox "Slide with this name already exists!"
GoTo retry
Exit Sub
SlideNotFound:
On Error GoTo 0
Application.ActiveWindow.View.Slide.name = newName
MsgBox "Slide renamed to '" + newName + "'."
End Sub
You can't manually set the slide name, but with a bit of code, it's simple. In VBA, for example:
Sub NameThatSlide()
ActivePresentation.Slides(1).Name = "Whatever You Like Here"
End Sub
You can rename a slide manually or with VBA. Once you know how, the door opens to some interesting possibilities, which I will demonstrate with code below.
Manually renaming slides. This ability is hidden in the VBA Editor's Properties pane, but it does not require coding.
If the Developer ribbon is not visible, enable it: File > Options > Customize Ribbon > check the Developer Main Tab.
From the Developer ribbon, click the Visual Basic menu item to open the Visual Basic Editor.
Press the Ctrl+R keys to navigate to the Project Explorer pane.
Expand "Microsoft PowerPoint Objects"
Click on any slide to select it.
Press the F4 key to navigate to the Properties pane.
Edit the (Name) item, and press Enter to apply the name change.
The slide name change may not appear immediately in the VBA Project Explorer pane. As long as the name is correct in the Properties pane, the name changed successfully.
This VBA code will also do the trick (hide slide number 1):
ActivePresentation.Slides(1).SlideShowTransition.Hidden = msoTrue
This code block covers a few ways to manage slide names and answers the main question.
Option Explicit
Public Function RenameSlide(oldName As String, newName As String)
' RenameSlide finds slide oldName and renames it to newName.
' Arguements:
' oldName: current (old) name of existing slide
' newName: new name for slide.
'
Dim tempBool As Boolean
Dim sld As Slide
Dim RetVal(0 To 1) As String
' Check if oldName can be found.
If SlideExists(oldName) Then
Set sld = Application.ActivePresentation.Slides(oldName)
Else
RetVal(0) = 1 'Error 1
RetVal(1) = "Error 1: slide with name " & oldName & " not found. Aborting."
Exit Function
End If
' Check if this slide name newName already exists.
If SlideExists(newName) Then
RetVal(0) = 2 'Error 1
RetVal(1) = "Error 2: slide with name " & newName & " already exists. Aborting."
Exit Function
End If
' Rename the slide
'Application.ActivePresentation.Slides(oldName) = newName
Application.ActivePresentation.Slides(oldName).Select
Application.ActiveWindow.View.Slide.Name = newName 'current slide
RetVal(0) = 0 'Success
RetVal(1) = "Success: slide renamed from '" & oldName & "' to '" & newName & "'."
End Function
Public Sub SetSlideName()
' Prompt user for new name for active slide.
'
Dim oldName As String
Dim newName As String
Dim sld As Slide
Dim msg As String
' Get current name of active slide.
oldName = Application.ActiveWindow.View.Slide.Name
msg = "Enter the new name for slide '" + oldName + "'."
retry:
newName = ""
' Prompt for new slide name. Loop until a name of at least 1 character is provided.
Do While newName = ""
newName = InputBox(msg, "Rename slide")
newName = Trim(newName)
If Len(newName) = 0 Then
msg = "Try again. You must enter a slide name to continue."
ElseIf newName = oldName Or newName = Str(vbCancel) Then
Exit Sub
End If
Loop
' If an existing slide already has name newName, then
' go back and prompt user again.slide name already exists
If SlideExists(newName) Then
msg = "Slide with this name already exists!"
GoTo retry
End If
' Set the new slide name
Application.ActiveWindow.View.Slide.Name = newName
MsgBox "Slide renamed to '" + newName + "'."
End Sub
Public Function SlideExists(SlideName As String) As Boolean
Dim RetVal As Boolean
Dim sld
' Assume slide does not exist.
SlideExists = False
' Try to find slide by name.
' If we error out, the slide does NOT exist.
On Error GoTo NoSlide
Set sld = ActivePresentation.Slides(SlideName)
' If we got this far, the slide DOES exist.
SlideExists = True
Exit Function
NoSlide:
' Error setting slide objects shows
' that slides does NOT exist.
SlideExists = False
End Function
As an aside, I use the slide naming trick and a little VBA to selectively remove certain slides from printing. I added a few extra VBA macros for the sake of populating the Macros list. From any slide: Developer ribbon > Macros > Select Macro > Run button. Use this method to kick off my PresentSlide, DontPresentSlide, PrintSlide and DontPrintSlide macros. Once you have properly tagged your various slides, simply run the PrepToPresentSlides or PrepToPrintSlides macro before you present or print, respectively.
Play around with these macros a bit and read the comments. You will find that I wrote the code extensibly, so you can modify it easily for your needs.
The code below helps me to manage which slides and objects are printed and which are presented on-screen. This is particularly useful when I want to print reference slides but not cover them. It is even more useful when I have slides with animations. Animations don't usually translate print well. So, I choose not to print some animated objects at all. In fact, I can even add in substitute content for the objects to be used just for printing (hidden when presenting) - though I rarely do this. Instead, I will typically hide the animation from printing or create a slide to present and a non-animated copy of it for print. With these macros, it is easy to manage a mix and match of slides and objects for print and slides and objects for presentation. I hope you enjoy.
Option Explicit
' DontPresentSlide - run macro while on a slide you wish to skip while presenting.
' The slide name will be appended with "NoPresent". You still
' need to run PrepToPresent before presenting to hide slide.
' PresentSlide - "NoPresent" will be removed from the slide. You still
' need to run PrepToPresent before presenting to hide slide.
' PrepToPesentSlides() - Unhide slides and objects you want presented and
' hide slides and objects you do NOT want presented.
' ShowNoPressnt() - show slides and shapes marked "NoPresent"
' HideNoPresent() - hide slides and shapes marked "NoPresent"
' DontPrintSlide - run macro while on a slide you wish to skip while presenting.
' The slide name will be appended with "NoPrint". You still
' need to run PrepToPresent before presenting to hide slide.
' PrintSlide - "NoPrint" will be removed from the slide. You still
' need to run PrepToPresent before presenting to hide slide.
' PrepToPrintSlides() - Unhide slides and objects you want printed and
' hide slides and objects you do NOT want printed.
' ShowNoPrint() - show slides and shapes marked "NoPrint"
' HideNoPrint() - hide slides and shapes marked "NoPrint"
' ShowHideSlides() - Hide or Unhide slides based on slide name.
' ShowHideShapes() - Hide or Unhide shapes based on shapes name.
Public Const cjaHide = False
Public Const cjaShow = True
Public Const cjaToggle = 2
Sub ShowHideSlides(NameContains As String _
, Optional LMR As String = "R" _
, Optional ShowSlide As Integer = False)
' Show or Hide slides based on slide name.
' Arguements:
' NameContains (string):
' slides with this string will be modified.
' LMR (string): enter L, M or R to indicate
' searching the Left, Middle or Right of
' the slide name, respectively.
' ShowSlide (integer):
' Show: True (-1)
' Hide: False (0)
' Toggle: 2
'
' To show or hide slides manually:
' Right-click the slide thumbnail, then click Hide Slide
' To rename slides,
' Use this VBA: ActiveWindow.View.Slide.Name = "NewSlideName"
' Or, edit the (Name) property in the VBA Properties window.
'
Dim sldCurrent As Slide
Dim found As Boolean
found = False
LMR = Trim(UCase(LMR))
If LMR <> "L" And LMR <> "M" Then LMR = "R"
'Loop through each slide in presentation.
For Each sldCurrent In ActivePresentation.Slides
'Match shape name left, right or middle as per LMR arguement.
'ActiveWindow.View.Slide.Name or Slide.SlideNumber
found = False
If LMR = "R" And LCase(right(sldCurrent.Name, Len(NameContains))) = LCase(NameContains) Then
found = True
ElseIf LMR = "L" And LCase(left(sldCurrent.Name, Len(NameContains))) = LCase(NameContains) Then
found = True
ElseIf LMR = "M" And InStr(1, LCase(NameContains), LCase(sldCurrent.Name)) Then
found = True
End If
'If match found, then set shape visibility per ShowShape arguement.
If found Then
If ShowSlide = True Then
ActivePresentation.Slides(sldCurrent.SlideNumber).SlideShowTransition.Hidden = msoFalse
ElseIf ShowSlide = False Then
ActivePresentation.Slides(sldCurrent.SlideNumber).SlideShowTransition.Hidden = msoTrue
Else
ActivePresentation.Slides(sldCurrent.SlideNumber).SlideShowTransition.Hidden = Not ActivePresentation.Slides(sldCurrent.SlideNumber).SlideShowTransition.Hidden
End If
End If
Next 'sldCurrent
End Sub
Sub ShowHideShapes(NameContains As String _
, Optional LMR As String = "R" _
, Optional ShowShape As Integer = False)
' Show or Hide shapes/objects based on object name.
' Arguements:
' NameContains (string):
' shapes with this string will be modified.
' LMR (string): enter L, M or R to indicate
' searching the Left, Middle or Right of
' the slide name, respectively.
' ShowSlide (integer):
' Show: True (-1)
' Hide: False (0)
' Toggle: 2
'
' To show, hide and/or rename objects:
' 1. Turn on Selection Pane via: Home Ribbon >
' Select > Selection Pane.
' 2. Double-click a shape name to rename it.
' 3. Click the eye icon to the far right to show/hide a shape.
Dim shpCurrent As Shape
Dim sldCurrent As Slide
Dim found As Boolean
found = False
LMR = Trim(UCase(LMR))
If LMR <> "L" And LMR <> "M" Then LMR = "R"
'Loop through each slide in presentation.
For Each sldCurrent In ActivePresentation.Slides
With sldCurrent
'Loop through each shape on current slide.
For Each shpCurrent In .Shapes
'Match shape name left, right or middle as per LMR arguement.
found = False
If LMR = "R" And right(shpCurrent.Name, Len(NameContains)) = NameContains Then
found = True
ElseIf LMR = "L" And left(shpCurrent.Name, Len(NameContains)) = NameContains Then
found = True
ElseIf LMR = "M" And InStr(1, NameContains, shpCurrent.Name) Then
found = True
End If
'If match found, then set shape visibility per ShowShape arguement.
If found Then
If ShowShape = True Then
shpCurrent.Visible = True
ElseIf ShowShape = False Then
shpCurrent.Visible = False
Else
shpCurrent.Visible = Not shpCurrent.Visible
End If
End If
Next 'sldCurrent
End With 'sldCurrent
Next 'sldCurrent
End Sub
Sub HideNoPrint()
' Hide slides and shapes you do NOT want printed.
'
' Run this macro to hide all slides and shapes that
' end with the string "NoPrint".
' Usage. Assume you have slides that contain animations that
' make the printed slide difficult or impossible to read.
' Let's further suppose you plan to present certain slides
' but not print them.
' 1. Add the"NoPrint" suffix to any shapes that clutter
' the printed page.
' 2. Add the "NoPrint" suffix to slides you don't want to
' print.
' 3. Run this macro to hide shapes and slides.
' 4. Print the slides.
' 5. Optionally, run the ShowNoPrint() macro in preparation
' for presenting the slides.
ShowHideShapes "NoPrint", "R", False
ShowHideSlides "NoPrint", "R", False
End Sub
Sub ShowNoPrint()
' Unhide slides and shapes that were hidden
' to prevent them from being printed in handouts.
'
ShowHideShapes "NoPrint", "P", True
ShowHideSlides "NoPrint", "P", True
End Sub
Sub HideNoPressent()
' Hide objects you do NOT want to present on screen.
'
' Run this macro to hide all slides and shapes that
' end with the string "NoPresent".
'
' Usage. Assume you have slides that contain supporting material
' that you wish to provide as printed handouts but not show.
' You can manually hide those slides and objects of course. I
' prefer to use these macros.
' 1. Add the"NoPresent" suffix to any shapes that you want
' to print to handouts but not show on-screen.
' 2. Add the "NoPresent" suffix to slides you want to
' print but not display on screen, such as reference slides.
' 3. Run this macro to hide the "NoPresent" shapes and slides.
' 4. Present your slides.
' 5. Optionally, run the ShowNoPresent() macro in preparation
' for printing the slides.
'
ShowHideShapes "NoPressent", "R", False
ShowHideSlides "NoPressent", "R", False
End Sub
Sub ShowNoPresent()
' Unhide objects that were hidden to prevent them from
' being presented on screen.
'
ShowHideShapes "NoPressent", "P", True
ShowHideSlides "NoPressent", "P", True
End Sub
Sub PrepToPrintSlides()
' Unhide objects you want printed and
' hide objects you do NOT want printed.
ShowNoPresent
HideNoPrint
End Sub
Sub PrepToPresentSlides()
' Unhide objects you want presented and
' hide objects you do NOT want presented.
ShowNoPrint
HideNoPresent
End Sub
Sub DontPresentSlide()
Dim RetVal, sldName As String
sldName = Application.ActiveWindow.View.Slide.Name
If InStr(1, sldName, "NoPresent", vbBinaryCompare) = 0 Then
RetVal = RenameSlide(sldName, sldName & "-NoPresent")
End If
HideNoPresent
End Sub
Sub PresentSlide()
Dim RetVal, sldName As String, strStart As String, newName As String
'Remove the NoPresent suffix from the current slide.
'get slide name
sldName = Application.ActiveWindow.View.Slide.Name
'Unhide slide
ActivePresentation.Slides(sldName).SlideShowTransition.Hidden = msoFalse
'remove "-NoPresent" from slide name
Do
strStart = InStr(1, sldName, "-NoPresent")
If InStr(1, sldName, "-NoPresent") Then
newName = left(sldName, strStart - 1) & right(sldName, Len(sldName) - strStart - 9)
RetVal = RenameSlide(sldName, newName)
End If
sldName = Application.ActiveWindow.View.Slide.Name
Loop Until InStr(1, sldName, "-NoPresent") = 0
'remove "NoPresent" from slide name
Do
strStart = InStr(1, sldName, "NoPresent")
If InStr(1, sldName, "NoPresent") Then
newName = left(sldName, strStart - 1) & right(sldName, Len(sldName) - strStart - 8)
RetVal = RenameSlide(sldName, newName)
End If
sldName = Application.ActiveWindow.View.Slide.Name
Loop Until InStr(1, sldName, "NoPresent") = 0
End Sub
Sub DontPrintSlide()
Dim RetVal, sldName As String
sldName = Application.ActiveWindow.View.Slide.Name
If InStr(1, sldName, "NoPrint", vbBinaryCompare) = 0 Then
RetVal = RenameSlide(sldName, sldName & "-NoPrint")
End If
HideNoPrint
End Sub
Sub PrintSlide()
Dim RetVal, sldName As String, strStart As String, newName As String
'Remove the NoPrint suffix from the current slide.
'get slide name
sldName = Application.ActiveWindow.View.Slide.Name
'Unhide slide
ActivePresentation.Slides(sldName).SlideShowTransition.Hidden = msoFalse
'remove "-NoPrint" from slide name
Do
strStart = InStr(1, sldName, "-NoPrint")
If InStr(1, sldName, "-NoPrint") Then
newName = left(sldName, strStart - 1) & right(sldName, Len(sldName) - strStart - 7)
RetVal = RenameSlide(sldName, newName)
End If
sldName = Application.ActiveWindow.View.Slide.Name
Loop Until InStr(1, sldName, "-NoPrint") = 0
'remove "NoPrint" from slide name
Do
strStart = InStr(1, sldName, "NoPrint")
If InStr(1, sldName, "NoPrint") Then
newName = left(sldName, strStart - 1) & right(sldName, Len(sldName) - strStart - 6)
RetVal = RenameSlide(sldName, newName)
End If
sldName = Application.ActiveWindow.View.Slide.Name
Loop Until InStr(1, sldName, "NoPrint") = 0
End Sub
Sub HideAllCovers()
' Run this macro to hide all Covers.
ShowHideShapes "Cover", "L", False
End Sub
Sub ShowAllCovers()
' Run this macro to hide all Covers.
ShowHideShapes "Cover", "L", True
End Sub
Sub HideAllAnswers()
' Run this macro to hide all Covers.
ShowHideShapes "Answer", "L", False
End Sub
Sub ShowAllAnswers()
' Run this macro to hide all Covers.
ShowHideShapes "Answer", "L", True
End Sub
Sub HideAllQuestions()
' Run this macro to hide all Covers.
ShowHideShapes "Question", "L", False
End Sub
Sub ShowAllQuestions()
' Run this macro to hide all Covers.
ShowHideShapes "Question", "L", True
End Sub
Sub ShowAll()
' Run this macro to hide all shapes (Covers and Answers).
ShowAllQuestions
ShowAllAnswers
ShowAllCovers
ShowNoPrint
End Sub
Sub HideAll()
' Run this macro to hide all shapes (Covers and Answers).
HideAllQuestions
HideAllAnswers
HideAllCovers
HideNoPrint
End Sub
Enable the "Developer" tab in "File -> Options -> Customize Ribbon" (Details: https://www.addintools.com/documents/powerpoint/where-is-developer-tab.html)
In the developer tab, follow these steps and see the image below (in Portuguese, sorry)
Enter the developer tab
Select the target slide
If you don't have any active X control (buttons, textboxes, etc.) in the slide, add a dummy button from the developer tab
Select this button on the slide and click "properties" at the developer tab
At the top of the properties window, there is a combo box where you can select the slide instead of the button
Select the slide and see its programming properties, including name
I'm not certain that this will enable you to set the Slide.Name property because I'm not a VBA programmer, but anyway AFAIK the easiest way to name slides in PowerPoint 2010 is using Outline view.
If you position your mouse farthest left on a created slide, you can drag rightwards a kind of vertical slide sorter. At the top of that pane, you'll see two tabs: Slides and Outline.
Select Outline, you'll see each slide numbered and a grey grab button which allows you to reorder your slides. If you click to the right of that, you can type in whatever name you like, say Home.
In the main view pane, the slide will then have Home emblazoned across it. You can then either leave it there, or conceal it by altering the font colour to the background or by moving the text outside the presentation frame.
BTW You can use these names in hyperlinks.
used the Sub SplitFile() function to create individual slides from a deck of >100 slides. All went well!! But can anyone tell me what code do I use to rename the file automatically, assuming that each slide has a title in a text box? I want the slide title to be the file name for the new, individual slide created.
Here's the code I used to create individual slides (as individual files), thanks to whoever posted it online.
Sub SplitFile()
Dim lSlidesPerFile As Long
Dim lTotalSlides As Long
Dim oSourcePres As Presentation
Dim otargetPres As Presentation
Dim sFolder As String
Dim sExt As String
Dim sBaseName As String
Dim lCounter As Long
Dim lPresentationsCount As Long ' how many will we split it into
Dim x As Long
Dim lWindowStart As Long
Dim lWindowEnd As Long
Dim sSplitPresName As String
On Error GoTo ErrorHandler
Set oSourcePres = ActivePresentation
If Not oSourcePres.Saved Then
MsgBox "Please save your presentation then try again"
Exit Sub
End If
lSlidesPerFile = CLng(InputBox("How many slides per file?", "Split Presentation"))
lTotalSlides = oSourcePres.Slides.Count
sFolder = ActivePresentation.Path & "\"
sExt = Mid$(ActivePresentation.Name, InStr(ActivePresentation.Name, ".") + 1)
sBaseName = Mid$(ActivePresentation.Name, 1, InStr(ActivePresentation.Name, ".") - 1)
If (lTotalSlides / lSlidesPerFile) - (lTotalSlides \ lSlidesPerFile) > 0 Then
lPresentationsCount = lTotalSlides \ lSlidesPerFile + 1
Else
lPresentationsCount = lTotalSlides \ lSlidesPerFile
End If
If Not lTotalSlides > lSlidesPerFile Then
MsgBox "There are fewer than " & CStr(lSlidesPerFile) & " slides in this presentation."
Exit Sub
End If
For lCounter = 1 To lPresentationsCount
' which slides will we leave in the presentation?
lWindowEnd = lSlidesPerFile * lCounter
If lWindowEnd > oSourcePres.Slides.Count Then
' odd number of leftover slides in last presentation
lWindowEnd = oSourcePres.Slides.Count
lWindowStart = ((oSourcePres.Slides.Count \ lSlidesPerFile) * lSlidesPerFile) + 1
Else
lWindowStart = lWindowEnd - lSlidesPerFile + 1
End If
' Make a copy of the presentation and open it
For Each oSlide In ActiveWindow.Presentation.Slides
strTitles = strTitles _
& "Slide: " _
& CStr(oSlide.SlideIndex) & vbCrLf _
& oSlide.Shapes.Title.TextFrame.TextRange.Text _
& vbCrLf & vbCrLf
Next oSlide
On Error GoTo ErrorHandler
intFileNum = FreeFile
sSplitPresName = sFolder & sBaseName & _
"_" & CStr(lWindowStart) & "-" & CStr(lWindowEnd) & "." & sExt
oSourcePres.SaveCopyAs sSplitPresName, ppSaveAsDefault
Set otargetPres = Presentations.Open(sSplitPresName, , , True)
With otargetPres
For x = .Slides.Count To lWindowEnd + 1 Step -1
.Slides(x).Delete
Next
For x = lWindowStart - 1 To 1 Step -1
.Slides(x).Delete
Next
.Save
.Close
End With
Next ' lpresentationscount
NormalExit:
Exit Sub
ErrorHandler:
MsgBox "Error encountered"
Resume NormalExit
End Sub

How can I find the shape that is selected in group box in Excel?

I have a group box with option buttons in it and I need to find out which one of them is selected in VBA. I have been browsing MSDN for hours now and I can't find a solution.
There has to be a way to find the selected option button. Possibly find the group by name and for-each through each option button?
Here's what seems to be a working solution.
(Nod to KazJaw for Dim ... As OptionButton. this seems to be the key to get .GroupBox to work)
Function WhichOption(shpGroupBox As Shape) As OptionButton
Dim shp As OptionButton
Dim shpOptionGB As GroupBox
Dim gb As GroupBox
If shpGroupBox.FormControlType <> xlGroupBox Then Exit Function
Set gb = shpGroupBox.DrawingObject
For Each shp In shpGroupBox.Parent.OptionButtons
Set shpOptionGB = shp.GroupBox
If Not shpOptionGB Is Nothing Then
If shpOptionGB.Name = gb.Name Then
If shp.Value = 1 Then
Set WhichOption = shp
Exit Function
End If
End If
End If
Next
End Function
Use it like this
Sub test()
Dim shpOpt As OptionButton
Set shpOpt = WhichOption(Worksheets("Sheet1").Shapes("Group Box 1"))
Debug.Print shpOpt.Name
End Sub
If you really need to check OptionButton which are grouped (Grouped in the way we group any type of shape) you could go with this code:
Sub Grouped_into_UnitType()
Dim i!
'grouped into 'UnitType' Shape
For i = 1 To ActiveSheet.Shapes("UnitType").GroupItems.Count
With ActiveSheet.Shapes("UnitType").GroupItems(i).ControlFormat
If .Value = 1 Then
MsgBox "Chosen item: " & i
End If
End With
Next i
End Sub
Edit having in mind the following picture the code above will solve the problem if we have Option Buttons which are group in the way we group any Shapes placed in the sheet.
The code under the picture will find which option button is selected if they are located within GroupBox. Code check the name of the group in which OptionButton is located.
Important Note! the code below didn't work until I switched Excel off and run it again.
Sub Grouped_into_GroupBox_UnitType()
Dim OB As OptionButton
For Each OB In ActiveSheet.OptionButtons
'check if grouped into 'UnitType' Shape
If OB.GroupBox.Name = "UnitType" Then
If OB.Value = 1 Then
MsgBox "Chosen item: " & OB.Name & _
vbNewLine & _
"Alt text: " & OB.ShapeRange.AlternativeText
End If
End If
Next
End Sub
Lets say you have two standard option buttons:
To check if its "on" use:
Dim opt As Shape
Set opt = Worksheets("Sheet1").Shapes("Option Button 1")
If opt.ControlFormat.Value = xlOn Then
Debug.Print "option is ""on"" value of 1"
Else
Debug.Print "option is ""off"" value of -4146"
End If
To get its alternat text use:
Debug.Print "Alternate Text is: " & opt.AlternativeText
For a large amount of options the "FormControlType" property can be used:
Dim s as Shape
For Each s In Worksheets("Sheet1").Shapes
If s.FormControlType = xlOptionButton Then
If s.ControlFormat.Value = xlOn Then
Debug.Print "option is ""on"" value of 1"
Else
Debug.Print "option is ""off"" value of -4146"
End If
Debug.Print "Alternate Text is: " & s.AlternativeText
End If
Next
If you wanted a particular group:
Dim s As Shape, o
For Each s In Worksheets("Sheet1").Shapes
If s.FormControlType = xlOptionButton Then
Set o = s.OLEFormat.Object
If o.GroupBox.Name = "Group Box 3" Then
If s.ControlFormat.Value = xlOn Then
Debug.Print "Option is ""on"" value of 1"
Else
Debug.Print "Option is ""off"" value of -4146"
End If
Debug.Print "Alternate Text is: " & s.AlternativeText
Debug.Print "Group: " & o.GroupBox.Name
End If
Set o = Nothing
End If
Next

Resources