You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy/Python邮件合并应用中MailMerge.merge_templates仅生效一次问题

解决Kivy邮件合并应用Save按钮重复点击不更新数据的问题

我看了你用Kivy+Python开发的邮件合并应用,遇到的问题确实挺头疼的——Save按钮第一次点击能正常生成填充后的文档,但修改输入框内容后再点,新文档还是老数据,必须重启应用才行。这问题其实出在你对MailMerge对象的复用逻辑上,咱们一步步来解决:

问题根源

你在选择Word模板时创建了全局的merge_doc对象,第一次调用merge_templates后,这个对象内部的文档结构已经被修改(合并域被替换成了第一次输入的数据),后续再调用merge_templates时,已经没有可替换的合并域了,自然不会更新内容。

解决方案

每次执行保存操作时,重新加载Word模板并创建新的MailMerge实例,这样每次都基于原始模板进行数据填充,就不会出现旧数据残留的问题了。同时,咱们也可以优化一下全局变量的使用,尽量减少不必要的全局状态。

修改后的代码

main.py

import tkinter as tk
from tkinter import filedialog
from kivy.app import App
from kivy.base import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from docx import *
from mailmerge import MailMerge
from datetime import date
from collections import OrderedDict
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
import os

f_path = None
merge_data = None
merge_objects = None

class doc_select(BoxLayout):
    def create_merge(self):
        global f_path, merge_data, merge_objects
        root = tk.Tk()
        root.withdraw()
        f_path = filedialog.askopenfilename()
        # 用临时文档获取合并域,用完即关闭
        temp_doc = MailMerge(f_path)
        merge_fields = temp_doc.get_merge_fields()
        merge_data = dict.fromkeys(merge_fields)
        merge_objects = dict.fromkeys(merge_fields)
        temp_doc.close()
        self.show_popup()

    def show_popup(self):
        pop = Popup(title= 'Input Details', content = popup_content(), size_hint = (None,None), size = (Window.width,Window.height))
        pop.open()

class popup_content(BoxLayout):
    data_inputs = []
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def dynamic_widgets(self):
        for wid in merge_objects.keys():
            self.ids.Mybox.add_widget(Label(text = wid, size_hint_y=None))
            merge_objects[wid] = TextInput(size_hint_y = None)
            self.ids.Mybox.add_widget(merge_objects[wid])

    def create_merge_data(self):
        for i in merge_objects.keys():
            merge_data[i] = merge_objects[i].text

    def save_func(self):
        save_path = 'C:/Users/pavan m sunder/tutorials/Kivy/py/docx/populated_doc.docx'
        self.create_merge_data()
        # 每次保存都重新加载原始模板
        with MailMerge(f_path) as merge_doc:
            merge_doc.merge_templates([merge_data], separator='page_break')
            merge_doc.write(save_path)
        os.startfile(save_path)

    def saveas_func(self):
        self.create_merge_data()
        # 同样基于原始模板生成新文档
        with MailMerge(f_path) as merge_doc:
            merge_doc.merge_templates([merge_data], separator='page_break')
            save_path = filedialog.asksaveasfilename(defaultextension='.docx', filetypes=(('doc files', '*.doc*'), ('All files', '*.*')))
            if save_path:  # 处理用户取消保存的情况
                merge_doc.write(save_path)

class docsy(App):
    def build(self):
        return Builder.load_file('C:/Users/pavan m sunder/tutorials/Kivy/py/docx/sample.kv')

if __name__ == '__main__':
    docsy().run()

关键修改点

  • 移除了全局的merge_doc变量,避免复用已被修改的文档对象
  • 在选择模板时用临时temp_doc获取合并域,用完立即关闭,不保留修改状态
  • save_func和saveas_func中,每次都通过with MailMerge(f_path)创建新实例,基于原始模板填充最新数据
  • 给saveas_func增加了判断,防止用户取消保存对话框时抛出错误

sample.kv(无需修改)

doc_select:
    Button:
        text: 'Open'
        on_press: root.create_merge()
<popup_content>:
    orientation: 'vertical'
    ScrollView:
        GridLayout:
            cols:2
            id: Mybox
            orientation: 'vertical'
            size_hint: 1, self.minimum_height
            on_kv_post: root.dynamic_widgets()
    GridLayout:
        size_hint: 1, 0.1
        cols: 2
        Button:
            text: 'Save'
            on_press: root.save_func()
        Button:
            text: 'SaveAs'
            on_press: root.saveas_func()

Word模板内容(sample.docx)

Welcome «Name»!
«Date»
Hello «Name». This is word editing using python. Go ahead and unleash your python skill. «Wish»!!

这样修改后,不管你多少次修改输入框内容并点击Save/SaveAs,都会基于原始模板重新填充最新的数据,再也不用重启应用啦!

内容的提问来源于stack exchange,提问作者Pavan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:15:51