# -*- coding: utf-8 -*- import sys from docx import Document from docx.shared import Pt, Cm, RGBColor from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING from docx.enum.table import WD_TABLE_ALIGNMENT from docx.enum.section import WD_SECTION from docx.oxml.ns import qn from docx.oxml import OxmlElement import docx.opc.constants sys.stdout.reconfigure(encoding="utf-8") OUT = r"C:\Users\aroun\Desktop\在线考试系统\在线考试系统开源方案调研与论文写作参考.docx" doc = Document() # ---------- page setup ---------- sec = doc.sections[0] sec.page_width = Cm(21.0) sec.page_height = Cm(29.7) sec.top_margin = Cm(2.54) sec.bottom_margin = Cm(2.54) sec.left_margin = Cm(2.8) sec.right_margin = Cm(2.8) TEXT_W = 21.0 - 2.8 * 2 # 15.4 cm # ---------- styles ---------- def set_cn_font(style_or_run, name_cn, name_ascii=None, size=None, bold=None, color=None): f = style_or_run.font f.name = name_ascii or name_cn if size is not None: f.size = Pt(size) if bold is not None: f.bold = bold if color is not None: f.color.rgb = color el = style_or_run.element if hasattr(style_or_run, "element") else style_or_run._element rPr = el.get_or_add_rPr() rFonts = rPr.find(qn("w:rFonts")) if rFonts is None: rFonts = OxmlElement("w:rFonts") rPr.append(rFonts) rFonts.set(qn("w:ascii"), name_ascii or name_cn) rFonts.set(qn("w:hAnsi"), name_ascii or name_cn) rFonts.set(qn("w:eastAsia"), name_cn) normal = doc.styles["Normal"] set_cn_font(normal, "宋体", "Times New Roman", 10.5) normal.paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE normal.paragraph_format.space_before = Pt(0) normal.paragraph_format.space_after = Pt(4) BLACK = RGBColor(0, 0, 0) h1 = doc.styles["Heading 1"] set_cn_font(h1, "黑体", "Times New Roman", 16, True, BLACK) h1.paragraph_format.space_before = Pt(18) h1.paragraph_format.space_after = Pt(8) h2 = doc.styles["Heading 2"] set_cn_font(h2, "黑体", "Times New Roman", 13, True, BLACK) h2.paragraph_format.space_before = Pt(14) h2.paragraph_format.space_after = Pt(6) h3 = doc.styles["Heading 3"] set_cn_font(h3, "黑体", "Times New Roman", 11, True, BLACK) h3.paragraph_format.space_before = Pt(10) h3.paragraph_format.space_after = Pt(4) # ---------- helpers ---------- def add_hyperlink(paragraph, url, text, size=9, bold=False): part = paragraph.part r_id = part.relate_to(url, docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK, is_external=True) hyperlink = OxmlElement("w:hyperlink") hyperlink.set(qn("r:id"), r_id) new_run = OxmlElement("w:r") rPr = OxmlElement("w:rPr") rFonts = OxmlElement("w:rFonts") rFonts.set(qn("w:ascii"), "Consolas") rFonts.set(qn("w:hAnsi"), "Consolas") rFonts.set(qn("w:eastAsia"), "宋体") rPr.append(rFonts) sz = OxmlElement("w:sz"); sz.set(qn("w:val"), str(int(size * 2))); rPr.append(sz) szcs = OxmlElement("w:szCs"); szcs.set(qn("w:val"), str(int(size * 2))); rPr.append(szcs) if bold: b = OxmlElement("w:b"); rPr.append(b) color = OxmlElement("w:color"); color.set(qn("w:val"), "1F4E79"); rPr.append(color) u = OxmlElement("w:u"); u.set(qn("w:val"), "single"); rPr.append(u) new_run.append(rPr) t = OxmlElement("w:t") t.text = text t.set(qn("xml:space"), "preserve") new_run.append(t) hyperlink.append(new_run) paragraph._p.append(hyperlink) return hyperlink def shade(cell, hexcolor): tcPr = cell._tc.get_or_add_tcPr() shd = OxmlElement("w:shd") shd.set(qn("w:val"), "clear") shd.set(qn("w:color"), "auto") shd.set(qn("w:fill"), hexcolor) tcPr.append(shd) def cell_margins(table, top=60, bottom=60, left=90, right=90): tblPr = table._tbl.tblPr mar = OxmlElement("w:tblCellMar") for tag, val in (("top", top), ("left", left), ("bottom", bottom), ("right", right)): el = OxmlElement("w:" + tag) el.set(qn("w:w"), str(val)) el.set(qn("w:type"), "dxa") mar.append(el) tblPr.append(mar) def repeat_header(row): trPr = row._tr.get_or_add_trPr() el = OxmlElement("w:tblHeader") el.set(qn("w:val"), "true") trPr.append(el) def cant_split(row): trPr = row._tr.get_or_add_trPr() el = OxmlElement("w:cantSplit") el.set(qn("w:val"), "true") trPr.append(el) def set_cell_text(cell, text, size=9, bold=False, align=None, color=None): cell.text = "" p = cell.paragraphs[0] p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.SINGLE p.paragraph_format.space_before = Pt(0) p.paragraph_format.space_after = Pt(0) if align is not None: p.alignment = align run = p.add_run(text) set_cn_font(run, "宋体", "Times New Roman", size, bold, color) def make_table(headers, rows, widths, link_col=None, font=8.5, head_font=8.5): table = doc.add_table(rows=1, cols=len(headers)) table.style = "Table Grid" table.alignment = WD_TABLE_ALIGNMENT.CENTER table.autofit = False cell_margins(table) hdr = table.rows[0] repeat_header(hdr) cant_split(hdr) for i, h in enumerate(headers): c = hdr.cells[i] c.width = Cm(widths[i]) shade(c, "D9D9D9") set_cell_text(c, h, head_font, True, WD_ALIGN_PARAGRAPH.CENTER) for r in rows: row = table.add_row() cant_split(row) for i, val in enumerate(r): c = row.cells[i] c.width = Cm(widths[i]) if link_col is not None and i == link_col: c.text = "" p = c.paragraphs[0] p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.SINGLE p.paragraph_format.space_before = Pt(0) p.paragraph_format.space_after = Pt(0) add_hyperlink(p, val[1], val[0], size=font - 0.5) else: set_cell_text(c, val, font) # force column widths on every cell (Word honours cell-level w) for row in table.rows: for i, c in enumerate(row.cells): c.width = Cm(widths[i]) return table def para(text, size=10.5, bold=False, indent=True, space_after=4, align=None, color=None, first_indent=True): p = doc.add_paragraph() p.paragraph_format.space_after = Pt(space_after) if align is not None: p.alignment = align if indent and first_indent: p.paragraph_format.first_line_indent = Pt(21) run = p.add_run(text) set_cn_font(run, "宋体", "Times New Roman", size, bold, color) return p def bullet(text, size=10.5, level=0): p = doc.add_paragraph(style="List Bullet") p.paragraph_format.left_indent = Cm(0.75 + 0.6 * level) p.paragraph_format.first_line_indent = Cm(-0.4) p.paragraph_format.space_after = Pt(2) run = p.add_run(text) set_cn_font(run, "宋体", "Times New Roman", size) return p def numitem(n, title, text, size=10.5): p = doc.add_paragraph() p.paragraph_format.space_after = Pt(4) p.paragraph_format.left_indent = Cm(0.75) p.paragraph_format.first_line_indent = Cm(-0.75) r1 = p.add_run("%s " % n) set_cn_font(r1, "宋体", "Times New Roman", size, True) r2 = p.add_run(title) set_cn_font(r2, "黑体", "Times New Roman", size, True) if text: r3 = p.add_run(text) set_cn_font(r3, "宋体", "Times New Roman", size) return p def caption(text): p = doc.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(6) p.paragraph_format.space_after = Pt(3) run = p.add_run(text) set_cn_font(run, "黑体", "Times New Roman", 9, True) return p def note(text): p = doc.add_paragraph() p.paragraph_format.space_before = Pt(2) p.paragraph_format.space_after = Pt(10) p.paragraph_format.left_indent = Cm(0.2) run = p.add_run(text) set_cn_font(run, "楷体", "Times New Roman", 9.5, False, RGBColor(0x40, 0x40, 0x40)) return p def quote_block(lines): for ln in lines: p = doc.add_paragraph() p.paragraph_format.left_indent = Cm(0.9) p.paragraph_format.right_indent = Cm(0.4) p.paragraph_format.space_after = Pt(4) p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE run = p.add_run(ln) set_cn_font(run, "楷体", "Times New Roman", 10) return # footer page number footer = sec.footer fp = footer.paragraphs[0] fp.alignment = WD_ALIGN_PARAGRAPH.CENTER run = fp.add_run() fld1 = OxmlElement("w:fldChar"); fld1.set(qn("w:fldCharType"), "begin") instr = OxmlElement("w:instrText"); instr.set(qn("xml:space"), "preserve"); instr.text = " PAGE " fld2 = OxmlElement("w:fldChar"); fld2.set(qn("w:fldCharType"), "end") run._r.append(fld1); run._r.append(instr); run._r.append(fld2) set_cn_font(run, "宋体", "Times New Roman", 9) print("setup ok") doc.save(OUT) print("saved skeleton")