VBA to Delete and Import Pictures in specific Column - excel

I am getting a Runtime error 1004:Unable to get the TopLeft Cell Property of the Picture class. When I run this code back to back. The error is inconsistent but usually happens when I run the code more than once.
Sub InsertMultipleRGPictures()
Dim Pictures() As Variant
Dim PictureFormat As String
Dim PicRng As Range
Dim PicShape As Shape
Dim xPicRg As Range
Dim xPic As Picture
Dim xRg As Range
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
ActiveSheet.DisplayPageBreaks = False
Application.Calculation = xlCalculationManual
Sheets("Auto Post").Range("AZ3:AZ9").Select
Columns("AZ:AZ").ColumnWidth = 57
Set xRg = Range("AZ3:AZ14")
For Each xPic In ActiveSheet.Pictures
Set xPicRg = Range(xPic.TopLeftCell.Address & ":" & xPic.BottomRightCell.Address)
If Not Intersect(xRg, xPicRg) Is Nothing Then xPic.Delete
Next
On Error Resume Next
PictureFormat = "Test Files (*.png; *.jpeg), *.png; *.jpeg"
Pictures = Application.GetOpenFilename(PictureFormat, MultiSelect:=True)
PicColIndex = Application.ActiveCell.Column
If IsArray(Pictures) Then
PicRowIndex = Application.ActiveCell.Row
For lLoop = LBound(Pictures) To UBound(Pictures)
Set PicRng = Cells(PicRowIndex, PicColIndex)
With ActiveSheet.Shapes.AddPicture(Pictures(lLoop), msoFalse, msoCTrue, PicRng.Left, PicRng.Top, -1, -1)
.LockAspectRatio = msoTrue
.Height = 250 * 3 / 4
Rng.RowHeight = .Height
.Top = PicRng.Top + (PicRng.Height - .Height) / 2
.Left = PicRng.Left + (PicRng.Width - .Width) / 2
Rng.ColumnWidth = .Width / Rng.Width * Rng.ColumnWidth
Rng.ColumnWidth = .Width / Rng.Width * Rng.ColumnWidth
Rng.ColumnWidth = .Width / Rng.Width * Rng.ColumnWidth
End With
PicRowIndex = PicRowIndex + 1
Next
MsgBox "Import Complete- Pictures"
End If
Columns("AZ:AZ").ColumnWidth = 52
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.Calculation = xlCalculationAutomatic
End Sub
Is there something I am missing here?

Related

How can I edit VBA code to center the imported pictures in their cells

I am relatively new to VBA so perhaps there is a simple solution to this? I am using the code below to import multiple pictures into a column. However, I need to center the pictures in their cells too. Is there a way to alter the current code? Which works great! (except the pictures are not centered).
Thank you
Sub InsertMultipleRGPictures()
Dim Pictures() As Variant
Dim PictureFormat As String
Dim PicRng As Range
Dim PicShape As Shape
Dim xPicRg As Range
Dim xPic As Picture
Dim xRg As Range
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
ActiveSheet.DisplayPageBreaks = False
Application.Calculation = xlCalculationManual
Sheets("Auto Post").Range("AZ3:AZ9").Select
Columns("AZ:AZ").ColumnWidth = 57
Set xRg = Range("AZ3:AZ14")
For Each xPic In ActiveSheet.Pictures
Set xPicRg = Range(xPic.TopLeftCell.Address & ":" & xPic.BottomRightCell.Address)
If Not Intersect(xRg, xPicRg) Is Nothing Then xPic.Delete
Next
On Error Resume Next
PictureFormat = "Test Files (*.png; *.jpeg), *.png; *.jpeg"
Pictures = Application.GetOpenFilename(PictureFormat, MultiSelect:=True)
PicColIndex = Application.ActiveCell.Column
If IsArray(Pictures) Then
PicRowIndex = Application.ActiveCell.Row
For lLoop = LBound(Pictures) To UBound(Pictures)
Set PicRng = Cells(PicRowIndex, PicColIndex)
With ActiveSheet.Shapes.AddPicture(Pictures(lLoop), msoFalse, msoCTrue, msoFalse, msoCTrue, PicRng.Left, PicRng.Top, -1, -1)
.LockAspectRatio = msoTrue
.Height = 250 * 3 / 4
Rng.RowHeight = .Height
Rng.ColumnWidth = .Width / Rng.Width * Rng.ColumnWidth
Rng.ColumnWidth = .Width / Rng.Width * Rng.ColumnWidth
Rng.ColumnWidth = .Width / Rng.Width * Rng.ColumnWidth
End With
PicRowIndex = PicRowIndex + 1
Next
MsgBox "Import Complete- Pictures"
End If
Columns("AZ:AZ").ColumnWidth = 50
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.Calculation = xlCalculationAutomatic
End Sub

Excel VBA - Creating buttons dynamically with code assigned

I am trying to create some buttons dynamically, and assign code to them.
The following code works
Dim MyR As Range, MyB As OLEObject
Dim MyR_T As Long, MyR_L As Long
Set MyR = Cells(i + 1, 11) 'just an example - you get that from your own script
MyR_T = MyR.Top 'capture positions
MyR_L = MyR.Left '...
'create button
Set MyB = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False)
'set main button properties
With MyB
.Name = "MyPrecodedButton" 'important - code must exist ... see below
.Object.Caption = "MyCaption"
.Top = MyR_T
.Left = MyR_L
.Width = 50
.Height = 18
.Placement = xlMoveAndSize
.PrintObject = True 'or false as per your taste
End With
It creates the buttons within my loop. However, I want to assign something to the on click, so I use the following code
Dim MyR As Range, MyB As OLEObject
Dim MyR_T As Long, MyR_L As Long
Set MyR = Cells(i + 1, 11) 'just an example - you get that from your own script
MyR_T = MyR.Top 'capture positions
MyR_L = MyR.Left '...
'create button
Set MyB = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False)
'set main button properties
With MyB
.OnAction = "interpHere"
.Name = "MyPrecodedButton" 'important - code must exist ... see below
.Object.Caption = "MyCaption"
.Top = MyR_T
.Left = MyR_L
.Width = 50
.Height = 18
.Placement = xlMoveAndSize
.PrintObject = True 'or false as per your taste
End With
Sub interpHere()
MsgBox "hi"
End Sub
I have basically added .OnAction = "interpHere" but when I run it, I get an error, unable to set the onaction property.
Where am I going wrong?
try this code
Sub CreateButtons()
Dim btn As Button
ActiveSheet.Buttons.Delete
Dim t As Range
For i = 2 To 6 Step 2
Set t = ActiveSheet.Cells(i, 3)
Set btn = ActiveSheet.Buttons.Add(t.Left, t.Top, t.Width, t.Height)
With btn
.OnAction = "interpHere"
.Caption = "Btn " & i
.Name = "Btn" & i
End With
Next i
End Sub
Sub interpHere()
MsgBox "hi"
End Sub

Optimizing VBA macro for PowerPoint

I am creating a powerpoint from the VBA editor and when I create the individual slides, it works great. However, when I try to create them all at once, PowerPoint crashes. I clear memory by setting Application.CutCopyMode=False at the end of each slide and have Application.Wait for 7 seconds.
My powerpoint is going to be about 25 slides and its already crashing past slide 7. Usually it crashes when I am formatting. I have added in the 3 basic layouts for each Macro I use and slides 8 and 9 of where it crashes.
The First Macro I use copies a slide from last presentation and
pastes to new powerpoint.
The Second Pastes a Table
The Third Pastes a Table, Chart, and Picture (only slide with Picture, otherwise slides of this type paste a table and chart only).
Code:
Sub CreateNewPresentation()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim ppApp As PowerPoint.Application
Dim ppPres As PowerPoint.Presentation
Dim slidesCount As Long
If ppApp Is Nothing Then
Set ppApp = New PowerPoint.Application
End If
Set ppPres = ppApp.Presentations.Add
ppPres.SaveAs "FileName"
ppApp.Visible = True
slidesCount = ppPres.Slides.Count
Call create_Slide1(slidesCount, ppPres, ppApp)
slidesCount = ppPres.Slides.Count
Application.CutCopyMode = False
Call create_Slide2(slidesCount, ppPres)
slidesCount = ppPres.Slides.Count
Application.CutCopyMode = False
Call create_Slide3(slidesCount, ppPres)
slidesCount = ppPres.Slides.Count
Application.CutCopyMode = False
ppPres.Save
ppPres.Close
Call create_Slide8(slidesCount, ppPres)
slidesCount = ppPres.Slides.Count
Application.CutCopyMode = False
Call create_Slide9(slidesCount, ppPres)
slidesCount = ppPres.Slides.Count
Application.CutCopyMode = False
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
sub Create_Slide1(sldNum As Long, ppPrez As PowerPoint.Presentation, ppt As PowerPoint.Application)
Dim myFile As String
Dim ppSlide As PowerPoint.Slide
Dim objPres As PowerPoint.Presentation
Set ppSlide = ppPrez.Slides.Add(sldNum + 1, ppLayoutBlank)
ppPrez.PageSetup.SlideSize = ppSlideSizeLetterPaper
myFile:"File name and path....."
Set objPres=ppt.Presentations.Open(myFile)
objPres.Slides(1).Copy
ppPrez.Slides.Paste Index:=sldNum+1
objPres.Close
ppPrez. Slides(sldNum+2).Delete
End Sub
Sub create_Slide2(sldNum As Long, ppPrez As PowerPoint.Presentation)
Dim ppSlide As PowerPoint.Slide
Set ppSlide = ppPrez.Slides.Add(sldNum + 1, ppLayoutBlank)
ppPrez.PageSetup.SlideSize = ppSlideSizeLetterPaper
ppSlide.Select
ThisWorkbook.Worksheets("Sheet2").Activate
ActiveSheet.Range(Cells(3, 2), Cells(27, 11)).Copy
ppSlide.Shapes.Paste.Select
With ppSlide.Shapes(1)
.Top = ppPrez.PageSetup.SlideHeight / 20
.Left = ppPrez.PageSetup.SlideWidth / 20
.Height = 17 * (ppPrez.PageSetup.SlideHeight) / 20
.Width = 9 * (ppPrez.PageSetup.SlideWidth / 10)
End With
End Sub
sub create_Slide3(sldNum As Long, ppPrez As PowerPoint.Presentation)
Dim ppSlide As PowerPoint.Slide
Dim ppTextBox As PowerPoint.Shape
Set ppSlide = ppPrez.Slides.Add(sldNum + 1, ppLayoutBlank)
ppPrez.PageSetup.SlideSize = ppSlideSizeLetterPaper
ppSlide.Select
Set ppTextBox = ppSlide.Shapes.AddTextbox( _
msoTextOrientationHorizontal, 0, 15, ppPrez.PageSetup.SlideWidth, 60)
With ppTextBox.TextFrame
.TextRange.Text = "Slide3"
.TextRange.ParagraphFormat.Alignment = ppAlignCenter
.TextRange.Font.Size = 20
.TextRange.Font.Name = "Calibri"
.VerticalAnchor = msoAnchorMiddle
End With
ThisWorkbook.Sheets("Sheet3").Activate
ActiveSheet.Range(Cells(17, 10), Cells(19, 19)).Copy
ppSlide.Shapes.Paste.Select
With ppSlide.Shapes(2)
.Width = (6 / 10) * ppPrez.PageSetup.SlideWidth
.Left = (1 / 40) * ppPrez.PageSetup.SlideWidth
.Top = (5 / 8) * ppPrez.PageSetup.SlideHeight
End With
Sheets("Sheet3").Shapes("Shape1").CopyPicture
ppSlide.Shapes.Paste
ppSlide.Shapes(4).Height = 850
ppSlide.Shapes(4).Width = 275
ppSlide.Shapes(4).Left = (6.2 / 10) * ppPrez.PageSetup.SlideWidth
ppSlide.Shapes(4).Top = (1 / 10) * ppPrez.PageSetup.SlideHeight
End sub
sub create_Slide8(sldNum As Long, ppPrez As PowerPoint.Presentation)
Dim ppSlide As PowerPoint.Slide
Set ppSlide = ppPrez.Slides.Add(sldNum + 1, ppLayoutBlank)
ppPrez.PageSetup.SlideSize = ppSlideSizeLetterPaper
ppSlide.Select
ThisWorkbook.Sheets("roll").Activate
ActiveSheet.ChartObjects("35").Activate
ActiveChart.ChartArea.Copy
ppSlide.Shapes.Paste.Select
With ppSlide.Shapes(1)
.Left = 1 * (ppPrez.PageSetup.SlideWidth / 20)
.Height = _
ppPrez.PageSetup.SlideHeight / 2
.Width = _
9 * (ppPrez.PageSetup.SlideWidth / 10)
.Top = 0
End With
Application.Wait (Now + TimeValue("0:00:03"))
Application.CutCopyMode = False
MsgBox ("done")
ActiveSheet.ChartObjects("40").Activate
ActiveChart.ChartArea.Copy
ppSlide.Shapes.Paste.Select
With ppSlide.Shapes(2)
.Left = 1 * (ppPrez.PageSetup.SlideWidth / 20)
.Height = _
ppPrez.PageSetup.SlideHeight / 2
.Width = _
9 * (ppPrez.PageSetup.SlideWidth / 10)
.Top = _
ppPrez.PageSetup.SlideHeight / 2
End With
Application.Wait (Now + TimeValue("0:00:07"))
MsgBox ("done")
End Sub
sub create_Slide9(sldNum As Long, ppPrez As PowerPoint.Presentation, ppt As PowerPoint.Application)
Dim ppSlide As PowerPoint.Slide
Dim objPres As PowerPoint.Presentation
Set ppSlide = ppPrez.Slides.Add(sldNum + 1, ppLayoutBlank)
ppPrez.PageSetup.SlideSize = ppSlideSizeLetterPaper
ppSlide.Select
myFile = "File Path....same as above"
Set objPres = ppt.Presentations.Open(myFile)
objPres.Slides(8).Copy
ppPrez.Slides.Paste Index:=sldNum + 1 'sometimes it fails here too because of a paste issue (Either vba doesn't like method or no where to paste too)
objPres.Close
ppPrez.Slides(sldNum + 2).Delete
MsgBox ("done")
Application.Wait (Now + TimeValue("0:00:07"))
End Sub
I'm not certain, but I think that message boxes are blocking. Execution is stopped until it's dealt with, so wont give your code time to recover.
The following code should work but I don't really like it. Its the best I can do without modifying some of your other functioning code too.
Hopefully you might see what the idea behind the code is and can improve on it.
Ideally it would use a loop and be inside your CreateNewPresentation sub instead of a recursive function.
You could potentially just replace the messageboxes in your code with Sleep 100 and not use my code (after copying the Sleep Declaration to your module)
PowerPoint doesn't have a ScreenUpdating type deal and some commands do take a while to complete. Using Sleep between each slide may help, it might not. It might be worth putting some Sleep's between some function calls in your create_slideN macros. I've never automated Powerpoint so dont know how it works.
Private Declare Sub Sleep Lib "kernel32" (ByVal lngMilliSeconds As Long)
Public CreationIndex As Integer
Dim ppApp As PowerPoint.Application
Dim ppPres As PowerPoint.Presentation
Dim slideCount As Integer
Sub CreateNewPresentation()
Application.ScreenUpdating = False
Application.EnableEvents = False
If ppApp Is Nothing Then
Set ppApp = New PowerPoint.Application
End If
Set ppPres = ppApp.Presentations.Add
ppPres.SaveAs "FileName"
ppApp.Visible = True
CreationIndex = 1
Create CreationIndex ' start the ball rolling...
End Sub
Sub Create(i As Integer)
slidesCount = ppPres.Slides.Count
Select Case i
Case 1
Call Create_Slide1(slidesCount, ppPres, ppApp)
Case 2
Call create_Slide2(slidesCount, ppPres)
Case 3
Call create_Slide3(slidesCount, ppPres)
Case Else
MsgBox "Complete or Broken...", vbOKOnly
Exit Sub
End Select
Application.CutCopyMode = False
Sleep 200 ' wait for a bit...
CreationIndex = CreationIndex + 1
Create CreationIndex
End Sub

Change Excel comment Shape Picture File format

Hi I want to change the file format of the comment shape picture (Fill) and as well as to a standard height and width. Tried the following code but it is keep on throwing Application defined error "Run time error 1004". Please guide me to correct this one.
Sub ReduceImageSize()
Dim cmt As Comment
Dim MyChart As Chart
Dim MyPicture As String
Dim pic As Object
Dim PicWidth As Long
Dim PicHeight As Long
Dim num As Long
num = 1
Application.ScreenUpdating = False
For Each cmt In ActiveSheet.Comments
With cmt
.Visible = True
.Shape.CopyPicture Appearance:=xlScreen, Format:=xlPicture
.Visible = False
PicHeight = .Shape.Height
PicWidth = .Shape.Width
Set MyChart = Charts.Add(0, 0, 100, 100).Chart
With MyChart.Parent
.Width = PicWidth
.Height = PicHeight
.ChartArea.Select
.Paste
.ChartObjects(1).Chart.Export Filename:="C:\Temp\MyPic " & num & ".jpg", FilterName:="jpg"
End With
.Shape.Fill.UserPicture PictureFile:="C:\Temp\MyPic " & num - 1 & ".jpg"
num = num + 1
ActiveChart.Delete
End With
Next
Application.ScreenUpdating = True
End Sub
Try changing Format:=xlPicture to Format:=xlBitmap because jpg is a bitmap type image. See the following from MS. https://msdn.microsoft.com/en-us/library/office/ff837557.aspx
And also https://msdn.microsoft.com/en-us/library/office/ff195475.aspx
Found the solution:
Option Explicit
Sub ReduceImageSize()
Dim cmt As Comment
Dim MyChart As ChartObject
Dim MyPicture As String
Dim pic As Object
Dim PicWidth As Long
Dim PicHeight As Long
Dim num As Long
Dim Mysheet As Worksheet
num = 1
Application.ScreenUpdating = False
For Each Mysheet In ThisWorkbook.Worksheets
For Each cmt In ActiveSheet.Comments
With cmt
.Visible = True
.Shape.CopyPicture Appearance:=xlScreen, Format:=xlBitmap
.Visible = False
PicHeight = .Shape.Height
PicWidth = .Shape.Width
Set MyChart = ActiveSheet.ChartObjects.Add(0, 0, 100, 100)
With MyChart
.Activate
.Width = PicWidth
.Height = PicHeight
.Chart.Paste
'.ChartArea.Select
'.Paste
.Chart.Export Filename:="C:\Temp\MyPic " & num & ".jpg", FilterName:="jpg"
End With
.Shape.Fill.UserPicture PictureFile:="C:\Temp\MyPic " & num & ".jpg"
num = num + 1
MyChart.Delete
End With
Next
Application.ScreenUpdating = True
Next
End Sub

Exporting a picture set as a comment fill

I have used some code that will allow a user to store a picture in the comments of a cell using:
Application.ActiveCell.AddComment.Shape.Fill.UserPicture (fName)
I now want to write something that iterates through the comments of a worksheet and exports all the pictures used above into separate picture files. I am not sure how to reach the right object to do this.
Thanks
Martin
I cobbled some code together from a few sources. How does this work?
Sub extractCommentImage()
'Borrowed from: https://excelribbon.tips.net/T011165_Moving_Comment_Background_Pictures_to_Cells.html
Dim cmt As Comment
Dim cel As Range
Dim bvisible As Boolean
For Each cmt In ActiveSheet.Comments
With cmt
bvisible = .Visible
.Visible = True
Set cel = .Parent.Offset(0, 1)
.Shape.CopyPicture appearance:=xlScreen, Format:=xlPicture
cel.PasteSpecial
selection.ShapeRange.LockAspectRatio = msoFalse
.Visible = bvisible
.Shape.Fill.OneColorGradient msoGradientFromCenter, 1, 1
End With 'cmt
Next cmt
ExportMyPicture
End Sub
And the "Export" sub:
Sub ExportMyPicture()
'borrowed from: https://stackoverflow.com/questions/18232987/export-pictures-from-excel-file-into-jpg-using-vba
Dim MyChart As String, MyPicture As String, pic As Object
Dim PicWidth As Long, PicHeight As Long, num As Long
Dim shtName as String
num = 1
Application.ScreenUpdating = False
shtName = ActiveSheet.Name
For Each pic In ActiveSheet.Pictures
MyPicture = pic.Name
With pic
PicHeight = .ShapeRange.Height
PicWidth = .ShapeRange.Width
End With
Charts.Add
ActiveChart.Location Where:=xlLocationAsObject, Name:=shtName
selection.Border.LineStyle = 0
MyChart = Split(ActiveChart.Name, " ")(1) & " 1"
With ActiveSheet
With .Shapes(MyChart)
.Width = PicWidth
.Height = PicHeight
End With
.Shapes(MyPicture).Copy
With ActiveChart
.ChartArea.Select
.Paste
End With
.ChartObjects(1).Chart.Export Filename:="C:\Users\[CHANGE THIS]\Desktop\MyPic " & num & ".jpg", FilterName:="jpg"
num = num + 1
.Shapes(MyChart).Cut
End With
Next pic
Application.ScreenUpdating = True
Exit Sub
End Sub

Resources