I have a PowerPoint which begins with a a media file automatically playing. The first slide is programmed to transition after 20 seconds, all the while the music keeps playing. I would like for it to keep playing for the duration of the slideshow, but fade to a lower volume once the second slide appears and remain that way for the rest of the presentation. I've looked at this Powerpoint change sound effect volume in macro but it doesn't seem to satisfy my needs.
I tried this:
Sub fadeVolSlideChange(ByVal ShowPos As SlideShowWindow)
Dim ShowPos As Integer
Dim bkgMusic As Shape
Dim Step As Long
ShowPos = ShowPos.View.CurrentShowPosition
Set bkgMusic = ActiveWindow.Selection.ShapeRange(1)
If ShowPos = 2 Then
Set Step = 0.05
For i = 1 To 0.5
With bkgMusic.MediaFormat
.Volume = i
.Muted = False
End With
i = i - Step
Application.Wait (Now + 0.0000025)
Next i
End If
End Sub
With no luck. Thoughts?
Here's the latest edit (still no luck getting it to work):
Sub OnSlideShowPageChange()
Dim i As Integer
Dim bkgMusic As Shape
Dim bkgVol As Long
Dim inc As Long
i = ActivePresentation.SlideShowWindow.View.CurrentShowPosition
Set bkgMusic = ActivePresentation.Slides(1).Shapes("Opening Theme")
If i = 1 Then
'Do nothing
ElseIf i <> 1 Then
inc = 0.05
For bkgVol = 1 To 0.1
With bkgMusic.MediaFormat
.Volume = bkgVol
.Muted = False
End With
bkgVol = bkgVol - inc
Application.Wait (Now + TimeValue("0:00:01"))
Next bkgVol
End If
End Sub
This almost works, but PPT shoots us down in the end. After it runs, the volume of the sound file has been reduced, but it doesn't change during the slideshow.
Sub OnSlideShowPageChange()
Dim i As Integer
Dim bkgMusic As Shape
' This needs to be single, not Long
Dim bkgVol As Single
Dim inc As Long
Dim lCounter As Long
i = ActivePresentation.SlideShowWindow.View.CurrentShowPosition
Set bkgMusic = ActivePresentation.Slides(1).Shapes("Opening Theme")
If i = 2 Then
inc = 0.05
' Changing the value by fractions so must be a single, not a long, and
' decreasing the value requires Step and a negative number:
For bkgVol = 1 To 0.1 Step -0.1
With bkgMusic.MediaFormat
.Volume = bkgVol
.Muted = False
End With
'bkgVol = bkgVol - inc
' Application.Wait is not supported in PPT
'Application.Wait (Now + TimeValue("0:00:01"))
WaitForIt
SlideShowWindows(1).View.GotoSlide (2)
Next bkgVol
End If
End Sub
Sub WaitForIt()
Dim x As Long
For x = 1 To 1000000
DoEvents
Next
'MsgBox "Done waiting"
End Sub
Related
How do I group all objects (or "shapes"?) on a slide and resize that group?
Subsequently the "big" group should be ungrouped.
My attempt fails with "function expected":
Sub Group_And_Resize()
Dim Sld As Slide
With Sld.Shapes
With .SelectAll.Group //Error here
.Width = 907
End With
End With
End Sub
By manual experimentation, I learned that some objects (or "shapes"?) cannot be added to a group, such as slide numbers which are automatically generated. Is there any possibility to exclude those from the selection?
If you want to group the shapes together first and then set the overall width to 907, you can use this code:
Sub Group_And_Resize()
Dim Sld As Slide, a As Variant, i As Integer
Set Sld = ActivePresentation.Slides(1) ' your slide
ReDim a(1 To Sld.Shapes.Count)
For i = LBound(a) To UBound(a)
a(i) = Sld.Shapes(i).Name
Next
Sld.Shapes.Range(a).Group.Width = 907
End Sub
If you want to make the width of each of the shapes on the slide = 907, you can use the following code:
Sub Group_And_Resize()
Dim Sld As Slide
Set Sld = ActivePresentation.Slides(1) ' your slide
Sld.Shapes.Range.Width = 907
End Sub
This is based on Алексей Р's answer but solves a few problems and also is more generic. It allows calling the routine on any slide in the active presentation and setting the width to any desired value. See comments for more details.
Sub Test()
With ActivePresentation
Call Group_And_Resize(.Slides(1), 200)
End With
End Sub
Sub Group_And_Resize(Sld As Slide, sngWidth As Single)
Dim a As Variant, i As Long ' Array indices are longs, not integers
Dim oGroup As Shape
' Call NonPlaceholderShapeCount to get number of
' shapes that are not placeholders, since placeholders
' cannot be grouped. Use that to ReDim the array:
ReDim a(1 To NonPlaceholderShapeCount(Sld))
For i = LBound(a) To UBound(a)
' Again, make sure we don't try to group placeholders
If Not Sld.Shapes(i).Type = msoPlaceholder Then
a(i) = Sld.Shapes(i).Name
End If
Next
' Get a reference to the new group
' since we need to set several properties on it
Set oGroup = Sld.Shapes.Range(a).Group
' This ensures that the group (and its shapes)
' aren't distorted:
oGroup.LockAspectRatio = True
' and finally, set the width
oGroup.Width = sngWidth
End Sub
Function NonPlaceholderShapeCount(Sld As Slide) As Long
' Returns the number of non-placeholder shapes on Sld
Dim x As Long
Dim lCount As Long
With Sld
For x = 1 To .Shapes.Count
If Not .Shapes(x).Type = msoPlaceholder Then
lCount = lCount + 1
End If
Next
End With
NonPlaceholderShapeCount = lCount
End Function
I am looking for a way to kind of re-engineer the VBA code I need to create a certain visual in PowerPoint.
For example purposes let's say, I want to create code to create this:
Right now I have wrote the following VBA code that allows you highlight the shapes used in the powerpoint:
Sub ListAllShapes()
Dim curSlide As Slide
Dim curShape As Shape
For Each curSlide In ActivePresentation.Slides
Debug.Print curSlide.SlideNumber
For Each curShape In curSlide.Shapes
MsgBox curShape.Name
Next curShape
Next curSlide
End Sub
If I run this with my example I get the following output:
Autoshape 7
However when I then lookup the Shape.name here: https://learn.microsoft.com/en-us/office/vba/api/office.msoautoshapetype I see that Autoshpape 7 is msoShapeIsoscelesTriangle. If I then insert the following code:
Sub InsertShape()
Set myDocument = ActivePresentation.Slides(1)
myDocument.Shapes.AddShape Type:=msoShapeIsoscelesTriangle, _
Left:=50, Top:=50, Width:=100, Height:=200
End Sub
I get a different graph, any thoughts on where I am going wrong?
The autoshape Name is not the autoshape Type. They're 2 different properties. Here's a macro to add all the shapes to a slide. Then look up the number on this page to get the VBA AutoshapeType name: MsoAutoShapeType enumeration
Sub MakeShapes()
Dim T As Long, L As Long
Dim oShape As Shape, oText As Shape
T = 0
L = 0
x = 1
For y = 1 To 15
For Z = 1 To 26
On Error GoTo NoShape
Set oShape = ActiveWindow.Selection.SlideRange.Shapes.AddShape(Type:=x, Left:=L, Top:=T, Width:=30, Height:=30)
On Error GoTo -1
Set oText = ActiveWindow.Selection.SlideRange.Shapes.AddTextbox(Orientation:=msoTextOrientationHorizontal, Left:=L, Top:=T + 36, Width:=36, Height:=18)
With oText.TextFrame2.TextRange
.Text = oShape.AutoShapeType
.Font.Size = 10
End With
Set oShape = Nothing
Set oText = Nothing
L = L + 36
NoShape:
x = x + 1
If x = 184 Then Exit Sub
Next Z
L = 0
T = T + 71
Next y
End Sub
I think this is less complicated than I am making it but being a novice with VBA I haven't been able to find the answer after a couple days of googling and playing with different code.
I have a macro that:
Opens a file in whatever folder path is named
Searches for specific text in the file to find the start of a specific section, i.e. A100
Finds the end of this section, i.e. A110 (variable in length depending on the file)
Copy and pastes the cells in this range to another specific range, i.e. O1:O10
Populates a userform with a checkbox for each cell in this new variable length range
I now need the user to click which checkboxes they want and then the captions for these checkboxes to be saved as an array that I can then call on later in the macro.
i.e. if they clicked dog, cat, and bird from the checkboxes, the output would be dog,cat,bird
Because of the variable length of the range and number of checkboxes, I can't figure out how to have it loop through each one and concatenate the correct values.
I think there is probably a way to cut out the copy pasting of the values to populate the userform with also, but this was the only way I could figure out that part given the variable length of the range.
Below is the code that generates the userform after the range has been copy pasted.
Private Sub UserForm_Initialize()
Dim curColumn As Long
Dim i As Long
Dim codeRow As Long
Dim chkBox As msforms.CheckBox
curColumn = 15
codeRow = Range("O20").End(xlUp).Row
For i = 1 To codeRow
Set chkBox = Me.Controls.Add("Forms.CheckBox.1", "CheckBox_" & i)
chkBox.Caption = Worksheets(1).Cells(i, curColumn).Value
chkBox.Left = 5
chkBox.Top = 5 + ((i - 1) * 20)
Next i
End Sub
Insert moduel code.
Public vCheck()
Bellows in form code.
Private Sub UserForm_Initialize()
Dim curColumn As Long
Dim i As Long
Dim codeRow As Long
Dim chkBox As msforms.CheckBox
curColumn = 15
codeRow = Range("O20").End(xlUp).Row
ReDim vCheck(0)
For i = 1 To codeRow
Set chkBox = Me.Controls.Add("Forms.CheckBox.1", "CheckBox_" & i)
ReDim Preserve vCheck(1 to i)
vCheck(i) = Worksheets(1).Cells(i, curColumn).Value
chkBox.Caption = vCheck(i)
chkBox.Left = 5
chkBox.Top = 5 + ((i - 1) * 20)
Next i
End Sub
Listbox was the way to go. Here is the updated code for others looking for help with the same issue:
Private Sub UserForm_Initialize()
Dim myLBox As msforms.ListBox
Dim codeRow As Long
codeRow = Range("O20").End(xlUp).Row
ListBox1.RowSource = "O1:O" & codeRow
End Sub
Private Sub CommandButton1_Click()
Dim rRange As Range
Dim lCount As Long 'Counter
On Error GoTo ErrorHandle
Set rRange = Range("P1")
With ListBox1
For lCount = 0 To .ListCount - 1
If .Selected(lCount) = True Then
rRange.Offset(lCount, 0).Value = .List(lCount)
End If
Next
End With
BeforeExit:
Set rRange = Nothing
Unload Me
Exit Sub
ErrorHandle:
MsgBox Err.Description
Resume BeforeExit
End Sub
Basically I want to transform the text in between the tags into bold. This text will always be in the comments. The current code doesnt do anything.
I am not really sure if this code makes any sense at all, but I usually use VBA for Excel and word seems to be a bit trickier.
Sub Bold()
Dim eCom As Comment
Dim iFound As Integer
Dim rbold As Range
Dim iDot As Integer
Dim flag As Boolean
Dim aDoc As Document
Set aDoc = ActiveDocument
flag = True
Application.ScreenUpdating = False
For Each eCom In ActiveDocument.Comments
iFound = InStr(eCom.Range.Text, "<strong>")
iDot = 0
If iFound > 0 Then
iDot = InStrRev(eCom.Range, "</") - iFound + 1
Set rbold = aDoc.Range(Start:=eCom.Range.Start + iFound, End:=eCom.Range.Start + InStrRev(eCom.Range, "<"))
rbold.Select
Selection.Font.Bold = wdToggle
End If
Next eCom
Application.ScreenUpdating = True
End Sub
There are a few problems here. First, it appears that the Comment Ranges do not use the same numbering as the document ranges. So
Set rbold = aDoc.Range(Start:=eCom.Range.Start + iFound, End:=eCom.Range.Start + InStrRev(eCom.Range, "<"))
is not actually the range in the comments, it is instead a range in the document starting with the place in the comment that has the strong html tag.
Second, even if this was working, it would start the bolding in the wrong place, starting with "strong>"
Third, there's no reason to select the range, just set it to bold.
This code will do what you want (I commented out a line as I couldn't figure out what it was supposed to do):
Sub Bold()
Dim eCom As Comment
Dim iFound As Integer
Dim rbold As Range
Dim iDot As Integer
Dim flag As Boolean
Dim aDoc As Document
Dim newCom As Comment
Set aDoc = ActiveDocument
flag = True
Application.ScreenUpdating = False
For Each eCom In ActiveDocument.Comments
iFound = InStr(eCom.Range.Text, "<strong>")
iDot = 0
If iFound > 0 Then
'iDot = InStrRev(eCom.Range, "</") - iFound + 1
Set rbold = eCom.Range
rbold.MoveEnd Unit:=wdCharacter, Count:=-(Len(rbold) - InStrRev(rbold, "</") + 1)
rbold.MoveStart Unit:=wdCharacter, Count:=iFound + Len("<strong>") - 1
rbold.Bold = True
End If
Next eCom
Application.ScreenUpdating = True
End Sub
I've created a couple of macros, one that creates a shape in a determined row with a macro assigned and the macro assigned that deletes the row when the shape is clicked on. The macro that adds the shape is activated by another macro that populates the last empty row of my table with relevant data and the shape to delete the row in question, but I'll leave that one out of it.
So the macros should add the shape to the row being populated and, once the shape gets clicked, it gets the shape's row and delete it.
Here are the macros:
--The one that creates the shape:
Sub addDelBt(ByVal Target As Range)
Dim rw As Long
rw = Target.Row
Dim shp As Object
Set shp = Plan1.Shapes.AddShape(msoShapeMathMultiply, Target.Left + 2.5, Target.Top + 2.5, Target.RowHeight - 2, Target.RowHeight - 2)
'shp.Width = 11
'shp.Height = 11
shp.Fill.ForeColor.RGB = RGB(192, 0, 0)
shp.Fill.BackColor.RGB = RGB(170, 170, 170)
shp.Line.Visible = msoFalse
With shp.Shadow
.ForeColor.RGB = RGB(0, 0, 128)
.OffsetX = 0.5
.OffsetY = 2
.Transparency = 0.5
.Visible = True
End With
With shp.ThreeD
.BevelTopType = msoBevelCircle
.BevelTopInset = 15
.BevelTopDepth = 3
.PresetLighting = msoLightRigBalanced
.LightAngle = 145
.Visible = True
End With
shp.Name = "btnDel" & rw
shp.OnAction = "delRow"
End Sub
--The action of the shape:
Sub delRow()
Plan1.Unprotect ("password")
Dim shp As Object
Set shp = Plan1.Shapes(Application.Caller)
Dim rw As Long
rw = shp.TopLeftCell.Row
Dim doc As String
doc = Plan1.Cells(rw, 2).Value
Dim msgResult As VbMsgBoxResult
msgResult = MsgBox("Você deseja deletar o documento " + doc + "?", vbYesNo)
If msgResult = vbYes Then
Plan1.Rows(rw).EntireRow.Delete
End If
Plan1.Protect ("password")
End Sub
The problem is that some times (I haven't found a pattern yet) the button from one row will delete another upper row. I can't find out why, can you see it?
Cannot see why this would happen. Everything looks alright with the code.
Once I also wanted to make very similar functionality and realized that using many dynamically created buttons is not the best option (at least not for me).
I have abandoned the idea of shapes and make similar functionality with Worksheet_SelectionChange event. With some nice formating you can make the cells in the column looks like some Delete Buttons. The Worksheet_SelectionChange event (for cells) works like OnClick event (for buttons / OnAction for shapes).
Example:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo ErrHandler
Application.EnableEvents = False
If Target.Column = 5 Then 'If the clicked cell is in the column 5
Dim doc As String
doc = Cells(Target.row, 2).Value
Dim msgResult As VbMsgBoxResult
msgResult = MsgBox("Voce^ deseja deletar o documento " + doc + "?", vbYesNo)
If msgResult = vbYes Then
Plan1.Rows(Target.Row).EntireRow.Delete
End If
End If
ErrHandler:
Application.EnableEvents = True
End Sub
The ErrorHandler with Disabling events is important to prevent the row.delete event to trigger another Worksheet_SelectionChange event.