How to add slide in the middle of presentation using python-pptx? - apache-poi

I have a template.pptx , having 10 slides in total. I want to copy a slide/layout of slide 2 and add new slide after 2, between 2 and 3.
what I can do currently is copy and add the slide at the end of presentation.
prs = Presentation('C:\Documents\template.pptx')
slide = prs.slides.add_slide(prs.slide_layouts[1])
prs.save('C:\Documents\template_save.pptx')
Can I do this using java apache-poi?

I have tried the hybrid approach and it works well.
Copy and add slide at the end of presentation with python-pptx
Reorder slides with Apache POI
ppt.setSlideOrder(slides.length-1, 4); // Bring last slide to 5th position

from pptx import Presentation
def move_slide(old_index, new_index):
xml_slides = presentation.slides._sldIdLst
slides = list(xml_slides)
xml_slides.remove(slides[old_index])
xml_slides.insert(new_index, slides[old_index])
presentation = Presentation(pptpath)
layout = presentation.slide_masters[0].slide_layouts[6]
slide = presentation.slides.add_slide(layout)
slide_id = presentation.slides.index(slide)
move_slide(slide_id, 3)
presentation.save(pptpath)

Related

Repositioning Excel Charts as I add them into the same powerpoint slide

I am using Python3 and the win32com package to automatically copy charts from an excel file and paste them into a powerpoint presentation. The charts do not all fit on one slide unless they are resized, so I scale their width by 0.85. However, I am not sure how to paste them at specific locations so they are all pasted atop one another. I think I have found a solution in visual basic (here: https://www.mrexcel.com/board/threads/vba-positioning-chart-in-powerpoint-after-copy-pasting-from-excel.1107603/ and here: VBA: Copy + Paste Selected Charts from Excel to Powerpoint) but I don't know any VBA so am not sure how to translate it to python. Thank you for your help!
import os
import win32com.client as client
from win32com.client import constants
xl = client.gencache.EnsureDispatch('Excel.Application')
ppt = client.gencache.EnsureDispatch('PowerPoint.Application')
wb = xl.Workbooks.Open(os.path.abspath("desiredFile.xlsx"))
prs = ppt.Presentations.Open(os.path.abspath("sample00.pptx"))
sheet = wb.Sheets('TheSheetINeed')
Slide = prs.Slides.Add(prs.Slides.Count,constants.ppLayoutBlank)
for ch in sheet.ChartObjects():
ch.Activate()
ch.Copy()
Slide.Shapes.PasteSpecial(constants.ppPasteShape).ScaleWidth(.85,0)
#Here is where I need help
prs.Save()
prs.Close()
wb.Close(False)
ppt.Quit()
xl.Quit()
I don't know how Python3 declares variables or otherwise works, but I would try something like the following. Instead of
Slide.Shapes.PasteSpecial(constants.ppPasteShape).ScaleWidth(.85,0)
I would try
shp = Slide.Shapes.PasteSpecial(constants.ppPasteShape).ScaleWidth(.85,0)
shp.Left = LeftValue
shp.Top = TopValue
where shp is a variable that represents the pasted shape.

Roman numeral page numbers for table of contents

I'm generating word docs entirely in VBA and am aiming to have roman numeral page numbers for my table of contents and numeric page numbers for the remainder of the document. My table of contents spans multiple pages and is variable in page size.
How would I achieve roman numeral page numbers for only a table of contents of variable page span?
Any help would be greatly appreciated.
If you don't know where to start, try this approach in Word:
Insert a section break after the table of content pages.
Turn on the macro recorder
Format the page numbers in the first section with Roman numerals
select the next section and unlink it from the previous section
Format the page numbers in the second section with regular numbers
Turn off the macro recorder.
Adjust the code as required.
I also find Word fiddly in this area, so here's some code to show one possible example. The code clears the content of the current document (so don't run it in your existing document!!), then generates a few headings, followed by a table of contents, both of which are then split by a section break. The section break allows different formatting of the page number (roman numerals for the first section, and arabic for the second). Change the for loop up to 100 will demonstrate multiple ToC pages. Might point you in the right direction. Cheers.
Option Explicit
Public Sub PageNumbers()
Dim myRange As Range
Dim Counter As Long
Dim myTOC As TableOfContents
' Delete word document content
ActiveDocument.StoryRanges(wdMainTextStory).Delete
' Add in some headings for testing
Set myRange = ActiveDocument.Range(0, 0)
For Counter = 1 To 10
myRange.InsertAfter "Heading " & Counter
myRange.Style = WdBuiltinStyle.wdStyleHeading1
myRange.InsertParagraphAfter
Next
' Add in a page number
With ActiveDocument.Sections(1)
.Footers(wdHeaderFooterPrimary).PageNumbers.Add _
PageNumberAlignment:=wdAlignPageNumberLeft, _
FirstPage:=True
End With
' Add in a section break at the start of the document
Set myRange = ActiveDocument.Range(0, 0)
myRange.InsertBreak Type:=wdSectionBreakNextPage
myRange.InsertParagraphAfter
' Insert a table of contents (into the first section)
Set myRange = ActiveDocument.Range(0, 0)
Set myTOC = ActiveDocument.TablesOfContents.Add(myRange, True, 1, 3, False)
' Format the page number of the first section to have roman numerals
With ActiveDocument.Sections.Item(1).Footers.Item(1).PageNumbers
.NumberStyle = wdPageNumberStyleLowercaseRoman
.HeadingLevelForChapter = 0
.IncludeChapterNumber = False
.ChapterPageSeparator = wdSeparatorHyphen
.RestartNumberingAtSection = False
.StartingNumber = 0
End With
' Format the page number of the second section to have arabic numerals
With ActiveDocument.Sections.Item(2).Footers.Item(1).PageNumbers
.NumberStyle = wdPageNumberStyleArabic
.HeadingLevelForChapter = 0
.IncludeChapterNumber = False
.ChapterPageSeparator = wdSeparatorHyphen
.RestartNumberingAtSection = True
.StartingNumber = 1
End With
End Sub
The Output:

Procedure continues before chart has been pasted from Excel to Powerpoint

On occasion you will want to copy a chart in Excel and paste it into a PowerPoint presentation using VBA. This comes in handy when you want to automate a report.
Problem: assuming you are not converting the graph to an image, and depending on the size and complexity of the graph you are trying to paste, the graph does not have time to paste before VBA attempts to continue with the procedure. This is annoying when you want to manipulate the graph after it has been pasted (e.g. positioning it on the slide). What effectively happens is you end up trying to move a chart on the slide... that does not yet 'exist' as a PowerPoint shape.
This issue is annoying and in my humble opinion actually constitutes a bug. I have not yet seen a robust solution to the problem on SO, with the potential exception of this answer from John Peltier. His answer is most likely correct (and has been designated as such on the thread) but unfortunately I could not get this to work in my implementation.
The issue I lay out below.
Code (simplified for ease of reference):
Public Sub X2P()
'Copy chart and paste
ActiveChart.ChartArea.Copy
Set mySlide = myPresentation.Slides(2)
PasteChartIntoSlide mySlide
End Sub
Function PasteChartIntoSlide(theSlide As Object) As Object
CreateObject("PowerPoint.Application").CommandBars.ExecuteMso ("PasteSourceFormatting")
End Function
I see others have tried to break up the script and to copy, paste and position charts using separate functions. This is cleaner, but it has not worked for me.
The solution I have found is to count the number of shapes on the slide before the code pastes the chart, num_obj, and to set variable num_obj_final as num_obj + 1 (i.e. total number of shapes once the chart has been pasted). I then create a loop after the paste event, where I recalculate num_obj with every iteration. Only when num_obj is equal to num_obj_final does the procedure exit the loop. And then the script can resume as expected, as you can be sure that the shape now 'exists' on the slide.
Final code for PasteChartIntoSlide() function:
Function PasteChartIntoSlide(theSlide As Object) As Object
theSlide.Select
num_obj = 0
num_obj_final = theSlide.Shapes.Count + 1
CreateObject("PowerPoint.Application").CommandBars.ExecuteMso ("PasteSourceFormatting")
DoEvents
Do Until num_obj = num_obj_final
num_obj = theSlide.Shapes.Count
'Debug.Print num_obj
Loop
End Function

export Crystal report to Excel (empty rows)

I am trying to export a report to excel. When I export my report to Excel I am getting blank rows between each detail section. I assume this is because I have a context menu in form of a normal text element which overlies the "normal" text elements.
Does anybody have any advice on how I can stop the blank rows occurring? Is it possible to suppress a text element only when it is exported to Excel?
Thanks!
Try to make it compact.
It should be no space between each object. You should set every object on the same row has the same height and every object on column has the same width.
When there's a space between objects, it will create a cell on excel.
There are 2 articles from Ken Hamady that might be helpfull:
http://kenhamady.com/cru/archives/231
http://www.kenhamady.com/news0506.shtml (scroll to the bottom of the page)
Another option , if you are working with tabular data is to use a report extension like it is shown in this video: https://www.youtube.com/watch?v=3hk6FJ1dvb4
This approach will use the Crystal report as a datasource and will export the data from a grid with much better formatting. The video is using a 3rd party tool, but it is free - http://www.r-tag.com/Pages/CommunityEdition.aspx
Use This Code:
Public Shared Sub ExportDataSetToExcel(ByVal ds As DataTable, ByVal filename As String)
Dim response As HttpResponse = HttpContext.Current.Response
response.Clear()
response.Buffer = True
response.Charset = ""
response.ContentType = "application/vnd.ms-excel"
Using sw As New StringWriter()
Using htw As New HtmlTextWriter(sw)
Dim dg As New DataGrid()
dg.DataSource = ds
dg.DataBind()
dg.RenderControl(htw)
response.Charset = "UTF-8"
response.ContentEncoding = System.Text.Encoding.UTF8
response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble())
response.Output.Write(sw.ToString())
response.[End]()
End Using
End Using
End Sub
Finally I've solved this issue, after a long time researching. Make the fields inside the details section fill the whole height of the section... no spaces between fields and top and bottom edges.
instead of this

save and close visio documents visual basic macro

I want to create a visio page, add some shapes, store it with a given filename and close it.
Currently, always the object/template toolbar is active and thus stored under the given filename.
What is the best way to store the current drawing?
thanks
Dim visioApp, visioPage as Object
Set visioApp = CreateObject("visio.application")
visioApp.Documents.AddEx ("")
Set visioPage = visioApp.ActiveWindow.Page
Set visioStencil = visioApp.Documents.Add("BASFLO_M.VSS")
' add shapes
visioApp.ActiveDocument.SaveAs ("c:\.......vsd")
visioApp.ActiveDocument.Close
As you point out, when you open the stencil the active document changes. You can change it back to the document you are editing like this:
Set visioApp = CreateObject("visio.application")
visioApp.Documents.AddEx ("")
Set visioPage = visioApp.ActiveWindow.Page
' Remember which window is active '
Set visioWindow = visioApp.ActiveWindow
Set visioStencil = visioApp.Documents.Add("BASFLO_M.VSS")
' Reactivate the drawing window '
visioWindow.Activate
visioPage.Drop visioStencil.Masters(1), 4, 4
visioApp.ActiveDocument.SaveAs "c:\temp\mydoc.vsd"
visioApp.ActiveDocument.Close
You could also use a reference to the document object you created and not rely on the active document:
Set visioApp = CreateObject("visio.application")
' Get a reference to the docment you are creating'
Set visioDoc = visioApp.Documents.AddEx("")
Set visioPage = visioApp.ActiveWindow.Page
Set visioStencil = visioApp.Documents.Add("BASFLO_M.VSS")
visioPage.Drop visioStencil.Masters(1), 4, 4
' Use the document object, not the active document '
visioDoc.SaveAs "c:\temp\mydoc1.vsd"
visioDoc.Close
I have one last suggestion. Instead of creating a new document and then a stencil I suggest you create a new document based on the Basic Flowchart template. By doing this you create a document with all the same default settings for grid, fonts, etc as the Basic Flowchart you would create if you selected that template in the user interface. Another benefit of using the template is that the flowchart stencils will be opened in the document's workspace every time the document you create is reopened. Try this:
Set visioApp = CreateObject("visio.application")
' BASFLO_M.VST is the filename of the Basic Flowchart Template (metric) '
Set visioDoc = visioApp.Documents.Add("BASFLO_M.VST")
Set visioPage = visioApp.ActiveWindow.Page
' The stencil will be already open as part of the BASFLO_M.VST workspace '
Set visioStencil = visioApp.Documents("BASFLO_M.VSS")
visioPage.Drop visioStencil.Masters(1), 4, 5
visioPage.Drop visioStencil.Masters(1), 5, 4
visioDoc.SaveAs "c:\temp\mydoc2.vsd"
visioDoc.Close

Resources