Skip to content

Add custom tabs #206

@bunbun

Description

@bunbun

I wanted to add custom tab positions at fixed positions for particular paragraphs or styles and did not find an easy way to do this in docx. A quick scroll through the issues list found some example code which I have adapted. If anyone wants to tidy this up and add this to this fantastic library...

To use:

        from docx import Document
        from docx.shared import Inches, Cm

        document = Document()

        # add to style
        style = document.document.styles["Header 2"]
        add_custom_tabs_to_paragraph_format(style.paragraph_format, [Cm(tt) for tt in range(1, 5)])

        # add to paragraph
        pp = document.add_paragraph("test", 3)
        add_custom_tabs_to_paragraph_format(pp.paragraph_format, [Cm(tt) for tt in range(1, 10)])
        document.save("test.docx")

Custom Tab Code:

#__________________________________________________________________________________________________________________

#   add_custom_tabs_to_paragraph_format

#__________________________________________________________________________________________________________________
def add_custom_tabs_to_paragraph_format(paragraph_format, tab_stops, tab_style = "left", tab_leader = None):
    """
    tab_stops specified as list of Cm or Inches
    N.B. Hanging indents create an implicit tab stop

        <w:pPr>
              <w:tabs><w:tab w:val="left" w:pos="567"/>
                  <w:tab w:val="left" w:pos="1134"/>
                  <w:tab w:val="left" w:pos="1701"/>
                  <w:tab w:val="left" w:pos="2268"/></w:tabs>
            ...
        </w:pPr>

    """
    if tab_style not in ["left", "right", "center", "decimal", "bar", "clear", "end", "num", "start", ]:
        raise Exception("tab_style = %s is not a valid tab style in add_custom_tabs_to_paragraph_format(...)" % tab_style )
    if tab_leader not in [None, "dot", "heavy", "hyphen", "middleDot", "none", "underscore", ]:
        raise Exception("tab_leader = %s is not a valid tab leader in add_custom_tabs_to_paragraph_format(...)" % tab_leader )


    from docx.oxml import OxmlElement
    from docx.oxml.ns import qn

    def first_child_found_in(parent, tagnames):
        """
        Return the first child of parent with tag in *tagnames*, or None if
        not found.
        """
        for tagname in tagnames:
            child = parent.find(qn(tagname))
            if child is not None:
                return child
        return None

    def insert_element_before(parent, elm, successors):
        """
        Insert *elm* as child of *parent* before any existing child having
        tag name found in *successors*.
        """
        successor = first_child_found_in(parent, successors)
        if successor is not None:
            successor.addprevious(elm)
        else:
            parent.append(elm)
        return elm


    elem = paragraph_format.element  # elem is the <w:style> XML element
    pPr = elem.get_or_add_pPr()
    pTabs = OxmlElement('w:tabs')
    insert_element_before(pPr, pTabs, successors=(
        'w:shd', 'w:tabs', 'w:suppressAutoHyphens', 'w:kinsoku', 'w:wordWrap',
        'w:overflowPunct', 'w:topLinePunct', 'w:autoSpaceDE', 'w:autoSpaceDN',
        'w:bidi', 'w:adjustRightInd', 'w:snapToGrid', 'w:spacing', 'w:ind',
        'w:contextualSpacing', 'w:mirrorIndents', 'w:suppressOverlap', 'w:jc',
        'w:textDirection', 'w:textAlignment', 'w:textboxTightWrap',
        'w:outlineLvl', 'w:divId', 'w:cnfStyle', 'w:rPr', 'w:sectPr',
        'w:pPrChange'
    ))

    for tt in tab_stops:
        tab_n = OxmlElement('w:tab')
        tab_n.set(qn('w:val'), tab_style)
        tab_n.set(qn('w:pos'), '%s' % (tt / 625))
        if tab_leader is not None:
            tab_n.set(qn('w:leader'), tab_leader)
        pTabs.append(tab_n)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions