1

I want to write a small app that counts net amount and tax. I wrote this code and I've tried many times using var.set() based on this post but I have no idea how do it correctly.

from tkinter import *
import tkinter as tk

def count23():
    b = gross.get()
    n = round(b/1.23, 2)
    v = round(b - n, 2)
    # print here works, but prints in shell 

def count8():
    b = gross.get()
    n = round(b/1.08, 2)
    v = round(b - n, 2)

def count5():
    b = gross.get()
    n = round(b/1.05, 2)
    v = round(b - n, 2)

root = tk.Tk()

gross = DoubleVar()
root.geometry('220x200+250+250')

L1 = Label(root, text='Input gross ammount').grid(row=0, column=0, columnspan=5)

E1 = Entry(root, textvariable=gross).grid(row=1, column=1, columnspan=3, sticky='WE', padx=5, pady=5)

L2 = Label(root, text='Choose your tax rate').grid(row=2, column=0, columnspan=5)

B1 = Button(root, text='5 %', command=count5)
B1.grid(row=3, column=0, padx=5, pady=5)

B2 = Button(root, text='8 %', command=count8)
B2.grid(row=3, column=2, padx=5, pady=5)

B3 = Button(root, text='23 %', command=count23)
B3.grid(row=3, column=4, padx=5, pady=5)

L3 = Label(root, text=' ').grid(row=4, column=0, columnspan=5)

L4 = Label(root, text='Net').grid(row=5, column=0, columnspan=2, sticky='WE')

L5 = Label(root, text='TAX').grid(row=5, column=3, columnspan=2, sticky='WE')

L6 = Label(root, relief='raised')
L6.grid(row=6, column=0, columnspan=2, sticky='WE')

L7 = Label(root, relief='raised')
L7.grid(row=6, column=3, columnspan=2, sticky='WE')

root.mainloop()

I need to print net and tax in L6 and L7 labels. Give me some clues how do it, please.

Community
  • 1
  • 1
guest013
  • 33
  • 1
  • 1
  • 11

1 Answers1

4

The simple way to do this is to give those labels their own textvariables.

I replaced your 3 count functions with a single function show_tax. We use lambda functions in each Button command to call show_tax with the desired tax rate. I've also made a few other minor changes.

import tkinter as tk

def show_tax(rate):
    b = gross.get()
    n = round(b / rate, 2)
    # Format to string with 2 digits after the decimal point
    net.set(format(n, '.2f'))
    t = round(b - n, 2)
    tax.set(format(t, '.2f'))

root = tk.Tk()
root.geometry('310x165+250+250')
root.title('Tax calculator')

gross = tk.DoubleVar()
net = tk.StringVar()
tax = tk.StringVar()

tk.Label(root, text='Input gross amount').grid(row=0, column=0, columnspan=5)

e = tk.Entry(root, textvariable=gross)
e.grid(row=1, column=1, columnspan=3, sticky='WE', padx=5, pady=5)

tk.Label(root, text='Choose your tax rate').grid(row=2, column=0, columnspan=5)

b = tk.Button(root, text='5 %', command=lambda r=1.05: show_tax(r))
b.grid(row=3, column=0, padx=5, pady=5)

b = tk.Button(root, text='8 %', command=lambda r=1.08: show_tax(r))
b.grid(row=3, column=2, padx=5, pady=5)

b = tk.Button(root, text='23 %', command=lambda r=1.23: show_tax(r))
b.grid(row=3, column=4, padx=5, pady=5)

# An empty Label to force row to be displayed
tk.Label(root).grid(row=4, column=0, columnspan=5)

tk.Label(root, text='Net').grid(row=5, column=0, columnspan=2, sticky='WE')
tk.Label(root, text='TAX').grid(row=5, column=3, columnspan=2, sticky='WE')

l = tk.Label(root, textvariable=net, relief='raised')
l.grid(row=6, column=0, columnspan=2, sticky='WE')

l = tk.Label(root, textvariable=tax, relief='raised')
l.grid(row=6, column=3, columnspan=2, sticky='WE')

root.mainloop()

I have a couple more comments on your code (and my changes to it).

It's not a good idea to use from tkinter import * as that imports about 130 Tkinter names into the global namespace, which is messy and can lead to name collisions. Using the explicit tk. form makes the code easier to read.

BTW, the Widget .grid and .pack methods return None. So when you do something like

L2 = Label(root, text='Choose your tax rate').grid(row=2, column=0, columnspan=5)

it creates the label, puts it into the grid, and then sets L2 to None. If you need to keep a reference to the label you need to create the widget & place it into the grid in two steps, like this:

L2 = Label(root, text='Choose your tax rate')
L2.grid(row=2, column=0, columnspan=5)

If you don't need to keep a reference to the widget, but you still want to split it over 2 lines to keep the line length short then just use a "throwaway" variable, like I have with e, b, and l.


As Bryan Oakley mentions in the comments we don't actually need to give those labels their own StringVar textvariables: we can directly update their texts using the widget's .config method.

import tkinter as tk

def show_tax(rate):
    b = gross.get()
    n = round(b / rate, 2)
    # Format to string with 2 digits after the decimal point
    L6.config(text=format(n, '.2f'))
    t = round(b - n, 2)
    L7.config(text=format(t, '.2f'))

root = tk.Tk()
root.geometry('310x165+250+250')
root.title('Tax calculator')

gross = tk.DoubleVar()

tk.Label(root, text='Input gross amount').grid(row=0, column=0, columnspan=5)

e = tk.Entry(root, textvariable=gross)
e.grid(row=1, column=1, columnspan=3, sticky='WE', padx=5, pady=5)

tk.Label(root, text='Choose your tax rate').grid(row=2, column=0, columnspan=5)

b = tk.Button(root, text='5 %', command=lambda r=1.05: show_tax(r))
b.grid(row=3, column=0, padx=5, pady=5)

b = tk.Button(root, text='8 %', command=lambda r=1.08: show_tax(r))
b.grid(row=3, column=2, padx=5, pady=5)

b = tk.Button(root, text='23 %', command=lambda r=1.23: show_tax(r))
b.grid(row=3, column=4, padx=5, pady=5)

# An empty Label to force row to be displayed
tk.Label(root).grid(row=4, column=0, columnspan=5)

tk.Label(root, text='Net').grid(row=5, column=0, columnspan=2, sticky='WE')
tk.Label(root, text='TAX').grid(row=5, column=3, columnspan=2, sticky='WE')

L6 = tk.Label(root, relief='raised')
L6.grid(row=6, column=0, columnspan=2, sticky='WE')

L7 = tk.Label(root, relief='raised')
L7.grid(row=6, column=3, columnspan=2, sticky='WE')

root.mainloop()
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • Thank You very much for this answer. Ive tried with 3 different textvariables but never thought using lambda. Its new thing for me. And thanks for comments. I like when someone tells me what im doing wrong – guest013 Nov 08 '16 at 21:50
  • 1
    _"The simple way to do this is to give those labels their own textvariables."_ - an even simpler way is to NOT give labels their own textvariables. You can directly update the labels without the need for the variable objects. Fewer objects == less complexity. Less complexity == easier to maintain. – Bryan Oakley Nov 08 '16 at 22:45
  • @BryanOakley: Good points. I've added a new version that does that. – PM 2Ring Nov 08 '16 at 23:02
  • @guest013 I'm glad you like it. Please see the new improved version. – PM 2Ring Nov 08 '16 at 23:03
  • @PM2Ring i must say that both solutions are good. They differ two code lines but they give me better knowledge than i had before. Now i know how set label in two ways - simple way and even simpler :) I will use .config in my other project right after i can handle .after method ;) – guest013 Nov 09 '16 at 15:48