In this blog, we build a GUI with Tkinter and automate MS Word with Python. so with the help of these projects, you will gonna learn the basics of Python tkinter library and docxtpl which a Python library to automate MS Word with Python.
Requirement
Project Name | Build a GUI with Tkinter and automate MS Word with Python |
IDLE | vscode , pycharm or sublime3 (text editor) |
Language | python |
packages or module | tkinter , docxtpl |
Project Difficulty | Medium |
Source Code | See the end of article |
In this blog tutorial, you will learn how to use Tkinter and docxtpl to build your Invoice Generator with the help of well-documented code
– Use doxtpl to automate Word documents with Python
– Generate Word documents with Python
– Create your Python Tkinter application
– Use labels, buttons, entries in Tkinter
– Use combobox, spinbox and checkbox in Tkinter
– learn about positioning in Tkinter: pack() and grid.
– Setup a Tkinter form and use Tkinter input fields.
– Make a responsive interface with Tkinter
– Add messagebox in Tkinter
Installing Packages
In order To build These project you need these two modules :
pip install tk
pip install docxtpl
code
import tkinter
from tkinter import ttk
from docxtpl import DocxTemplate
import datetime
from tkinter import messagebox
def clear_item():
qty_spinbox.delete(0, tkinter.END)
qty_spinbox.insert(0, "1")
desc_entry.delete(0, tkinter.END)
price_spinbox.delete(0, tkinter.END)
price_spinbox.insert(0, "0.0")
invoice_list = []
def add_item():
qty = int(qty_spinbox.get())
desc = desc_entry.get()
price = float(price_spinbox.get())
line_total = qty*price
invoice_item = [qty, desc, price, line_total]
tree.insert('',0, values=invoice_item)
clear_item()
invoice_list.append(invoice_item)
def new_invoice():
first_name_entry.delete(0, tkinter.END)
last_name_entry.delete(0, tkinter.END)
phone_entry.delete(0, tkinter.END)
clear_item()
tree.delete(*tree.get_children())
invoice_list.clear()
def generate_invoice():
doc = DocxTemplate("invoice_template.docx")
name = first_name_entry.get()+last_name_entry.get()
phone = phone_entry.get()
subtotal = sum(item[3] for item in invoice_list)
salestax = 0.1
total = subtotal*(1-salestax)
doc.render({"name":name,
"phone":phone,
"invoice_list": invoice_list,
"subtotal":subtotal,
"salestax":str(salestax*100)+"%",
"total":total})
doc_name = "new_invoice" + name + datetime.datetime.now().strftime("%Y-%m-%d-%H%M%S") + ".docx"
doc.save(doc_name)
messagebox.showinfo("Invoice Complete", "Invoice Complete")
new_invoice()
window = tkinter.Tk()
window.title("Invoice Generator Form")
frame = tkinter.Frame(window)
frame.pack(padx=20, pady=10)
first_name_label = tkinter.Label(frame, text="First Name")
first_name_label.grid(row=0, column=0)
last_name_label = tkinter.Label(frame, text="Last Name")
last_name_label.grid(row=0, column=1)
first_name_entry = tkinter.Entry(frame)
last_name_entry = tkinter.Entry(frame)
first_name_entry.grid(row=1, column=0)
last_name_entry.grid(row=1, column=1)
phone_label = tkinter.Label(frame, text="Phone")
phone_label.grid(row=0, column=2)
phone_entry = tkinter.Entry(frame)
phone_entry.grid(row=1, column=2)
qty_label = tkinter.Label(frame, text="Qty")
qty_label.grid(row=2, column=0)
qty_spinbox = tkinter.Spinbox(frame, from_=1, to=100)
qty_spinbox.grid(row=3, column=0)
desc_label = tkinter.Label(frame, text="Description")
desc_label.grid(row=2, column=1)
desc_entry = tkinter.Entry(frame)
desc_entry.grid(row=3, column=1)
price_label = tkinter.Label(frame, text="Unit Price")
price_label.grid(row=2, column=2)
price_spinbox = tkinter.Spinbox(frame, from_=0.0, to=500, increment=0.5)
price_spinbox.grid(row=3, column=2)
add_item_button = tkinter.Button(frame, text = "Add item", command = add_item)
add_item_button.grid(row=4, column=2, pady=5)
columns = ('qty', 'desc', 'price', 'total')
tree = ttk.Treeview(frame, columns=columns, show="headings")
tree.heading('qty', text='Qty')
tree.heading('desc', text='Description')
tree.heading('price', text='Unit Price')
tree.heading('total', text="Total")
tree.grid(row=5, column=0, columnspan=3, padx=20, pady=10)
save_invoice_button = tkinter.Button(frame, text="Generate Invoice", command=generate_invoice)
save_invoice_button.grid(row=6, column=0, columnspan=3, sticky="news", padx=20, pady=5)
new_invoice_button = tkinter.Button(frame, text="New Invoice", command=new_invoice)
new_invoice_button.grid(row=7, column=0, columnspan=3, sticky="news", padx=20, pady=5)
window.mainloop()
Save this code as Main.py File
from docxtpl import DocxTemplate
doc = DocxTemplate("invoice_template.docx")
invoice_list = [[2, "pen", 0.5, 1],
[1, "paper pack", 5, 5],
[2, "notebook", 2, 4]]
doc.render({"name":"john",
"phone":"555-55555",
"invoice_list": invoice_list,
"subtotal":10,
"salestax":"10%",
"total":9})
doc.save("new_invoice.docx")
save it as doc_gen.py and before running this python make sure you have created a docx file named as “invoice_template.docx”
Basically, doc_gen.py file creates a Word document to generate a template for our main.py to create an invoice like this:
Now create a new main.file and paste this code :
import tkinter
from tkinter import ttk
from docxtpl import DocxTemplate
import datetime
from tkinter import messagebox
def clear_item():
qty_spinbox.delete(0, tkinter.END)
qty_spinbox.insert(0, "1")
desc_entry.delete(0, tkinter.END)
price_spinbox.delete(0, tkinter.END)
price_spinbox.insert(0, "0.0")
invoice_list = []
def add_item():
qty = int(qty_spinbox.get())
desc = desc_entry.get()
price = float(price_spinbox.get())
line_total = qty*price
invoice_item = [qty, desc, price, line_total]
tree.insert('',0, values=invoice_item)
clear_item()
invoice_list.append(invoice_item)
def new_invoice():
first_name_entry.delete(0, tkinter.END)
last_name_entry.delete(0, tkinter.END)
phone_entry.delete(0, tkinter.END)
clear_item()
tree.delete(*tree.get_children())
invoice_list.clear()
def generate_invoice():
doc = DocxTemplate("invoice_template.docx")
name = first_name_entry.get()+last_name_entry.get()
phone = phone_entry.get()
subtotal = sum(item[3] for item in invoice_list)
salestax = 0.1
total = subtotal*(1-salestax)
doc.render({"name":name,
"phone":phone,
"invoice_list": invoice_list,
"subtotal":subtotal,
"salestax":str(salestax*100)+"%",
"total":total})
doc_name = "new_invoice" + name + datetime.datetime.now().strftime("%Y-%m-%d-%H%M%S") + ".docx"
doc.save(doc_name)
messagebox.showinfo("Invoice Complete", "Invoice Complete")
new_invoice()
window = tkinter.Tk()
window.title("Invoice Generator Form")
frame = tkinter.Frame(window)
frame.pack(padx=20, pady=10)
first_name_label = tkinter.Label(frame, text="First Name")
first_name_label.grid(row=0, column=0)
last_name_label = tkinter.Label(frame, text="Last Name")
last_name_label.grid(row=0, column=1)
first_name_entry = tkinter.Entry(frame)
last_name_entry = tkinter.Entry(frame)
first_name_entry.grid(row=1, column=0)
last_name_entry.grid(row=1, column=1)
phone_label = tkinter.Label(frame, text="Phone")
phone_label.grid(row=0, column=2)
phone_entry = tkinter.Entry(frame)
phone_entry.grid(row=1, column=2)
qty_label = tkinter.Label(frame, text="Qty")
qty_label.grid(row=2, column=0)
qty_spinbox = tkinter.Spinbox(frame, from_=1, to=100)
qty_spinbox.grid(row=3, column=0)
desc_label = tkinter.Label(frame, text="Description")
desc_label.grid(row=2, column=1)
desc_entry = tkinter.Entry(frame)
desc_entry.grid(row=3, column=1)
price_label = tkinter.Label(frame, text="Unit Price")
price_label.grid(row=2, column=2)
price_spinbox = tkinter.Spinbox(frame, from_=0.0, to=500, increment=0.5)
price_spinbox.grid(row=3, column=2)
add_item_button = tkinter.Button(frame, text = "Add item", command = add_item)
add_item_button.grid(row=4, column=2, pady=5)
columns = ('qty', 'desc', 'price', 'total')
tree = ttk.Treeview(frame, columns=columns, show="headings")
tree.heading('qty', text='Qty')
tree.heading('desc', text='Description')
tree.heading('price', text='Unit Price')
tree.heading('total', text="Total")
tree.grid(row=5, column=0, columnspan=3, padx=20, pady=10)
save_invoice_button = tkinter.Button(frame, text="Generate Invoice", command=generate_invoice)
save_invoice_button.grid(row=6, column=0, columnspan=3, sticky="news", padx=20, pady=5)
new_invoice_button = tkinter.Button(frame, text="New Invoice", command=new_invoice)
new_invoice_button.grid(row=7, column=0, columnspan=3, sticky="news", padx=20, pady=5)
window.mainloop()
Make sure you have first created an empty docx file and renamed it as “invoice_template.docx”
Then you run doc_gen.py and after that main.py
if you getting confused then Here is a complete source code you have to just download and extract the zip file and Run the Main.py File but before that make sure you have installed the required Python library.
Complete Source code :