Excel to PowerPoint VBA - Table Conditional Formatting - excel

I'm relatively new to VBA.
I'm helping an internal team to improve workflow by reducing errors when copying and pasting data from Excel to PowerPoint.
How do I configure conditional formatting in the PowerPoint table based on two rules?
2-Color Scale:
Icon Set:
My current code is as follows. This has allowed for data to be copied from a single Excel cell to a single PowerPoint table cell.
Sub TableData()
Dim oPPApp As Object, oPPrsn As Object, oPPSlide As Object
Dim oPPShape As Object
Dim FlName As String
FlName = "FILE PATH"
On Error Resume Next
Set oPPApp = GetObject(, "PowerPoint.Application")
If Err.Number <> 0 Then
Set oPPApp = CreateObject("PowerPoint.Application")
End If
Err.Clear
On Error GoTo 0
oPPApp.Visible = True
Set oPPrsn = oPPApp.Presentations.Open(FlName)
Set oPPSlide = oPPrsn.Slides(1)
Set oPPShape = oPPSlide.Shapes(2)
ThisWorkbook.Sheets("Sheet1").Activate
oPPShape.Table.Cell(2, 3).Shape.TextFrame.TextRange.Text = Range("C1").Value
End Sub

For the table creation, the code is based on this answer I received, so you may have to adjust the code to your liking (it creates a slide for each row), the dimensions of the source and target table are based on my needs, since your code works only for one cell I wanted to test with more data.
The relevant part for your request is anyway this one:
Dim RGB_Val As String
RGB_Val = rng(i).DisplayFormat.Interior.Color
newTable.cell(i, 2).Shape.Fill.ForeColor.RGB = RGB_Val
that takes the background color of Conditionally Formatted cells (so you would have to apply conditional formatting to the Excel table, first) (information gathered from this answer and this one taking care of the comment Jun 9, 2018 at 13:08).
In each slide created following the row, each Excel column cell will then become a row in PPT, on the second column, while on the first there will be the circles, whose size can be defined by FlowRatio's value.
Their colors will have to be defined as per below (values and colors taken from your screenshot):
If rng(i).Value >= 12 Then
ElseIf rng(i).Value < 12 And rng(i).Value >= -12 Then
ElseIf rng(i).Value < -12 Then
So, from this:
you will get this:
but as per above, you may have to adjust sizes of the ranges to avoid errors.
Ah, it runs from Excel to PPT.
Sub CopyConditionalFormattingAddChecks()
Dim DataRange As Range, DataRow As Range, rng As Range, i As Long, col As Long
Dim ppApp As PowerPoint.Application, pres As PowerPoint.Presentation
Dim sld As PowerPoint.slide, newTable As PowerPoint.Table, Sldss As Slides
Dim CellLeft As Single
Dim CellTop As Single
Dim CellWidth As Single
Dim CellHeight As Single
Dim CellWidth_2 As Single
Dim Shp_Cntr As Single
Dim Shp_Mid As Single
Dim CircleCheck As PowerPoint.Shape
Dim IconNavigator As Object
Dim RGB_Val As String
Dim SlideCounter As Integer
Dim FlowCounter As Integer
Dim IconCounter As Integer
Dim TestCounter As Integer
FlowRatio = 0.6
On Error Resume Next
Set ppApp = GetObject(, "PowerPoint.Application")
Set pres = ppApp.ActivePresentation
On Error GoTo 0
If pres Is Nothing Then
MsgBox "Destination presentation must be open in PowerPoint", vbCritical
Exit Sub
End If
SlideCounter = 0
CircleCheckCounter = 0
Set DataRange = Selection
For Each DataRow In DataRange.Rows
Set sld = pres.Slides.AddSlide(pres.Slides.Count + 1, pres.SlideMaster.CustomLayouts(2))
SlideCounter = SlideCounter + 1
Set newTable = sld.Shapes.AddTable(14, 4).Table ' different here
With newTable.Columns(1): .Width = 5: End With
With newTable.Columns(2): .Width = 60: End With
With newTable.Columns(3): .Width = 5: End With
With newTable.Columns(4): .Width = 50: End With
With sld.Shapes.Placeholders(2): .Width = 550: End With
Set rng = DataRow.Cells(1).Resize(1, 10)
For i = 1 To newTable.Rows.Count
newTable.cell(i, 2).Shape.TextFrame2.TextRange.Text = rng.Cells(i).Value
RGB_Val = rng(i).DisplayFormat.Interior.Color
newTable.cell(i, 2).Shape.Fill.ForeColor.RGB = RGB_Val
If rng(i).Value >= 12 Then
CellTop = newTable.cell(i, 1).Shape.Top
CellLeft = newTable.cell(i, 1).Shape.Left
CellWidth = newTable.cell(i, 1).Shape.Width
CellHeight = newTable.cell(i, 1).Shape.Height
Shp_Cntr = CellLeft + CellWidth / 2
Shp_Mid = CellTop + CellHeight / 2
Set CircleCheck = sld.Shapes.AddShape(Type:=msoShapeOval, Left:=Shp_Cntr - (CellHeight * FlowRatio / 2), Top:=Shp_Mid - (CellHeight * FlowRatio / 2), Width:=CellHeight * FlowRatio, Height:=CellHeight * FlowRatio)
CircleCheck.Fill.ForeColor.RGB = RGB(214, 85, 50)
CircleCheck.Line.Weight = 0.75
CircleCheck.Line.ForeColor.RGB = RGB(255, 255, 255)
CircleCheck.Line.Visible = msoTrue
CircleCheck.LockAspectRatio = msoTrue
CircleCheck.Name = "CircleCheck " & CircleCheckCounter
CircleCheck.ZOrder msoBringToFront
ElseIf rng(i).Value < 12 And rng(i).Value >= -12 Then
CellTop = newTable.cell(i, 1).Shape.Top:
CellLeft = newTable.cell(i, 1).Shape.Left
CellWidth = newTable.cell(i, 1).Shape.Width
CellHeight = newTable.cell(i, 1).Shape.Height
Shp_Cntr = CellLeft + CellWidth / 2
Shp_Mid = CellTop + CellHeight / 2
'
Set CircleCheck = sld.Shapes.AddShape(Type:=msoShapeOval, Left:=Shp_Cntr - (CellHeight * FlowRatio / 2), Top:=Shp_Mid - (CellHeight * FlowRatio / 2), Width:=CellHeight * FlowRatio, Height:=CellHeight * FlowRatio)
CircleCheck.Fill.ForeColor.RGB = RGB(234, 194, 130)
CircleCheck.Line.Weight = 0.75
CircleCheck.Line.ForeColor.RGB = RGB(255, 255, 255)
CircleCheck.Line.Visible = msoTrue
CircleCheck.LockAspectRatio = msoTrue
CircleCheck.Name = "CircleCheck " & CircleCheckCounter
CircleCheck.ZOrder msoBringToFront
ElseIf rng(i).Value < -12 Then
CellTop = newTable.cell(i, 1).Shape.Top:
CellLeft = newTable.cell(i, 1).Shape.Left
CellWidth = newTable.cell(i, 1).Shape.Width
CellHeight = newTable.cell(i, 1).Shape.Height
Shp_Cntr = CellLeft + CellWidth / 2
Shp_Mid = CellTop + CellHeight / 2
Set CircleCheck = sld.Shapes.AddShape(Type:=msoShapeOval, Left:=Shp_Cntr - (CellHeight * FlowRatio / 2), Top:=Shp_Mid - (CellHeight * FlowRatio / 2), Width:=CellHeight * FlowRatio, Height:=CellHeight * FlowRatio)
CircleCheck.Fill.ForeColor.RGB = RGB(104, 164, 144)
CircleCheck.Line.Weight = 0.75
CircleCheck.Line.ForeColor.RGB = RGB(255, 255, 255)
CircleCheck.Line.Visible = msoTrue
CircleCheck.LockAspectRatio = msoTrue
CircleCheck.Name = "CircleCheck " & CircleCheckCounter
CircleCheck.ZOrder msoBringToFront
End If
Next i
Next DataRow
End Sub

Related

when i extract from excel to PowerPoint shows automation error

i have code that can extract from excel to PowerPoint but sometime shows automation error
i tried using return but it doesn't work
can u plz help me with this issue?
this is my code so far:
'''
Sub presntation()
Dim pptapp As PowerPoint.Application
Dim PPTPres As PowerPoint.Presentation
Dim PPTSlide As PowerPoint.Slide
'Declare Excel Variables
Dim ExcRng As Range
Dim RngArray As Variant
Dim RngArray1 As Variant
' On Error Resume Next
' x = x - 1
' e = e - 1
' h = h - 1
Dim oPPTApp As PowerPoint.Application
Dim oPPTFile As PowerPoint.Presentation
Dim oPPTShape As PowerPoint.Shape
Dim oPPTSlide As PowerPoint.Slide
'intger ma jjsjks kskjsdkjsd
Dim Rng As Range
Dim h As Integer
Dim v As Integer
'intger1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Dim m As Integer
Dim s As Integer
p = 0
On Error GoTo errhandler
'errhandler:
'Resume Next
Dim g As Integer
Dim e As Integer
Dim p As Integer
'Do
'DoEvents
'Loop Until ie.readstate = readystate_complete
'Tate Complete
'Get the PowerPoint Application, I am assuming it's already open.
Set pptapp = New PowerPoint.Application
pptapp.Visible = True
Set oPPTApp = GetObject(, "PowerPoint.Application")
'Set a reference to the range you want to copy, and then copy it.
'Set Rng = Worksheets("Sheet1").Range("B3:N9")
' Rng.Copy
'Set a reference to the active presentation.
g = 0
m = 0
Dim o As Integer
o = 0
h = 1
e = 0
x = 0
errhandler:
If p = 1 Then
oPPTFile.Slides(s).Delete
If x = 0 Then
GoTo Go
'
Else
If x = Even.Value = True Then
s = s - 1
'x = x - 1
e = e - 1
GoTo Go
Else
s = s - 1
x = x - 2
e = e - 2
GoTo Go
End If
End If
Else
End If
'Populate our array
' If x = 0 Then
' Sheets("WBB2").Select
' Else
' If x = 1 Then
' Sheets("WBB3").Select
' Else
' End If
'End If
'Create a new instance of PowerPoint
s = 1
e = 0
' Set pptapp = New PowerPoint.Application
' pptapp.Visible = True
'Create a new Presentation
Set PPTPres = pptapp.Presentations.Add
'RngArray = Array(Worksheets("Backup data1").Range("E9:O38"))
RngArray = Array(Worksheets("Backup data1").Range("E9:O38"), Worksheets("Backup
data1").Range("E6:O8"), Worksheets("Backup data1").Range("E50:O79"), Worksheets("Backup
data1").Range("E47:O49"), Worksheets("Backup data1").Range("E87:O116"), Worksheets("Backup
data1").Range("E84:O86"), Worksheets("Backup data1").Range("E127:O156"), Worksheets("Backup
data1").Range("E123:O125"), Worksheets("Backup data1").Range("E165:O195"), Worksheets("Backup
data1").Range("E163:O165"), Worksheets("Backup data1").Range("E203:O232"), Worksheets("Backup
data1").Range("E200:O202"), Worksheets("Backup data1").Range("E241:O270"), Worksheets("Backup
data1").Range("E237:O239"), Worksheets("Backup data1").Range("C307:L314"), Worksheets("Backup
data1").Range("D301:K303"), Worksheets("Backup data1").Range("C335:L340"), Worksheets("Backup
data1").Range("D329:K331"), Worksheets("Backup data1").Range("C365:L372"), Worksheets("Backup
data1").Range("D359:K361"), _
Worksheets("Backup data1").Range("C393:L396"), Worksheets("Backup data1").Range("D387:K389"),
Worksheets("Backup data1").Range("C421:L428"), Worksheets("Backup data1").Range("D415:K417"),
Worksheets("Backup data1").Range("C449:L455"), Worksheets("Backup data1").Range("D443:K445"),
Worksheets("Backup data1").Range("C477:L479"), Worksheets("Backup data1").Range("D471:K473"),
Worksheets("Backup data1").Range("C505:L510"), Worksheets("Backup data1").Range("D499:K501"),
Worksheets("Backup data1").Range("A531:F544"), Worksheets("Backup data1").Range("B527:K529"))
'Loop through the range array, create a slide for each range, and copy that range on to the
slide.
For x = LBound(RngArray) To UBound(RngArray)
Go:
'Set a reference to the range
Set ExcRng = RngArray(x)
'Copy Range
ExcRng.Copy
'Enable this line of code if you recieve error about the range not being in the clipboard
- This will fix that error by pausing the program for ONE Second.
Set oPPTFile = oPPTApp.ActivePresentation
If h = 1 Then
If m = 2 Then
Set oPPTSlide = Nothing
Set PPTSlide = Nothing
x = x - (1 + g)
Set PPTSlide = PPTPres.Slides.Add(x + 1, ppLayoutBlank)
' Application.Wait Now + #12:00:01 AM#
m = 1
x = x + (1 + g)
s = s + 1
g = g + 1
Else
m = m + 1
Set PPTSlide = PPTPres.Slides.Add(x + 1, ppLayoutBlank)
End If
'Set PPTSlide = PPTPres.Slides.Add(x + 1, ppLayoutBlank)
'x = x + 1
'Set a reference to the slide you want to paste it on.
Set oPPTSlide = oPPTFile.Slides(s)
Else
m = m + 1
End If
Application.Wait Now + TimeValue("00:00:02")
p = 1
'On Error GoTo errhandler
'errhandler:
'Resume Next
'WARNING THIS METHOD IS VERY VOLATILE, PAUSE THE APPLICATION TO SELECT THE SLIDE
For i = 1 To 5000: DoEvents: Next
oPPTSlide.Select
'WARNING THIS METHOD IS VERY VOLATILE, PAUSE THE APPLICATION TO PASTE THE OBJECT
For i = 1 To 10000: DoEvents: Next
oPPTApp.CommandBars.ExecuteMso "PasteSourceFormatting"
oPPTApp.CommandBars.ReleaseFocus
For i = 1 To 10000: DoEvents: Next
'
If e < 14 Then
If h = 2 Then
With oPPTApp.ActiveWindow.Selection.ShapeRange
.Top = 20
.Left = 25
.Width = 910
End With
Set oPPTSlide = Nothing
Set PPTSlide = Nothing
h = 0
'Application.Wait Now + #12:00:01 AM#
Else
With oPPTApp.ActiveWindow.Selection.ShapeRange
.Top = 80
.Left = 50
.Height = 450
.Width = 870
' Application.Wait Now + #12:00:01 AM#
End With
End If
Else
If h = 2 Then
With oPPTApp.ActiveWindow.Selection.ShapeRange
.Top = 20
.Left = 25
.Width = 910
Set oPPTSlide = Nothing
Set PPTSlide = Nothing
End With
h = 0
Else
With oPPTApp.ActiveWindow.Selection.ShapeRange
.Top = 80
.Left = 50
.Height = 300
' .Height = 200
.Width = 870
End With
End If
End If
o = o + 1
e = e + 1
'Create a new Slide
'Set PPTSlide = PPTPres.Slides.Add(x + 1, ppLayoutBlank)
'Paste the range in the slide as a linked OLEObject
'PPTApp.CommandBars.ExecuteMso
'PPTSlide.Shapes.PasteSpecial DataType:=ppPasteOLEObject
' pptApplication.CommandBars.ExecuteMso ("PasteSourceFormatting")
h = h + 1
Next x
End Sub
You're using 'Set oPPTFile = oPPTApp.ActivePresentation'
Depending what you do during the macro is running, PowerPoint might lose the focus, then the 'ActivePresentation' is empty.
Some lines before you use 'Set PPTPres = pptapp.Presentations.Add'
As a quick workaround try 'Set oPPTFile = PPTPres' instead of 'Set oPPTFile = oPPTApp.ActivePresentation', for future projects: If you already assigned an object to a variable, use this variable instead of the ActivePresentation.
It could be that you are not waiting long enough for the paste to be completed. Try the method described here
Option Explicit
Sub presntation()
' Power point variables
Dim oPPTApp As PowerPoint.Application
Dim oPPTPres As PowerPoint.Presentation
Dim oPPTShape As PowerPoint.Shape
Dim oPPTSlide As PowerPoint.Slide
' Excel Variables
Dim xl As Excel.Application
Dim wb As Workbook
Dim i As Long, RngArray As Variant, p As Integer, t0 As Single
Dim n As Integer
t0 = Timer
RngArray = Array("E9:O38", "E6:O8", "E50:O79", "E47:O49", _
"E87:O116", "E84:O86", "E127:O156", "E123:O125", _
"E165:O195", "E163:O165", "E203:O232", "E200:O202", _
"E241:O270", "E237:O239", "C307:L314", "D301:K303", _
"C335:L340", "D329:K331", "C365:L372", "D359:K361", _
"C393:L396", "D387:K389", "C421:L428", "D415:K417", _
"C449:L455", "D443:K445", "C477:L479", "D471:K473", _
"C505:L510", "D499:K501", "A531:F544", "B527:K529")
' Get the PowerPoint Application, I am assuming it's already open.
'Set oPPTApp = GetObject(, "PowerPoint.Application")
' Create new presentation
Set oPPTApp = New PowerPoint.Application
oPPTApp.Visible = msoTrue
Set oPPTPres = oPPTApp.Presentations.Add(msoTrue)
' create slides
Set wb = ThisWorkbook
Set xl = wb.Parent
For i = LBound(RngArray) To UBound(RngArray) Step 2
' create slide
If i Mod 2 = 0 Then
p = p + 1
oPPTPres.Slides.Add p, ppLayoutBlank
End If
xl.StatusBar = "Creating slide " & p
Set oPPTSlide = oPPTPres.Slides(p)
oPPTSlide.Select
'Copy Top Range
wb.Worksheets("Backup data1").Range(RngArray(i + 1)).Copy
n = oPPTSlide.Shapes.Count
oPPTApp.CommandBars.ExecuteMso "PasteExcelTableSourceFormatting"
' wait for shape to be created
Do
DoEvents
Loop Until oPPTSlide.Shapes.Count > n
With oPPTSlide.Shapes(oPPTSlide.Shapes.Count)
.Top = 20
.Left = 25
.Width = 910
End With
xl.CutCopyMode = False
'Copy Bottom Range
wb.Worksheets("Backup data1").Range(RngArray(i)).Copy
n = oPPTSlide.Shapes.Count
oPPTApp.CommandBars.ExecuteMso "PasteExcelTableSourceFormatting"
' wait for shape to be created
Do
DoEvents
Loop Until oPPTSlide.Shapes.Count > n
With oPPTSlide.Shapes(oPPTSlide.Shapes.Count)
.Top = 80
.Left = 50
.Width = 870
If i < 14 Then
.Height = 450
Else
.Height = 300
End If
End With
xl.CutCopyMode = False
Next i
AppActivate xl.Caption
xl.StatusBar = "Done"
MsgBox p & " slides created", vbSystemModal, Format(Timer - t0, "0.0 secs")
End Sub

Excel VBA SeriesCollection_Run time error 1004_parameter not valid

Thanks #Rory! I was able to fix it and now I got a new bug
Run time error 1004/parameter not valid
at at .SeriesCollection(j).XValues = ws.Range(rs)
Could someone please help me?
'''
I am trying to make multiple charts. And each chart would have 20 different groups with legend.
The way I have tried is first make multiple charts by columns and then add for/n loop in my code (here tried to have every 20 rows for one each group
Sub horizontal()
Dim sh As Shape
Dim ws As Worksheet
Dim ch As Chart
Dim rd As Range
Dim i As Integer, j As Integer, k As Integer
Set ws = Sheets("S1")
On Error Resume Next
ws.ChartObjects.Delete
On Error GoTo 0
For i = 20 To 45
Set rs = ws.Range("s2:s21")
Set rd = ws.Range("f1:j10")
Set sh = ws.Shapes.AddChart2(240, xlXYScatterLines)
Set ch = sh.Chart
For j = 1 To 20
k = j * 20
With ch 'shape.chart'
.SetSourceData Union(rs, ws.Range(ws.Cells(2, i), ws.Cells(21, i)))
.SeriesCollection.NewSeries
.SeriesCollection(j).XValues = ws.Range("s2:s21")
.SeriesCollection(j).Values = ws.Range(ws.Cells(k - 18, i), ws.Cells(k + 1, i))
.HasTitle = True
.ChartTitle.Text = ws.Range("T1")
.HasLegend = True
End With
Next j
With sh
.Name = "cht" & (i - 19)
.Top = (i - 20) * rd.Height
.Left = rd.Left
.Width = rd.Width
.Height = rd.Height
End With
Next i
End Sub
I tried the below two codes but they didn'twork.
Sub horizontal()
Dim sh As Shape
Dim ws As Worksheet
Dim ch As Chart
Dim rd As Range
Dim i As Integer, j As Integer, k As Integer
Set ws = Sheets("S1")
On Error Resume Next
ws.ChartObjects.Delete
On Error GoTo 0
For i = 20 To 45
Set rs = ws.Range("s2:s21")
Set rd = ws.Range("f1:j10")
Set sh = ws.Shapes.AddChart2(240, xlXYScatterLines)
Set ch = sh.Chart
With ch 'shape.chart'
.SetSourceData Union(rs, Range(Cells(2, i), Cells(21, i)))
.HasTitle = True
.ChartTitle.Text = ws.Range("T1")
.HasLegend = True
End With
With sh
.Name = "cht" & (i - 19)
.Top = (i - 20) * rd.Height
.Left = rd.Left
.Width = rd.Width
.Height = rd.Height
End With
Next i
End Sub
Sub diameter()
Dim ws As Worksheet
Dim sh As Shape
Dim ch As Chart
Dim rng As Range, rngTime As Range
Dim n As Integer, m As Integer, k As Integer, i As Integer
Set ws = Sheets("S1")
'delete previous plots
If ws.ChartObjects.Count > 0 Then
ws.ChartObjects.Delete
End If
Set rngTime = ws.Range(Cells(2, 19), Cells(21, 19))
ws.Shapes.AddChart2(240, xlXYScatterLines).Select
ws.Shapes(1).Chart.SetSourceData Union(rngTime, Range(Cells(2, 20), Cells(21, 20)))
'Source:=Range("'S1'!$S$2:$S$21,'S1'!$T$2:$T$21")
For n = 1 To 20
m = n * 20
With ActiveChart.SeriesCollection.NewSeries
ActiveChart.FullSeriesCollection(n).XValues = ws.Range(Cells(2, 19), Cells(21, 19))
ActiveChart.FullSeriesCollection(n).Values = ws.Range(Cells(m - 18, 20), Cells(m + 1, 20))
End With
Next n
End Sub
'''

Positioning pictures in worksheet

Below code count pictures that are pasted (by other macro) as msorectangle shape in excel worksheet and position them in 1 row in specific distance beetween each of them. I need to add another restrctions to positioning and im struggling with coding it. Question is how to upgrade this code if:
If number of pictures is <=6 than 1 row of pictures and set size to h:7,25cm w:4,7cm
If number of pictures is >6 and <=11 then 1 row of pictures with size h:5,9cm w:3,8cm
If number of pictures is =12 than 2 rows with size from 1 point h:7,25cm w:4,7cm.
If number of pictures is >12 than every (7, 13, 19, 25 etc. pic) is starting from next row with size from point nr 2 h:5,9cm w:3,8cm
The list of pictures is dynamic.
Sub Sample2()
Dim shp As Shape, shp2 As Shape
Dim ws As Worksheet
Dim lstShp As Integer
Dim shpLft As Double, shpTop As Double, shpWidth As Double, shpHeight As Double
Dim inBetweenMargin As Double
Dim i As Long
'~~> In betwen margin
inBetweenMargin = 8
Set ws = ThisWorkbook.Worksheets("wk")
With ws
'~~> Get the max shape number(name)
For Each shp In .Shapes
If shp.AutoShapeType = msoShapeRectangle Then
If Val(shp.Name) > 1 And Val(shp.Name) > lstShp Then _
lstShp = Val(shp.Name)
End If
Next
'~~> Loop through the shapes
For i = 1 To lstShp
'~~> This is required in case you delete shape 3
'~~> and have only shapes 1,2,4,5 etc...
On Error Resume Next
Set shp = .Shapes(CStr(i))
'shp2 = first photo
Set shp2 = ws.Shapes("1")
On Error GoTo 0
'~~> position them
If Not shp Is Nothing And shp.AutoShapeType = msoShapeRectangle Then
If shpLft = 0 And shpTop = 0 And shpWidth = 0 Then
shpLft = shp.Left
shpTop = shp.Top
shpWidth = shp.Width
Else
shp.Top = shpTop
shp.Left = shpLft + shpWidth + inBetweenMargin
shpLft = shp.Left
shpWidth = shp.Width
End If
End If
'position picture nr 7 and above in second row
If Val(shp.Name) = 7 Then
shp.Top = shp2.Top + shp2.Height + inBetweenMargin
shp.Left = shp2.Left
shpLft = shp.Left
shpWidth = shp.Width
End If
If Val(shp.Name) >= 8 Then
shp.Top = shp2.Top + shp2.Height + inBetweenMargin
End If
Next i
End With
End Sub
For the 2nd last condition, if the total picture count is 12 then I am safely assuming that you need 6 per line. And for the last condition you want 7 per line. For these two we will use a Counter and then we will do either Counter Mod 6 or Counter Mod 7 for that purpose. You can read about Mod operator in MS KB.
The logic is to reset the .Top and .Left in the next line for the last 2 conditions.We will use a boolean variable for that.
Is this what you are trying?
Option Explicit
Sub Sample()
Dim shp As Shape, shp2 As Shape
Dim ws As Worksheet
Dim lstShp As Integer
Dim shpLft As Single, shpTop As Single, shpWidth As Single, shpHeight As Single
Dim oldLeft As Single, oldTop As Single
Dim inBetweenMargin As Single
Dim i As Long, counter As Long, picCount As Long
Dim nextLine As Boolean, MultipleRows As Boolean
Dim ModByNumber As Long
'~~> In betwen margin
inBetweenMargin = 8
Set ws = ThisWorkbook.Worksheets("Sheet1")
With ws
'~~> Get the max shape number(name)
For Each shp In .Shapes
If shp.AutoShapeType = msoShapeRectangle Then
If Val(shp.Name) > 1 And Val(shp.Name) > lstShp Then _
lstShp = Val(shp.Name)
picCount = picCount + 1
End If
Next
Select Case picCount
Case 1 To 6
'~~> Set your default height and Width
shpHeight = 7.25 * 28.34646 '<~~ Cm to Points
shpWidth = 4.7 * 28.34646 '<~~ Cm to Points
Case 7 To 11
'~~> Set your default height and Width
shpHeight = 5.9 * 28.34646 '<~~ Cm to Points
shpWidth = 3.8 * 28.34646 '<~~ Cm to Points
Case 12
'~~> Set your default height and Width
shpHeight = 7.25 * 28.34646 '<~~ Cm to Points
shpWidth = 4.7 * 28.34646 '<~~ Cm to Points
MultipleRows = True
ModByNumber = 6
Case Is > 12
'~~> Set your default height and Width
shpHeight = 5.9 * 28.34646 '<~~ Cm to Points
shpWidth = 3.8 * 28.34646 '<~~ Cm to Points
MultipleRows = True
ModByNumber = 7
End Select
nextLine = False
'~~> Loop through the shapes
For i = 1 To lstShp
'~~> This is required in case you delete shape 3
'~~> and have only shapes 1,2,4,5 etc...
On Error Resume Next
Set shp = .Shapes(CStr(i))
On Error GoTo 0
'~~> position them
If Not shp Is Nothing Then
If shp.AutoShapeType = msoShapeRectangle Then
If shpLft = 0 And shpTop = 0 Then
shpLft = shp.Left
shpTop = shp.Top
shp.Height = shpHeight
shp.Width = shpWidth
'~~> Storing the top and left for resetting
'~~> when moving to next line
oldTop = shp.Top
oldLeft = shp.Left
counter = counter + 1
Else
shp.Top = shpTop
oldTop = shpTop
If nextLine = True Then
shp.Left = shpLft
nextLine = False
counter = 1
Else
shp.Left = shpLft + shpWidth + inBetweenMargin
counter = counter + 1
End If
shp.Height = shpHeight
shp.Width = shpWidth
shpLft = shp.Left
If MultipleRows = True Then
If counter Mod ModByNumber = 0 Then
shpLft = oldLeft
shpTop = oldTop + shpHeight + inBetweenMargin
nextLine = True
End If
End If
End If
End If
End If
'~~> This is required if there is no shape between 4 and 6.
'~~> 5 gets deleted? Also the reason why we are not using "i Mod 7"
'~~> and using "counter Mod 7"
Set shp = Nothing
Next i
End With
End Sub
Screenshots
If number of pictures is 6 than 1 row and set size to h:7,25cm w:4,7cm
If number of pictures is >7 and <=10 then 1 row of pictures with size h:5,9cm w:3,8cm
If number of pictures is <12 than 2 rows with size from 1 point.
If number of pictures is >12 than every 7 pic is starting from next row with size from point nr 2
So if we take i as the amount of pictures:
We can do some simple calculations to check which condition is met and use Select Case
to identify and assign each of your 4 cases like so:
Select Case i
Case IS >= 12
numberofrows = i \ 7 '(this only gives whole numbers)
Formatting = 2
Case IS > 10
numberofrows = 2
Formatting = 1
Case IS >= 7
numberofrows = 1
Formatting = 2
Case ELSE
numberofrows = 1
Formatting = 1
End Select

Link Connectors to ChartPoint VBA

I created a macro that add an arrow to chartPoint if value of that point is under 1 and different from 0
The code works perfectly but When Itry to create The Arrow I get an error "Object Required" and I didn't manage to select the head of that shape and create arrow there .
What I'm trying to do is described in the Image below
The code of Verifying Result and Add arrow is below
Sub fzerfgsdf()
'
' fzerfgsdf Macro
'
Dim clLeft As Double
Dim clTop As Double
Dim clWidth As Double
Dim clHeight As Double
Dim cl As Range
Dim shpOval As Shape
ActiveSheet.ChartObjects("Graphique 69").Activate
x = ActiveChart.SeriesCollection(1).Values
For i = LBound(x) To UBound(x)
Debug.Print "Point "; i; "="; x(i)
If x(i) < 1 And x(i) <> 0 Then
ActiveChart.SeriesCollection(1).Points(i).Select
Set cl = ActiveChart.SeriesCollection(1).Points(i).Select '<-- Range("C2")
clLeft = cl.Left
clTop = cl.Top
clHeight = 131.25
clWidth = 579
Set shpOval = ActiveSheet.Shapes.AddConnector(msoConnectorStraight, clLeft, clTop, 579, 131.25)
shpOval.Select
selection.ShapeRange.Line.EndArrowheadStyle = msoArrowheadOpen
selection.ShapeRange.ShapeStyle = msoLineStylePreset20
End If
Next i
End Sub
I found solution for first problem which is creating shape but I can't figure out how to locate that shape in the right place where the blue chart using a specific values see image
Sub fzerfgsdf()
'
' fzerfgsdf Macro
'
ActiveSheet.ChartObjects("Graphique 69").Activate
x = ActiveChart.SeriesCollection(1).Values
For i = LBound(x) To UBound(x)
Debug.Print "Point "; i; "="; x(i)
If x(i) < 1 And x(i) <> 0 Then
ActiveSheet.ChartObjects("Graphique 69").Activate
ActiveChart.SeriesCollection(1).Points(i).Select
Dim clLeft As Double
Dim clTop As Double
Dim clWidth As Double
Dim clHeight As Double
Dim cl As Point
Dim shpOval As Shape
Set cl = ActiveChart.SeriesCollection(1).Points(i) '<-- Range("C2")
clLeft = cl.Left
clTop = cl.Top
clHeight = 131.25
clWidth = 579
Set shpOval = ActiveSheet.Shapes.AddConnector(msoConnectorStraight,
clLeft,
clTop, 579, 131.25)
shpOval.Select
selection.ShapeRange.Line.EndArrowheadStyle = msoArrowheadOpen
selection.ShapeRange.ShapeStyle = msoLineStylePreset20
End If
Next i
End Sub
Could Anyone light in solving This ?
Best Regards
Polos
Public Sub fzerfgsdf()
'
' fzerfgsdf Macro
'
Dim ws As Excel.Worksheet
Dim chrt As Excel.Chart
Dim sries As Excel.Series
Dim x As Variant
Dim clLeft As Double, clTop As Double
Dim clWidth As Double, clHeight As Double
Dim clBeginX As Double, clBeginY As Double, clEndX As Double, clEndY As Double
Dim cl As Excel.Point
Dim shpOval As Excel.Shape
Dim dl As Excel.DataLabel
Dim i As Long
clHeight = 30
clWidth = 15
Set ws = Application.ActiveSheet
Set chrt = ws.ChartObjects("Graphique 69").Chart
Set sries = chrt.SeriesCollection(1)
x = sries.Values
For i = LBound(x) To UBound(x)
Debug.Print "Point "; i; "="; x(i)
If (x(i) < 1) And (x(i) <> 0) Then
Set cl = sries.Points(i)
With chrt.ChartArea
clBeginX = IIf(.Left + cl.Left - clWidth < 0, 0, .Left + cl.Left - clWidth)
clBeginY = IIf(.Top + cl.Top - clHeight < 0, 0, .Top + cl.Top - clHeight)
clEndX = .Left + cl.Left
clEndY = .Top + cl.Top
End With
Set shpOval = ws.Shapes.AddConnector(msoConnectorStraight, clBeginX, clBeginY, clEndX, clEndY)
shpOval.Line.EndArrowheadStyle = msoArrowheadOpen
shpOval.ShapeStyle = msoLineStylePreset20
cl.HasDataLabel = True
sries.HasLeaderLines = False
Set dl = cl.DataLabel
With dl
.Text = "RFT 93%=> 5P"
.Position = xlLabelPositionAbove
.Format.AutoShapeType = msoShapeRectangularCallout
.Format.Line.Visible = msoFalse
.Top = cl.Top - clHeight - .Height - 5
.Left = cl.Left - clWidth - (.Width / 2)
With .Format.TextFrame2.TextRange.Font
.Size = 12
.Fill.ForeColor.RGB = RGB(255, 0, 0)
.Bold = msoTrue
End With
End With
End If
Next
Set shpOval = Nothing
Set cl = Nothing
Set sries = Nothing
Set chrt = Nothing
Set ws = Nothing
End Sub

I'm trying to make the pictures only go 10 Rows down, the Loop Back up to the next row. Can anyone help me? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
This is what I have so far, I just can't figure out how to loop the pictures back after 10 rows.
Sub InsertPictures()
Dim PicList() As Variant
Dim PicFormat As String
Dim Rng As Range
Dim sShape As Shape
Dim MaxWidth#
On Error Resume Next
PicList = Application.GetOpenFilename(PicFormat, MultiSelect:=True)
xColIndex = Application.ActiveCell.Column
If IsArray(PicList) Then
xRowIndex = Application.ActiveCell.Row
For lLoop = LBound(PicList) To UBound(PicList)
Set Rng = Cells(xRowIndex, xColIndex)
With ActiveSheet.Shapes.AddPicture(PicList(lLoop), msoFalse, msoCTrue, Rng.Left, Rng.Top, -1, -1)
.LockAspectRatio = True
.Height = 100 * 3 / 4
Rng.RowHeight = .Height
If MaxWidth < .Width Then
MaxWidth = .Width
End If
End With
xRowIndex = xRowIndex + 1
Next
Rng.ColumnWidth = MaxWidth / Rng.Width * Rng.ColumnWidth
Rng.ColumnWidth = MaxWidth / Rng.Width * Rng.ColumnWidth
Rng.ColumnWidth = MaxWidth / Rng.Width * Rng.ColumnWidth
For Each sShape In ActiveSheet.Shapes
sShape.Left = MaxWidth / 2 - sShape.Width / 2
Next
End If
End Sub
Simply track xRowIndex change compared to original row. When it's > 10 different update row and column
Refactored (with a few other improvements)
Sub InsertPictures()
Dim PicList() As Variant
Dim PicFormat As String
Dim Rng As Range
Dim sShape As Shape
Dim MaxWidth#
Dim xColIndex As Long, xRowIndex As Long, lLoop As Long
Dim xColIncrement As Long, xRowInit As Long
Dim ws As Worksheet
Set ws = ActiveSheet ' <-- better to be explicit rather than rely on implicit ActiveSheet reference
'On Error Resume Next <-- dont just ignore all errors
PicList = Application.GetOpenFilename(PicFormat, MultiSelect:=True)
xColIncrement = 1 ' <-- adjust to how many columns to increment by
xColIndex = Application.ActiveCell.Column
xRowInit = Application.ActiveCell.Row
xRowIndex = xRowInit
With ws
If IsArray(PicList) Then
For lLoop = LBound(PicList) To UBound(PicList)
Set Rng = .Cells(xRowIndex, xColIndex)
With .Shapes.AddPicture(PicList(lLoop), msoFalse, msoCTrue, Rng.Left, Rng.Top, -1, -1)
.LockAspectRatio = True
.Height = 100 * 3 / 4
Rng.RowHeight = .Height
If MaxWidth < .Width Then
MaxWidth = .Width
End If
End With
xRowIndex = xRowIndex + 1
' Check if rows is > 10 different to initial row
If xRowIndex >= xRowInit + 10 Then
Rng.ColumnWidth = MaxWidth / Rng.Width * Rng.ColumnWidth
MaxWidth = 0
xColIndex = xColIndex + xColIncrement
xRowIndex = xRowInit
End If
Next
Rng.ColumnWidth = MaxWidth / Rng.Width * Rng.ColumnWidth
End If
End With
End Sub
Here is a bit simplified version:
Sub InsertPictures() ': DrawingObjects.Delete: Cells.Delete ' used for testing
Dim picList, pic, picFormat As String
Dim rng As Range, sShape As Shape, MaxWidth As Double
picList = Application.GetOpenFilename(picFormat, MultiSelect:=True)
If Not IsArray(picList) Then Exit Sub ' picList = False if no files selected
Set rng = ActiveCell
Application.ScreenUpdating = False ' optional to make it faster
For Each pic In picList
With Shapes.AddPicture(pic, 0, 1, rng.Left, rng.Top, -1, -1)
.LockAspectRatio = True
rng.RowHeight = rng.RowHeight * 10
.Height = rng.Height
If MaxWidth < .Width Then MaxWidth = .Width
End With
Set rng = rng(2) ' move to the cell below
Next
rng.ColumnWidth = MaxWidth * 255 / 1342.5
For Each sShape In Shapes
sShape.Left = rng.Left + (rng.Width - sShape.Width) / 2
Next
Application.ScreenUpdating = True
End Sub

Resources