无法使用docx更改“标题1”字体名称

问题描述 投票:0回答:2

我正在使用以下脚本:

header = self.document.add_paragraph(style='Heading 1')
header.style.font.name = 'Arial'
header.style.font.size = Pt(16)
header.add_run('Header One')

结果是“Header One”得到“Calibri”。

python-2.7 python-docx
2个回答
6
投票

即使对于 python-docx 版本 0.8.5,这也是一个合法的错误。如果您要更改“Normal”样式的字体名称,它可以工作(如 python-docx 手册上的示例所示),但这不适用于“Heading 1”样式。

一种解决方法是创建一个新的标题样式,以标题 1 作为基本样式,然后修改新样式的字体名称和大小:

from docx.enum.style import WD_STYLE_TYPE

styles = self.document.styles
new_heading_style = styles.add_style('New Heading', WD_STYLE_TYPE.PARAGRAPH)
new_heading_style.base_style = styles['Heading 1']
font = new_heading_style.font
font.name = 'Arial'
font.size = Pt(16)
self.document.add_paragraph('Header One', style='New Heading')

0
投票

我找到了解决方案这里@scanny

from docx.oxml.ns import qn

h1 = doc.styles['Heading 1']
rFonts = h1.element.rPr.rFonts
rFonts.set(qn("w:asciiTheme"), "Times New Roman")

来自原始答案的详细副本

我将此作为 python-docx 问题提交:https://github.com/python-openxml/python-docx/issues/805 但被要求在此处展开讨论。

https://python-docx.readthedocs.io/en/latest/user/styles-using.html意味着我应该能够像这样更改标题字体样式:

font = doc.styles['Heading 1'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(16)

但这不起作用:生成的文档对所有标题都使用 Calibri。 (它们也是蓝色的,标题 1 有下划线,我也需要以某种方式消除它。)

更改特定标题上的字体也不起作用,也无法删除标题的 Latent_styles。

这是一个尝试所有三种方法的测试程序,但标题 1 和 2 仍然显示为蓝色 Calibri,尽管尝试将其更改为 Times New Roman:

import docx

doc = docx.Document()

# Deleting heading latent styles seems to do nothing:
latent_styles = doc.styles.latent_styles
latent_styles['Heading 1'].delete()
latent_styles['Heading 2'].delete()

# Setting the Normal font works:
font = doc.styles['Normal'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(12)

# Setting heading styles doesn't do anything:
# they all still end up as blue Calibri.
font = doc.styles['Heading 1'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(16)

font = doc.styles['Heading 2'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(14)

doc.add_heading("Heading 0", 0)
doc.add_paragraph('Here is a paragraph of text.')
doc.add_heading("Heading 1", 1)
doc.add_paragraph('Here is a paragraph of text.')
doc.add_heading("Heading 2", 2)
doc.add_paragraph('Here is a paragraph of text.')

# It also doesn't work to change the style of a specific heading:
heading = doc.add_heading("Another Heading 1", 1)
heading.style.font.name = "Times New Roman"
doc.add_paragraph('Here is a paragraph of text.')

doc.save('test.docx')

无法使用 docx 更改“标题 1”字体名称将此视为错误,并建议创建新样式作为解决方法。一个更简单的解决方法是在普通段落文本中创建连续行,然后设置这些连续行的样式。但如果可以将这些标题设置为蓝色 Calibri 以外的其他样式,那么使用“标题 1”等标准元素似乎会更好……并且文档暗示这是可能的。 广告

回答

正如您所观察到的,通常更改样式的字体(font.name)“就可以”。由于我不完全理解的原因,标题以及标题 1、标题 2 等样式是一个例外。我希望这与主题指定的字体选择有关。也许这与它们在形成目录方面的特殊作用有关。

首先,有一些观察结果:

  • document.add_heading("0th-level Heading", 0)应用的样式是Title。我认为这在某种程度上是有道理的,因为最高级别的标题赋予了整个文档的标题。当在该函数调用中分别使用 1 和 2 时,将应用标题 1、标题 2 等样式。

  • 如果我们将字体名称“Times New Roman”应用到标题样式,然后检查生成的 XML,我们会看到以下内容:

>>> heading = document.add_heading("Title", 0)
>>> title_style = heading.style
>>> title_style.font.name = "Times New Roman"
>>> title_style.element.xml
<w:style xmlns:w=... w:type="paragraph" w:styleId="Title">
  <w:name w:val="Title"/>
  <w:basedOn w:val="Normal"/>
  <w:next w:val="Normal"/>
  <w:link w:val="TitleChar"/>
  <w:uiPriority w:val="10"/>
  <w:qFormat/>
  <w:rsid w:val="00FC693F"/>
  <w:pPr>
    <w:pBdr>
      <w:bottom w:val="single" w:sz="8" w:space="4" w:color="4F81BD" w:themeColor="accent1"/>
    </w:pBdr>
    <w:spacing w:after="300" w:line="240" w:lineRule="auto"/>
    <w:contextualSpacing/>
  </w:pPr>
  <w:rPr>
    <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia"
              w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi"
              w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
    <w:color w:val="17365D" w:themeColor="text2" w:themeShade="BF"/>
    <w:spacing w:val="5"/>
    <w:kern w:val="28"/>
    <w:sz w:val="52"/>
        <w:szCs w:val="52"/>
  </w:rPr>
</w:style>
  • 从中我们可以看到很多有趣的项目,但我们目前的重点可以限于 元素:
>>> title_style.element.rPr.rFonts.xml
<w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia"
          w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi"
          w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>

我们可以看到“Times New Roman”确实已应用于两种字体设置,但标题仍然出现在 Calibri 中,而这恰好是“majorHAnsi”映射的内容。

要跳转到解决方案,如果我们将 w:asciiTheme 字体名称设置为“Times New Roman”,标题将根据需要显示:

from docx.oxml.ns import qn

rFonts = title_style.element.rPr.rFonts
rFonts.set(qn("w:asciiTheme"), "Times New Roman")

我希望同样的程序也适用于其他标题样式。

请注意,如果您要“从头开始”生成文档而不是编辑现有文档,则从已具有所需样式的空白文档开始可能会更容易:

© www.soinside.com 2019 - 2024. All rights reserved.