python-pptx icon indicating copy to clipboard operation
python-pptx copied to clipboard

shape: set z-order of shape in slide

Open scanny opened this issue 12 years ago • 16 comments

scanny avatar Oct 07 '13 14:10 scanny

@scanny Any pointers as to where to look in the code for something like this ?

NotSqrt avatar Aug 20 '15 14:08 NotSqrt

The z-order of shapes on a slide is determined solely by their document order in the slide part (e.g. slide1.xml). So the general gist would be to re-order that sequence of elements. The shapes in a slide are contained in the slide's "shape tree", a <p:spTree> element with the same syntax as the group shape, just the different name. The object I expect you'll want to look at first is pptx.shapes.shapetree.SlideShapeTree and its parent BaseShapeTree, which is what you get from slide.shapes. The _spTree attribute on that object gives you the lxml object for the <p:spTree> element, which would allow you to reorder shapes.

If you see how far you can get with that, feel free to ask more questions about the finer points, as needed :)

scanny avatar Sep 01 '15 23:09 scanny

Thanks @scanny We ended up using shapes._spTree.remove and shapes._spTree.insert to swap elements, like you said!

NotSqrt avatar Sep 02 '15 07:09 NotSqrt

If you can post the operative bit of the code you developed, that would be a help to others who arrive here on search. Glad you got it working :)

scanny avatar Sep 02 '15 16:09 scanny

An example with a picture:

picture = slide.shapes.add_picture(
    image, Cm(left), Cm(top), height=Cm(height)
)
# move picture to background
slide.shapes._spTree.remove(picture._element)
slide.shapes._spTree.insert(2, picture._element)  # use the number that does the appropriate job

NotSqrt avatar Sep 02 '15 17:09 NotSqrt

Awesome, thanks @NotSqrt :)

scanny avatar Sep 02 '15 17:09 scanny

+1 for this feature request. I tried the example above but it seems to create a slide that crashes powerpoint when opened.

smcpherson avatar Nov 10 '16 06:11 smcpherson

when I try to do this :

shape = shapes.add_shape(MSO_SHAPE.RECTANGLE,left,top,width,height)
slide.shapes._spTree.remove(shape._element)

an error says:

shape object has no attribute ’_Element'

did I make a mistake here?

BarryArch avatar Jun 06 '17 12:06 BarryArch

Looks like a typo. All shapes have the attribute ._element, not ._Element.

scanny avatar Jun 06 '17 16:06 scanny

It is not a typo actually, I typed shape._element or shape._Element , Error always says:

shape object has no attribute '_Element'

Not a typo

BarryArch avatar Jun 07 '17 00:06 BarryArch

What is the type of the object you get back?

shape = shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height)
print(shape.__class__)  # or perhaps print(shape.__class__.__name__)

And what available attributes to you find when you introspect into shape?

print(dir(shape))

scanny avatar Jun 07 '17 04:06 scanny

Is there a workaround other than using _spTree.remove and _spTree.insert? It creates corrupted pptx files which generate an alert when opening in MS Powerpoint. Thanks

chrismcmc avatar Aug 05 '17 18:08 chrismcmc

I don't believe you have to actually remove and insert to change the order. Perhaps counterintuitive to the naming, I believe the .addprevious() and .addnext() lxml methods actually move the XML element in question.

So you could do something like this to move a shape from ninth position to fourth:

# shape will be positioned relative to this one, hence the name "cursor"
cursor_sp = shapes[3]._element

cursor_sp.addprevious(shapes[8]._element)

scanny avatar Aug 05 '17 18:08 scanny

thanks @scanny! I used the following to move a picture I added using add_picture to the background:

cursor_sp = shapes[0]._element
cursor_sp.addprevious(pic._element)

MS Powerpoint opens the file without complaining

chrismcmc avatar Aug 05 '17 19:08 chrismcmc

@chrismcmc Glad to hear you got it working :)

scanny avatar Aug 05 '17 19:08 scanny

Thank you !

YuquanCui avatar Mar 22 '25 04:03 YuquanCui