tkinter开发word模板小桌面工具

0 前言:

​ 本文利用python中的GUI库tkinter开发word模板桌面小工具,主要功能是在python编辑word模板的条件下,利用excel文件上传的方式,生成目标word文档。小工具运行打开后,如下图:
在这里插入图片描述

​ 该工具这里设计了3个一级菜单:文件、配置修改、README。其中,一级菜单“文件”下有3个二级菜单:新建、打开、退出,这里“新建”二级菜单下包含2个三级菜单:数据报告、其他;一级菜单“配置修改”下有3个二级菜单:默认保存位置、WINWORD.EXE地址、其他配置;一级菜单“README”下有2个二级菜单:模板信息、系统信息,这里“模板信息”二级菜单下包含2个三级菜单:数据报告README、其他模板README。

​ 以上就是小工具的整体结构,详细信息请参考2.1 运行文件。

1 脚本设计:

​ 小工具设计了2+个代码文件,“1”是运行文件和“1+”是文档模板文件,可以针对需求自行设计需要的模板文件,添加进运行文件即可运行操作。

​ 其中,2.1 运行文件部分,有详细的tkinter实现代码,这里解决了多级菜单、菜单切换、文本输入接收、文件上传、打开文档等功能的实现。2.2 文档模板文件部分,是可以独立运行的代码,添加main函数即可,这里解决了excel文件的读取、word文档的写入、word文档字体和段落控制、表格添加、页码添加等功能的实现。

2 详细脚本:
2.1 运行文件

​ 文件名:master_system.py

​ 这里解决了多级菜单、菜单切换、文本输入接收、文件上传、打开文档等功能的实现。

# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from tkinter import *
from mask_sjbg_report import *
import subprocess
from ttkbootstrap import Style

class fm_sys(tk.Tk):
# 继承父类tk.TK
    def __init__(self):
        super().__init__()
        style = Style(theme="cosmo")
        window = style.master
        self.title("模板文档生成系统")
        self.geometry("550x400")

        # 创建两个Frame
        self.Frame_home = tk.Frame(window)
        self.frame_report = tk.Frame(window)
        self.frame_winword = tk.Frame(window)

        # winword.exe的默认地址
        self.winword = r"C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE"

    # 打开提示页面
    def home_page(self):
        # 在Frame_home中添加控件
        tk.Label(self.Frame_home, text=
        "欢迎来到模板文档生成系统!\n "
        "Welcome to Mask Make System!\n"
        "tips:\n"
        "   这里是小贴士!"
                 ).grid(row=3, column=3)
        # 将Frame_home添加到主窗口中
        self.Frame_home.grid(row=4, column=3, padx=10, pady=10)


    # #############################  数据 报告  #############################
    # 1-1-1 文件_新建_数据报告
    def report_page(self):
        try:
            # 添加标签_汇总信息
            sum_label = tk.Label(self.frame_report, text='汇总信息', width=15, height=2).grid(row=2, column=1)

            # 添加标签_整体概况
            all_label = tk.Label(self.frame_report, text='整体概况', width=15, height=2).grid(row=3, column=1)

            # 添加标签_指标清单
            rule_label = tk.Label(self.frame_report, text='指标清单', width=15, height=2).grid(row=4, column=1)

            # 添加标签_表清单
            table_label = tk.Label(self.frame_report, text='表清单', width=15, height=2).grid(row=5, column=1)

            # 添加标签_字段清单
            column_label = tk.Label(self.frame_report, text='字段清单', width=15, height=2).grid(row=6, column=1)
            # 添加标签_报告名称
            dept_label = tk.Label(self.frame_report, text='报告名称', width=15, height=2).grid(row=7, column=1)

            # 添加输入框_汇总信息
            self.es = tk.Entry(self.frame_report, width=40)
            self.es.grid(row=2, column=2, columnspan=1, padx=5, pady=5)

            # 添加输入框_整体概况
            self.ea = tk.Entry(self.frame_report, width=40)
            self.ea.grid(row=3, column=2, columnspan=1, padx=5, pady=5)

            # 添加输入框_指标清单
            self.er = tk.Entry(self.frame_report, width=40)
            self.er.grid(row=4, column=2, columnspan=1, padx=5, pady=5)

            # 添加输入框_表清单
            self.et = tk.Entry(self.frame_report, width=40)
            self.et.grid(row=5, column=2, columnspan=1, padx=5, pady=5)

            # 添加输入框_字段清单
            self.ec = tk.Entry(self.frame_report, width=40)
            self.ec.grid(row=6, column=2, columnspan=1, padx=5, pady=5)

            # 添加输入框_报告名称
            entry_var = tk.StringVar()
            self.e_dept = tk.Entry(self.frame_report,  textvariable=entry_var, width=40)
            self.e_dept.grid(row=7, column=2, columnspan=1, padx=5, pady=5)

            # 添加按钮_汇总信息
            b_sum_text = tk.Button(self.frame_report, text='汇总信息上传', width=10, height=2, command=self.all_sum_path)
            b_sum_text.grid(row=2, column=4)

            # 添加按钮_整体概况
            b_all_text = tk.Button(self.frame_report, text='整体概况上传', width=10, height=2, command=self.all_file_path)
            b_all_text.grid(row=3, column=4)

            # 添加按钮_指标清单
            b_rule_text = tk.Button(self.frame_report, text='指标清单上传', width=10, height=2, command=self.all_rule_path)
            b_rule_text.grid(row=4, column=4)

            # 添加按钮_表清单
            b_table_text = tk.Button(self.frame_report, text='表清单上传', width=10, height=2, command=self.all_table_path)
            b_table_text.grid(row=5, column=4)

            # 添加按钮_字段清单
            b_column_text = tk.Button(self.frame_report, text='字段清单上传', width=10, height=2, command=self.all_column_path)
            b_column_text.grid(row=6, column=4)

            # 添加按钮_报告名称输入确认
            b_clear_text = tk.Button(self.frame_report, text='确认', width=10, height=2, command=self.get_dept)
            b_clear_text.grid(row=7, column=4, sticky=W, padx=5, pady=20)

            # 添加按钮_生成word
            b_product_text = tk.Button(self.frame_report, text='生成word', width=10, height=2,
                                       command=self.word_make_messagebox)
            b_product_text.grid(row=8, column=2, sticky=W, padx=5, pady=20)

            # 添加按钮_查看
            b_clear_text = tk.Button(self.frame_report, text='查看word', width=10, height=2,
                                     command=self.open_this_word)
            b_clear_text.grid(row=8, column=4, sticky=W, padx=5, pady=20)

            # 切换界面
            self.Frame_home.grid_forget()  # 隐藏第home个界面
            self.frame_winword.grid_forget()  # 隐藏第3个frame_winword界面
            self.frame_report.grid(row=0, column=0, padx=10, pady=10)  # 显示第二个界面
        except Exception as e:
            print(e)


    def all_sum_path(self):  # 获取路径
        try:
            self.es.delete(0, 'end')
            global path_sum
            path_sum = ''
            path_sum = filedialog.askopenfilename()
            path_sum = path_sum.replace('/', "\\") #通过replace函数替换绝对文件地址中的/来使文件可被程序读取 #注意:\\转义后为\,所以\\\\转义后为\\
            self.es.insert('insert', path_sum)
        except Exception as e:
            if 'is not defined' in e:
                self.warnning_not_path()
            else:
                print(e)


    def all_file_path(self):  # 获取路径
        try:
            self.ea.delete(0, 'end')
            global path_all
            path_all = ''
            path_all = filedialog.askopenfilename()
            path_all = path_all.replace('/', "\\") #通过replace函数替换绝对文件地址中的/来使文件可被程序读取 #注意:\\转义后为\,所以\\\\转义后为\\
            self.ea.insert('insert', path_all)
        except Exception as e:
            if 'is not defined' in e:
                self.warnning_not_path()
            else:
                print(e)


    def all_rule_path(self):  # 获取路径
        try:
            self.er.delete(0, 'end')
            global path_rule
            path_rule = ''
            path_rule = filedialog.askopenfilename()
            path_rule = path_rule.replace('/', "\\") #通过replace函数替换绝对文件地址中的/来使文件可被程序读取 #注意:\\转义后为\,所以\\\\转义后为\\
            self.er.insert('insert', path_rule)
        except Exception as e:
            if 'is not defined' in e:
                self.warnning_not_path()
            else:
                print(e)


    def all_table_path(self):  # 获取路径
        try:
            self.et.delete(0, 'end')
            global path_table
            path_table = ''
            path_table = filedialog.askopenfilename()
            path_table = path_table.replace('/', "\\") #通过replace函数替换绝对文件地址中的/来使文件可被程序读取 #注意:\\转义后为\,所以\\\\转义后为\\
            self.et.insert('insert', path_table)
        except Exception as e:
            if 'is not defined' in e:
                self.warnning_not_path()
            else:
                print(e)


    def all_column_path(self):  # 获取路径
        try:
            self.ec.delete(0, 'end')
            global path_column
            path_column = ''
            path_column = filedialog.askopenfilename()
            path_column = path_column.replace('/', "\\") #通过replace函数替换绝对文件地址中的/来使文件可被程序读取 #注意:\\转义后为\,所以\\\\转义后为\\
            self.ec.insert('insert', path_column)
        except Exception as e:
            if 'is not defined' in e:
                self.warnning_not_path()
            else:
                print(e)

    # 获取输入框内容
    def get_dept(self):
        try:
            global dept_value
            dept_value = self.e_dept.get()
        except Exception as e:
            if 'is not defined' in e:
                self.warnning_not_path()
            else:
                print(e)


    # 数据报告生成
    def word_product(self):  #
        try:
            msrt = mask_sjbg_report()
            msrt.read_sheet1(path_sum)
            msrt.read_sheet2(path_all)
            msrt.read_sheet3(path_rule)
            msrt.read_sheet4(path_table)
            msrt.read_sheet5(path_column)
            msrt.msrt(dept_value)
        except Exception as e:
            print(e)

    # #############################  打开  #############################
    # 打开文档
    def open_word(self):
        try:
            path_name = filedialog.askopenfilename()
            path_name = path_name.replace('/', "\\") #通过replace函数替换绝对文件地址中的/来使文件可被程序读取 #注意:\\转义后为\,所以\\\\转义后为\\

            word_path = self.winword  # Word程序的路径
            document_path = r"{}".format(path_name)  # Word文档的路径

            subprocess.Popen([word_path, document_path])
        except OSError:
            print("无法找到Word程序或打开文档失败。")
            self.warnning_win()


    # 打开生成报告
    def open_this_word(self):
        try:
            word_path = self.winword
            file_name = '附件:数据报告{}.docx'.format(dept_value)
            document_path = r"{}".format(file_name)  # Word文档的路径
            subprocess.Popen([word_path, document_path])
        except:
            print("无法找到Word程序或打开文档失败。")
            self.warnning_win()

    # #############################  配置  #############################

    def winword_dir(self):
        try:
            # 在frame_winword中添加控件
            tk.Label(self.frame_winword, text=
            "更改winword地址"
                     ).grid(row=2, column=1)

            # 添加输入框_winword地址
            self.ew = tk.Entry(self.frame_winword, width=30)
            self.ew.grid(row=2, column=2, columnspan=1, padx=5, pady=5)

            # 添加按钮_winword地址
            b_select_text = tk.Button(self.frame_winword, text='查询地址', width=10, height=2, command=self.winword_path)
            b_select_text.grid(row=2, column=3)

            # 添加按钮_保存
            b_save_text = tk.Button(self.frame_winword, text='保存', width=10, height=2, command=self.save_winword_path)
            b_save_text.grid(row=3, column=2, sticky=W, padx=5, pady=20)

            # 添加按钮_重置
            b_truncate_text = tk.Button(self.frame_winword, text='重置', width=10, height=2, command=self.truncate_winword_path)
            b_truncate_text.grid(row=3, column=3, sticky=W, padx=5, pady=20)

            # 切换界面
            self.Frame_home.grid_forget()  # 隐藏第1个Frame_home界面
            self.frame_report.grid_forget()  # 隐藏第2个frame_report界面
            self.frame_winword.grid(row=0, column=0, padx=10, pady=10)  # 显示第三个界面
        except Exception as e:
            print(e)

    def winword_path(self):  # 获取路径
        try:
            self.ew.delete(0, 'end')
            global path_winword_exe
            path_winword_exe = filedialog.askopenfilename()
            path_winword_exe = path_winword_exe.replace('/', "\\") #通过replace函数替换绝对文件地址中的/来使文件可被程序读取 #注意:\\转义后为\,所以\\\\转义后为\\
            self.ew.insert('insert', path_winword_exe)
            # print(type(path_winword_exe))
        except Exception as e:
            print(e)

    def save_winword_path(self):
        try:
            result = messagebox.askquestion(title='保存确认',
                                   message='是否保存新地址!')  # 信息确认弹窗 是 Ture或 否 False
            if result == 'yes':
                self.winword = r"{}".format(path_winword_exe)
                print("新地址已经保存:{}".format(self.winword))
        except Exception as e:
            print(e)

    def truncate_winword_path(self):
        try:
            result = messagebox.askquestion(title='重置确认',
                                            message='是否重置已有地址!')  # 信息确认弹窗 是 Ture或 否 False
            if result == 'yes':
                self.winword = ''
                self.ew.delete(0, "end")
                print("已有地址已经重置")
        except Exception as e:
            print(e)


    def clear_input(self):  # 获取路径
        pass

    # 其他页面
    def do_job(self):
        pass

    # #############################  弹窗   #############################
    # 警告弹窗
    def warnning_not_path(self):
        result = messagebox.showwarning(title='错误',
                                        message='请输入路径信息!')  #

    # 警告弹窗
    def warnning_win(self):
        result = messagebox.showwarning(title='错误',
                                        message='无法找到Word程序或打开文档失败!')  #


    # word生成确认弹窗
    def word_make_messagebox(self):
        try:
            result = messagebox.askquestion(title='文档生成确认',
                                   message='请再次生成确认!')  # 信息确认弹窗 是 Ture或 否 False
            if result == 'yes':
                self.word_product()
        except Exception as e:
            print(e)

    # 退出确认弹窗
    def quit_messagebox(self):
        try:
            result = messagebox.askquestion(title='退出确认',
                                   message='确定要退出吗?')  # 信息确认弹窗 是 Ture或 否 False
            if result == 'yes':
                self.quit()
        except Exception as e:
            print(e)

    # #############################  主界面   #############################

    # 00 主界面
    def rootpage(self):
        try:
            # 创建菜单
            menubar = tk.Menu(self)
            # 菜单一
            filemenu = tk.Menu(menubar, tearoff=0)
            # 1 一级菜单
            menubar.add_cascade(label='文件', menu=filemenu)

            # 新建子菜单
            submenu = tk.Menu(filemenu)
            # 1-1 二级菜单
            filemenu.add_cascade(label='新建', menu=submenu, underline=0)
            # 1-1-1 三级菜单
            submenu.add_command(label='数据报告', command=self.report_page)
            submenu.add_command(label='其他', command=self.do_job)

            # 1-2 二级菜单
            filemenu.add_command(label='打开', command=self.open_word)
            filemenu.add_separator()  # 分割线
            # 1-3 二级菜单
            filemenu.add_command(label='退出', command=self.quit_messagebox)

            # 菜单二
            editmenu = tk.Menu(menubar, tearoff=0)
            # 2 一级菜单
            menubar.add_cascade(label='配置修改', menu=editmenu)
            # 2-1 二级菜单
            editmenu.add_command(label='默认保存地址', command=self.do_job)

            # 2-2 二级菜单
            editmenu.add_command(label='WINWORD.EXE地址', command=self.winword_dir)

            # 2-3 其他配置
            editmenu.add_command(label='其他配置', command=self.do_job)

            # 菜单三
            readmemenu = tk.Menu(menubar, tearoff=0)
            # 3 一级菜单
            menubar.add_cascade(label='README', menu=readmemenu)

            # 三级菜单
            # 模板信息-子菜单
            submenu2 = tk.Menu(readmemenu)
            # 3-1 二级菜单
            readmemenu.add_cascade(label='模板信息', menu=submenu2, underline=0)
            # 3-1-1级菜单
            submenu2.add_command(label='数据报告README', command=self.do_job)
            # 3-1-2级菜单
            submenu2.add_command(label='其他模板README', command=self.do_job)

            # 3-2 二级菜单
            readmemenu.add_command(label='系统信息', command=self.do_job)

            self.config(menu=menubar)
            # #显示出来
            self.mainloop()
        except Exception as e:
            print(e)

if __name__ == "__main__":
    app = fm_sys()
    app.home_page()
    app.rootpage()
2.2 文档模板文件

​ 文件名:mask_sjbg_report.py

​ 这里解决了excel文件的读取、word文档的写入、word文档字体和段落控制、表格添加、页码添加等功能的实现。

# -*- coding: utf-8 -*-
"""
-- 数据报告
-- 新增变量
-- 删除变量
-------------------------------------------------------------------------
"""
#################################
# 01 读取excel表格数据常用操作
#################################
import xlrd
from docx import Document
from docx.enum.section import WD_SECTION_START, WD_ORIENTATION
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.enum.text import WD_LINE_SPACING, WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
from docx.shared import Pt, RGBColor, Cm, Inches
import datetime
from docx.oxml import OxmlElement
import numpy as np
import win32com
from win32com import client
import sys
import time


class mask_  报告_report():

    def __init__(self):
        # 创建docx对象
        self.document = Document()
        self.var_sheet1 = ''    # 报告汇总信息
        self.var_sheet2 = ''    # 报告整体概况
        self.var_sheet3 = ''    # 报告指标清单
        self.var_sheet4 = ''    # 报告表清单
        self.var_sheet5 = ''    # 报告字段清单
        self.file_path = ''     # 文档保存路径

    # mysql下的excel读取   ######################## 生成word  ########################
    # 读取报告的文本汇总
    def read_sheet1(self, var_sheet1_dir):
        # -- 输入参数1:var_sheet1_dir,  报告的汇总信息
        # 01 读取  报告的汇总信息
        # # 读取文本汇总
        path_sum_excel = xlrd.open_workbook(var_sheet1_dir)
        table_sum = path_sum_excel.sheets()[0]
        # 返回某行中所有单元格的数据组成的列表
        self.var_sheet1 = table_sum.cell_value(rowx=1, colx=0)

        now1 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print('>>>{} 已经读取到汇总信息excel'.format(now1))

    # 读取报告的整体概况
    def read_sheet2(self, var_sheet2_dir):
        # -- 输入参数1:var_sheet1_dir,  报告的整体概况地址
        # 02 读取  报告的整体概况
        try:
            path_all_excel = xlrd.open_workbook(var_sheet2_dir).sheets()[0]
            num_rows = path_all_excel.nrows  # 获取该sheet中的有效行数
            num_cols = path_all_excel.ncols  # 获取该sheet中的有效列数
            # 建立矩阵存储获取内容
            outside_list = []
            rule_type = ['A', 'B', 'C', 'D', 'E', 'F']
            rule_type_tmp = rule_type

            for i in range(1, num_rows):
                row_list = []
                for j in range(num_cols):
                    if (j == 4 or j == 5) and path_all_excel.cell_value(rowx=i, colx=j) != '':
                        xh_num = path_all_excel.cell_value(rowx=i, colx=j)
                        row_list.append(int(xh_num))  # 返回单元格中的数据
                    else:
                        row_list.append(path_all_excel.cell_value(rowx=i, colx=j))  # 返回单元格中的数据
                rule_type_tmp.remove(row_list[0])
                outside_list.append(row_list)
            for i in range(len(rule_type_tmp)):
                append_row = [rule_type_tmp[i], '/', '/', '/', '/', '/']
                outside_list.append(append_row)
            # 返回某行中所有单元格的数据组成的列表
            self.var_sheet2 = outside_list
            now1 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            print('>>>{} 已经读取到整体概况excel'.format(now1))
            print(outside_list)
        except Exception as e:
            print(e)

        # 读取报告的指标清单
    def read_sheet3(self,  var_sheet3_dir):
        # -- 输入参数1:var_sheet3_dir,  报告的指标清单地址
        # 03 读取  报告的指标清单
        path_all_excel = xlrd.open_workbook(var_sheet3_dir).sheets()[0]
        num_rows = path_all_excel.nrows  # 获取该sheet中的有效行数
        num_cols = path_all_excel.ncols  # 获取该sheet中的有效列数
        # 建立矩阵存储获取内容
        outside_list = []

        for i in range(1, num_rows):
            row_list = []
            for j in range(num_cols):
                    row_list.append(path_all_excel.cell_value(rowx=i, colx=j))  # 返回单元格中的数据
            outside_list.append(row_list)
        # 返回某行中所有单元格的数据组成的列表
        self.var_sheet3 = outside_list
        now1 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print('>>>{} 已经读取到指标清单excel'.format(now1))
        print(outside_list)

        # 读取报告的表清单
    def read_sheet4(self,  var_sheet4_dir):
        # -- 输入参数1:var_sheet3_dir,  报告的表清单地址
        # 03 读取  报告的表清单
        path_all_excel = xlrd.open_workbook(var_sheet4_dir).sheets()[0]
        num_rows = path_all_excel.nrows  # 获取该sheet中的有效行数
        num_cols = path_all_excel.ncols  # 获取该sheet中的有效列数
        # 建立矩阵存储获取内容
        outside_list = []

        for i in range(1, num_rows):
            row_list = []
            for j in range(num_cols):
                    row_list.append(path_all_excel.cell_value(rowx=i, colx=j))  # 返回单元格中的数据
            outside_list.append(row_list)
        # 返回某行中所有单元格的数据组成的列表
        self.var_sheet4 = outside_list
        now1 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print('>>>{} 已经读取到表清单excel'.format(now1))
        print(outside_list)

        # 读取报告的字段清单
    def read_sheet5(self,  var_sheet5_dir):
        # -- 输入参数1:var_sheet3_dir,  报告的字段清单地址
        # 03 读取报告的字段清单
        path_all_excel = xlrd.open_workbook(var_sheet5_dir).sheets()[0]
        num_rows = path_all_excel.nrows  # 获取该sheet中的有效行数
        num_cols = path_all_excel.ncols  # 获取该sheet中的有效列数
        # 建立矩阵存储获取内容
        outside_list = []

        for i in range(1, num_rows):
            row_list = []
            for j in range(num_cols):
                    row_list.append(path_all_excel.cell_value(rowx=i, colx=j))  # 返回单元格中的数据
            outside_list.append(row_list)
        # 返回某行中所有单元格的数据组成的列表
        self.var_sheet5 = outside_list
        now1 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print('>>>{} 已经读取到字段清单excel'.format(now1))
        print(outside_list)



    # 数据  报告生成   ######################## 生成word  ########################
    def msrt(self,file_title):  #
        # 02 创建文档
        # 附件
        par_01_fj = self.document.add_paragraph('')
        par_01_fj.line_spacing_rule = WD_LINE_SPACING.SINGLE  # 单倍行距

        run_par_01_fj = par_01_fj.add_run('报告')
        run_par_01_fj.font.name = ''
        run_par_01_fj.element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')  # 设置中文是宋体
        run_par_01_fj.font.size = Pt(16)  # 字号大小

        # 文章标题
        par_02_title = self.document.add_paragraph('')
        par_02_title.line_spacing_rule = WD_LINE_SPACING.SINGLE  # 单倍行距
        par_02_title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中对齐
        run_par_02_title = par_02_title.add_run('{}数据报告'.format(file_title))
        run_par_02_title.font.size = Pt(22)  # 字号大小
        run_par_02_title.font.name = ''
        run_par_02_title.element.rPr.rFonts.set(qn('w:eastAsia'), '方正小标宋简体')  # 设置字体

        # 标题一
        self.add_one_title('一、数据指标情况')

        # 一:段落1.1
        self.add_one_par('1.数据问题')

        # 一:段落1.2  ########################################  self.var_sheet1   ########################################

        self.add_one_par(('数据报告汇总信息:'
                                                    '{}'.format(self.var_sheet1)))
        # 一:段落2.1
        self.add_one_par('整体概况如下:')

        # 一:段落2.2 表格1 ########################################  self.var_sheet2   ########################################
        table1_data = self.var_sheet2
        np_var_sheet2 = np.array(self.var_sheet2)   # np_var_sheet2
        rows = np_var_sheet2.shape[0]  # 输出行
        cols = np_var_sheet2.shape[1]  # 输出列
        table1 = self.document.add_table(rows=rows+2, cols=cols+1, style='Table Grid')
        table1.alignment = WD_TABLE_ALIGNMENT.CENTER
        # 表头
        header1 = ['序号','  评估指标','指标数','表数量','字段数量','数据量','正常数据量']
        for i in range(len(header1)):
            # table1.cell(0, i).text = header1[i]
            self.add_heeder_sheet0(table1, i, header1[i])

        # 表内容
        xh_num = 0
        for i in range(1,rows+1):
            xh_num += 1
            for j in range(cols+1):
                if j == 0:      # 序号
                    self.add_one_sheet0(table1, i, j, xh_num)
                else:           # 非序号内容
                    self.add_one_sheet0(table1, i, j, table1_data[i-1][j-1])

        # 表汇总行
        # 合并单元格
        par_table1 = table1.cell(rows + 1, 0).paragraphs[0]
        table1.cell(rows + 1, 0).vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER  # 垂直居中
        par_table1.paragraph_format.alignment = WD_TABLE_ALIGNMENT.CENTER  # 水平居中
        run_par_07_table1 = par_table1.add_run("合计(去重后)")
        run_par_07_table1.font.size = Pt(12)
        run_par_07_table1.font.name = '仿宋_GB2312'
        run_par_07_table1.element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')  # 设置中文是宋体
        table1.cell(rows + 1,0).merge(table1.cell(rows + 1,1))
        table1.cell(rows + 1, 0).vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER  # 垂直居中

        # 汇总行添加信息
        jhgz_row = xlrd.open_workbook(var_sheet3_dir).sheets()[0]
        num_jhgz_row = jhgz_row.nrows  # 获取该sheet中的有效行数
        num_list, get_num1, get_num2 = self.num_get(self.var_sheet1)
        self.add_one_sheet0(table1, rows + 1, 2, num_jhgz_row-1)  # 
        self.add_one_sheet0(table1, rows + 1, 3, num_list[0])     # 
        self.add_one_sheet0(table1, rows + 1, 4, num_list[1])     # 
        self.add_one_sheet0(table1, rows + 1, 5, get_num1)        # 
        self.add_one_sheet0(table1, rows + 1, 6, get_num2)        # 

        # 标题 二
        self.add_one_title('二、数据指标清单')

        # 二:段落2.1
        self.add_one_par('本报告共涉及{}项数据指标:'.format(num_jhgz_row-1))

        # 二:段落2.2 表格2 ########################################  self.var_sheet3   ########################################
        table2_data = self.var_sheet3
        np_var_sheet3 = np.array(self.var_sheet3)   # np_var_sheet3
        rows = np_var_sheet3.shape[0]  # 输出行
        cols = np_var_sheet3.shape[1]  # 输出列
        table2 = self.document.add_table(rows=rows+1, cols=cols+1, style='Table Grid')
        table2.alignment = WD_TABLE_ALIGNMENT.CENTER
        # 二:段落2.2 表头
        header2 = ['序号','指标','指标代码','行业标准','部门标准','指标描述']
        for i in range(len(header2)):
            # table2.cell(0, i).text = header2[i]
            self.add_heeder_sheet0( table2, i, header2[i])

        # 二:段落2.2  表内容
        xh_num = 0
        for i in range(1,rows+1):
            xh_num += 1
            for j in range(cols+1):
                if j == 0:      # 序号
                    self.add_one_sheet0(table2, i, j, xh_num)
                else:           # 非序号内容
                    self.add_one_sheet0(table2, i, j, table2_data[i-1][j-1])

        # 二:段落2.3
        self.add_one_par('具体指标结果详见字段清单(附件B)。')

        # 分节
        default_section = self.document.sections[0]  # 获取默认节
        new_section_1 = self.document.add_section(start_type=WD_SECTION_START.NEW_PAGE)  # 新增一个节,类型是新页的分隔符
        new_section_1.start_type = WD_SECTION_START.EVEN_PAGE

        new_section_1.orientation = WD_ORIENTATION.LANDSCAPE  # 改为横向
        # 需要手动互换高度和宽带
        new_section_1.page_width, new_section_1.page_height = new_section_1.page_height, new_section_1.page_width

        # 附件A
        self.add_one_title('附件A')

        # 附件A 标题
        par_08_title = self.document.add_paragraph('')
        par_08_title.line_spacing_rule = WD_LINE_SPACING.SINGLE  # 单倍行距
        par_08_title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中对齐
        run_par_08_title = par_08_title.add_run('报告表清单')
        # run_par_08_title.paragraph_format.space_before = Pt(13)  # 段前30磅
        # run_par_08_title.paragraph_format.space_after = Pt(13)  # 段后15磅
        run_par_08_title.font.size = Pt(20)  # 字号大小
        run_par_08_title.font.name = ''
        run_par_08_title.element.rPr.rFonts.set(qn('w:eastAsia'), '方正小标宋简体')  # 设置字体

        # 附件A 表格3 ########################################  self.var_sheet4   ########################################
        table3_data = self.var_sheet4
        np_var_sheet4 = np.array(self.var_sheet4)   # np_var_sheet3
        rows = np_var_sheet4.shape[0]  # 输出行
        cols = np_var_sheet4.shape[1]  # 输出列
        table3 = self.document.add_table(rows=rows+1, cols=cols+1, style='Table Grid')
        table3.alignment = WD_TABLE_ALIGNMENT.CENTER
        # 附件A 表头
        header3 = ['序号','中文表名','英文表名','总字段数(项)','指标数(项)','关联指标数(个)','总数据量(条)',
                   '正常数据量(条)','合格率','数据库名称','日志表名称']
        for i in range(len(header3)):
            # table2.cell(0, i).text = header2[i]
            self.add_heeder_sheet0(table3, i, header3[i])

        # 附件A  表内容
        xh_num = 0
        for i in range(1,rows+1):
            xh_num += 1
            for j in range(cols+1):
                if j == 0:      # 序号
                    self.add_one_sheet0(table3, i, j, xh_num)
                else:           # 非序号内容
                    self.add_one_sheet0(table3, i, j, table3_data[i-1][j-1])


        # 附件B
        self.document.add_page_break()  # 分页
        self.add_one_title('附件B')

        # 附件B 标题
        par_08_title = self.document.add_paragraph('')
        par_08_title.line_spacing_rule = WD_LINE_SPACING.SINGLE  # 单倍行距
        par_08_title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中对齐
        run_par_08_title = par_08_title.add_run('报告字段清单')
        # run_par_08_title.paragraph_format.space_before = Pt(13)  # 段前30磅
        # run_par_08_title.paragraph_format.space_after = Pt(13)  # 段后15磅
        run_par_08_title.font.size = Pt(20)  # 字号大小
        run_par_08_title.font.name = ''
        run_par_08_title.element.rPr.rFonts.set(qn('w:eastAsia'), '方正小标宋简体')  # 设置字体

        # 附件B 表格4 ########################################  self.var_sheet5   ########################################
        table4_data = self.var_sheet5
        np_var_sheet5 = np.array(self.var_sheet5)   # np_var_sheet3
        rows = np_var_sheet5.shape[0]  # 输出行
        cols = np_var_sheet5.shape[1]  # 输出列
        table4 = self.document.add_table(rows=rows+1, cols=cols+1, style='Table Grid')
        table4.alignment = WD_TABLE_ALIGNMENT.CENTER
        # 附件B 表头
        header4 = ['序号','中文表名','英文表名','总字段数(项)','指标数(项)','关联指标数(个)','总数据量(条)',
                   '正常数据量(条)','合格率']
        for i in range(len(header3)):
            # table2.cell(0, i).text = header2[i]
            if i == 0:  # 序号
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(1)
            elif i == 1:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(2.3)
            elif i == 2:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(2.7)
            elif i == 3:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(1.5)
            elif i == 4:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(2.3)
            elif i == 5:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(2)
            elif i == 6:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(3)
            elif i == 7:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(1.5)
            elif i == 8:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(1.5)
            elif i == 9:  # 非序号内容
                self.add_heeder_sheet0(table4, i, header4[i])
                table4.cell(0, i).width = Cm(1.5)

        # 附件B  表内容
        xh_num = 0
        for i in range(1,rows+1):
            xh_num += 1
            for j in range(cols+1):
                if j == 0:      # 序号
                    self.add_one_sheet0(table4, i, j, xh_num)
                    table4.cell(i, j).width = Cm(1)
                elif j == 1:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(2.3)
                elif j == 2:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(2.7)
                elif j == 3:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(1.5)
                elif j == 4:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(2.3)
                elif j == 5:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(2)
                elif j == 6:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(3)
                elif j == 7:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(1.5)
                elif j == 8:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(1.5)
                elif j == 9:           # 非序号内容
                    self.add_one_sheet0(table4, i, j, table4_data[i-1][j-1])
                    table4.cell(i, j).width = Cm(1.5)

        # ########################################  文件名称  ########################################
        # 文件名称
        NOW = datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S')
        # 保存文档
        file_name = '附件:数据报告{}{}.docx'.format(file_title, NOW)
        self.document.save(r'D:\output\{}'.format(file_name))
        now2 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print('>>>{} 已经生成文档{}'.format(now2, file_name))

        self.file_path = r'D:\output\{}'.format(file_name)

    def num_get(self, str):
        num_str = ''
        num_list = []
        # 非数值字符替换 -
        for i in range(len(str)):
            if str[i].isdecimal():
                num_str = num_str + str[i]
            else:
                num_str = num_str + '-'
        # 提前数值字符串,添加至列表 num_list
        num_lis = num_str.split('-')
        for string in num_lis:
            if string != '':
                num_list.append(string)

        # 并返回数值样式
        get_num1 = '{:,}'.format(int(num_list[2]))
        get_num2 = '{:,}'.format(int(num_list[3]))
        return num_list, get_num1, get_num2
        # ########################################  段落格式函数  ########################################
    def add_heeder_sheet0(self,table_one,i, sheet0_header):
        # self.add_heeder_sheet0( table2, i, header2[i])
        par_table2 = table_one.cell(0, i).paragraphs[0]
        table_one.cell(0, i).vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER  # 垂直居中
        par_table2.paragraph_format.alignment = WD_TABLE_ALIGNMENT.CENTER  # 水平居中
        run_par_08_table2 = par_table2.add_run(sheet0_header)
        run_par_08_table2.font.bold = True  # 是否加粗
        run_par_08_table2.font.size = Pt(12)
        run_par_08_table2.font.name = '仿宋_GB2312'
        run_par_08_table2.element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')  # 设置中文是宋体

    def add_one_sheet0(self,table_one,i,j,sheet0_content):
        # self.add_one_sheet0(table2, i, j, xh_num)
        par_table_one = table_one.cell(i, j).paragraphs[0]
        table_one.cell(i, j).vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER  # 垂直居中
        par_table_one.paragraph_format.alignment = WD_TABLE_ALIGNMENT.CENTER  # 水平居中

        run_par_table_one = par_table_one.add_run(str(sheet0_content))
        run_par_table_one.font.size = Pt(12)
        run_par_table_one.font.name = '仿宋_GB2312'
        run_par_table_one.element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')  # 设置中文是宋体

    def add_one_par(self,par_content):
        par_one_content = self.document.add_paragraph('')
        par_one_content.paragraph_format.line_spacing = Pt(27)  # 行间距,固定值
        par_one_content.paragraph_format.first_line_indent = Pt(27)  # 首行缩进
        par_one_content.paragraph_format.space_before = Pt(0)  # 段前30磅
        par_one_content.paragraph_format.space_after = Pt(0)  # 段后15磅
        run_par_one_content = par_one_content.add_run(par_content)  # 添加输入变量
        run_par_one_content.font.name = '仿宋_GB2312'
        run_par_one_content.element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')  # 设置中文是宋体
        run_par_one_content.font.size = Pt(16)  # 字号大小

    def add_one_title(self,title_content):
        head_title = self.document.add_heading(level=2)
        run_head_title = head_title.add_run(title_content)
        run_head_title.font.size = Pt(16)  # 字号大小
        run_head_title.font.color.rgb = RGBColor(0, 0, 0)  # 字体颜色
        run_head_title.font.bold = False  # 是否加粗
        run_head_title.font.name = '黑体'
        run_head_title.element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')  # 设置字体


    def add_annex_title(self,title_content):
        head_title = self.document.add_heading(level=2)
        run_head_title = head_title.add_run(title_content)
        run_head_title.paragraph_format.line_spacing = Pt(27)  # 行间距,固定值
        run_head_title.paragraph_format.space_before = Pt(13)  # 段前30磅
        run_head_title.paragraph_format.space_after = Pt(13)  # 段后15磅
        run_head_title.font.size = Pt(16)  # 字号大小
        run_head_title.font.color.rgb = RGBColor(0, 0, 0)  # 字体颜色
        run_head_title.font.bold = False  # 是否加粗
        run_head_title.font.name = '黑体'
        run_head_title.element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')  # 设置字体

    def create_page(self): # 已生成文档添加页码
        file = self.file_path
        w = win32com.client.gencache.EnsureDispatch("Word.Application")
        w.Visible = 0  # 设置应用可见
        adoc = w.Documents.Open(file)
        #  0获取节
        wd_section = adoc.Sections(1)  # 注意section内部成员编号是从1开始的
        # 1 创建页码对象1,设置页码格式
        activefooter = wd_section.Footers(win32com.client.constants.wdHeaderFooterPrimary).Range
        activefooter.InsertAfter(Text='-')
        # 页码对象1,设置页码位置
        activefooter.ParagraphFormat.Alignment = win32com.client.constants.wdAlignParagraphCenter
        # 页码对象1,添加页码内容
        activefooter.Collapse(0)
        activefooter.Fields.Add(activefooter, win32com.client.constants.wdFieldPage)
        # 1 创建页码对象2,设置页码格式
        activefooter = wd_section.Footers(win32com.client.constants.wdHeaderFooterPrimary).Range
        activefooter.Collapse(0)
        activefooter.InsertAfter(Text='-')
        # 下面是添加总页数
        # activefooter.Collapse(0)
        # activefooter.Fields.Add(activefooter, win32com.client.constants.wdFieldNumPages)

        adoc.Save()
        adoc.Close()
        w.Quit()
        print('文档:{} \n添加页面完毕'.format(file))

3 文件打包成exe
3.1 安装pyinstaller

​ 首先,需要安装pyinstaller库,使用pip命令安装即可。

3.2 生成exe文件

​ 然后,进入控制台,通过cd指令进入到项目当前文件夹下,在控制台输入如下命令:

Pyinstaller -F master_system.py # 仅打包exe

Pyinstaller -F -w master_system.py # 不带控制台的打包

Pyinstaller -F -w -i picture.ico master_system.py # 打包指定exe图标打包(注意图片要ico的)

​ 打包成功后会在项目目录下生产一个dist文件夹,里边有打包好的exe程序 。把这个exe程序拷贝到windows下的任意位置,双击执行即可。

​ 最后,需要将模板文件放于项目环境下的依赖库里。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值