How to insert values created by a loop function to tkinter text boxes which are also created automatically with a loop function

Hi I’m trying to write a code that calculates the net present values of the installments. The code runs perfect up to a point where I can’t insert the calculated values in to the tkinter text boxes individually.

For example the code is asking the yearly interest rate and the input can be 15. The list price of an house can be 1000000 and the down payment can be 0.2 which is %20 of the list price. And we can input 12 as the number of installments.

Down payment will be calculated by multiplying 1000000 with 0.2 and gives 200000. And the execution will be inserted to the first tkinter text box. But when the calculation done for the net present values of the installments, all of them appear inside last tkinter text box rather than appearing individually.

Here is the code;

# This program is to create a payment schedule for the customers and check whether
# the payment plan is suitable for the seller in terms of net present value.

from tkinter import *

window=Tk()
    
# This part asks the number of installments and creates the desired amount of text boxes.
def create():
    for y in range(number_of_installments.get()):
        t11 = Label(window,text= '%s.Installment'%(y+1),foreground="green")
        t11.grid(row = y+2,column=0)    

    for y in range(number_of_installments.get()):
        ttt = Text(window, height=1, width=20, foreground="red")
        ttt.grid(row = y+2,column=1)
        
        #Net present values of the installments are calculated in this part.
        def NPV_calculation():
            interest_rate = [pow(1+0.0125,i) for i in range(1,int(number_of_installments.get())+1)]
            installment_amount = (float(list_price.get())-(float(list_price.get())*float(downpayment_percentage.get())))/(float(number_of_installments.get()))
            calculation = [installment_amount/i for i in interest_rate]
            ttt.insert(END,calculation)
           
        
    downpayment_calculation()
    NPV_calculation()  

#Downpayment calculated by entering a value between 0 to 1. For example if 0.2 is typed in the textbox it will multiply the list price by %20.
def downpayment_calculation():
    Downpayment = float(list_price.get())*float(downpayment_percentage.get())
    t0.insert(END,Downpayment)

#Entry boxes
number_of_installments = IntVar(value="")
installment = Entry(window, textvariable=number_of_installments)
installment.grid(row=3,column=3)

interest_value = StringVar()
interest = Entry(window, textvariable=interest_value)
interest.grid(row=0,column=3)

list_price = StringVar()
list = Entry(window, textvariable=list_price)
list.grid(row=1,column=3)

downpayment_percentage = StringVar()
downpayment = Entry(window, textvariable=downpayment_percentage)
downpayment.grid(row=2,column=3)

#Create button for creating number of grids based on the number of installments.
b1 = Button(window, text="Create", command=create)
b1.grid(row=0,column=4)

#Labels for the enrty boxes
n_installments = Label(window,text="Number Of Installments",foreground="blue")
n_installments.grid(row=3,column=2)

yearly_interest = Label(window,text="Yearly Interest",foreground="blue")
yearly_interest.grid(row=0,column=2)

price_list = Label(window,text="List Price",foreground="blue")
price_list.grid(row=1,column=2)

per_downpayment = Label(window,text="Downpayment Percentage",foreground="blue")
per_downpayment.grid(row=2,column=2)

#Label and text box for the downpayment
t0 = Label(window,text="Downpayment",foreground="green")
t0.grid(row=1,column=0) 

t0 = Text(window, height=1, width=20, foreground="red")
t0.grid(row=1,column=1)

window.mainloop()

Answer

When you call the NPV_calculation function, ttt is the last text widget.

# This part asks the number of installments and creates the desired amount of text boxes.
def create():
    for y in range(number_of_installments.get()):
        t11 = Label(window,text= '%s.Installment'%(y+1),foreground="green")
        t11.grid(row = y+2,column=0)    

    for y in range(number_of_installments.get()):
        ttt = Text(window, height=1, width=20, foreground="red")
        ttt.grid(row = y+2,column=1)
        print("the object named ttt in this loop iteration is:", ttt)
        
        #Net present values of the installments are calculated in this part.
        def NPV_calculation():
            interest_rate = [pow(1+0.0125,i) for i in range(1,int(number_of_installments.get())+1)]
            installment_amount = (float(list_price.get())-(float(list_price.get())*float(downpayment_percentage.get())))/(float(number_of_installments.get()))
            calculation = [installment_amount/i for i in interest_rate]
            ttt.insert(END,calculation)
            print("the object named ttt is:", ttt)
        
    downpayment_calculation()
    NPV_calculation() # <- when you call this function, ttt is the last Text widget

Output for number_of_installments = 3:

the object named ttt in this loop iteration is: .!text2
the object named ttt in this loop iteration is: .!text3
the object named ttt in this loop iteration is: .!text4
the object named ttt is: .!text4

You need to insert values when creating a text widget in a loop. It is better to move the NPV_calculation function out of the loop.

This is a simplified example for the part where the values are generated automatically.

import tkinter as tk


window = tk.Tk()

def do_n_calculation(n):
    calculation = [x+1 for x in range(n)]
    return calculation
    
def create():
    # get new values
    n = number_of_installments.get()
    calculation_list = do_n_calculation(n)
    
    # clear previous values
    for i in installment_frame.winfo_children():
        i.destroy()

    # insert new values
    for y in range(n):
        t11 = tk.Label(installment_frame, text= '%s.Installment'%(y+1), foreground="green")
        t11.grid(row=y, column=0)
    for y in range(n):
        ttt = tk.Text(installment_frame, height=1, width=20, foreground="red")
        ttt.grid(row=y, column=1)
        ttt.insert(tk.END, calculation_list[y])

label = tk.Label(window, text="Number Of Installments")
label.grid(row=0, column=0)

number_of_installments = tk.IntVar(value="")
entry = tk.Entry(window, textvariable=number_of_installments)
entry.grid(row=0, column=1)

button = tk.Button(window, text="Create", command=create)
button.grid(row=0, column=2)

installment_frame = tk.Frame(window)
installment_frame.grid(row=1, column=0)

window.mainloop()

Complete example using the class.

import tkinter as tk


class Application(tk.Frame):
    """
          | column 0          | column 1   |
    -----------------------------------------
    row 0 | downpayment_frame | form_frame |
    -----------------------------------------
    row 1 | installment_frame |            |
    -----------------------------------------
    """
    def __init__(self, master):
        super().__init__(master)
        
        # data attributes
        self.downpayment_value = None
        self.calculation_list = None

        # left side
        
        # Label and text box for the downpayment
        self.downpayment_frame = tk.Frame(self)
        self.downpayment_frame.grid(row=0, column=0, padx=5, pady=5)
        
        self.downpayment_label = tk.Label(self.downpayment_frame, text="Downpayment", foreground="green")
        self.downpayment_label.grid(row=0, column=0) 

        self.downpayment_text = tk.Text(self.downpayment_frame, height=1, width=20, foreground="red")
        self.downpayment_text.grid(row=0, column=1)

        self.installment_frame = tk.Frame(self)
        self.installment_frame.grid(row=1, column=0, padx=5, pady=5)

        # right side

        self.form_frame = tk.Frame(self)
        self.form_frame.grid(row=0, column=1, padx=5, pady=5)
        
        # Labels for the enrty boxes
        self.yearly_interest = tk.Label(self.form_frame, text="Yearly Interest", foreground="blue")
        self.yearly_interest.grid(row=0, column=0)

        self.price_list = tk.Label(self.form_frame, text="List Price", foreground="blue")
        self.price_list.grid(row=1, column=0)

        self.per_downpayment = tk.Label(self.form_frame, text="Downpayment Percentage", foreground="blue")
        self.per_downpayment.grid(row=2, column=0)

        self.n_installments = tk.Label(self.form_frame, text="Number Of Installments", foreground="blue")
        self.n_installments.grid(row=3, column=0)
        
        # Entry boxes
        self.interest_value = tk.StringVar()
        self.interest = tk.Entry(self.form_frame, textvariable=self.interest_value)
        self.interest.grid(row=0, column=1)

        self.list_price = tk.StringVar()
        self.price = tk.Entry(self.form_frame, textvariable=self.list_price)
        self.price.grid(row=1, column=1)

        self.downpayment_percentage = tk.StringVar()
        self.downpayment = tk.Entry(self.form_frame, textvariable=self.downpayment_percentage)
        self.downpayment.grid(row=2, column=1)

        self.number_of_installments = tk.IntVar(value="")
        self.installment = tk.Entry(self.form_frame, textvariable=self.number_of_installments)
        self.installment.grid(row=3, column=1)

        # Create button for creating number of grids based on the number of installments.
        self.create_button = tk.Button(self.form_frame, text="Create", command=self.create)
        self.create_button.grid(row=0, column=2, rowspan=4, padx=[5, 0])

    # Net present values of the installments are calculated in this part.
    def NPV_calculation(self, number, list_price, percentage):
        interest_rate = [pow(1+0.0125,i) for i in range(1,int(number)+1)]
        installment_amount = (float(list_price)-(float(list_price)*float(percentage)))/(float(number))
        calculation = [installment_amount/i for i in interest_rate]
        return calculation
    
    def downpayment_calculation(self, list_price, percentage):
        downpayment = float(list_price)*float(percentage)
        return downpayment

    def create(self):
        number = self.number_of_installments.get()
        list_price = self.list_price.get()
        percentage = self.downpayment_percentage.get()

        # get new values and set data attributes
        self.downpayment_value = self.downpayment_calculation(list_price, percentage)
        self.calculation_list = self.NPV_calculation(number, list_price, percentage)

        # clear previous values
        self.downpayment_text.delete("1.0", tk.END)
        for i in self.installment_frame.winfo_children():
            i.destroy()
        
        # insert new values
        self.downpayment_text.insert(tk.END, self.downpayment_value)

        for y in range(number):
            label = tk.Label(self.installment_frame,text= '%s.Installment'%(y+1), foreground="green")
            label.grid(row=y, column=0)    

        for y in range(number):
            text = tk.Text(self.installment_frame, height=1, width=20, foreground="red")
            text.grid(row=y, column=1)
            text.insert(tk.END, self.calculation_list[y])
            
        self.get_calculation()

    def get_calculation(self):
        print(self.downpayment_value)
        print(self.calculation_list)


root = tk.Tk()
app = Application(master=root)
app.pack()
app.mainloop()