How do I link a function to a button in Tkinter? - python

So, I made a "love calculator" code and it's working but I want to give it a GUI. I want when I click on the button a number shows up under it. but I can't get it working. I really need help. I'm using python 3.8 with Tkinter. I want when I click on the button. I get an error that l1 is not defined. If you can please help because I'm an absolute beginner to Pyhton.
Here is the code:
import random
import tkinter as tk
from tkinter import *
from random import*
def get_love():
name1 = entry1.get()
name2 = entry2.get()
if (len(name1)) - (len(name2))== 2 or 1 or 0 or -1 or -2 or -3:
l1 = tk.Label(root, text="Here is how much you love eachother: ", (randint(40, 100)), '%')
else:
l2 = tk.Label(root, "Here is how much you love eachother: ", (randint(0, 49)), '%')
root = tk.Tk()
root.title("Love Calculator")
root.minsize(600, 600)
root.configure(background = 'pink')
w = tk.Label(root, bg="pink",font="Times 32 bold", text="Welcome to Love Calculator")
w1 = tk.Label(root, bg="pink",font="Arial 20", text=" ")
w2 = tk.Label(root, bg="pink", fg="white" ,font="Arial 19", text="Write your name here")
entry1 = tk.Entry (root)
w10 = tk.Label(root, bg="pink",font="Arial 20", text=" ")
w3 = tk.Label(root, bg="pink", fg="white" ,font="Arial 19", text="Write your lover's name here")
entry2 = tk.Entry (root)
b = Button(root, text="Click to see how much you love each other", font='Times 20 bold', command=get_love)
w.pack()
w1.pack()
w2.pack()
entry1.pack()
entry2.pack()
w3.pack()
w10.pack()
b.pack()
l1.pack()
l2.pack()
root.mainloop()

Here is a complete guide for you to fix your issue with only a few simple changes.
There are three simple problems with your program:
Problem 1:
You are using or in a wrong way so the condition(if) always returns True and the else block never gets executed, Here:
if (len(name1)) - (len(name2)) == 2 or 1 or 0 or -1 or -2 or -3:
Solution:
You can use range to solve this issue. You have to give it two numbers keeping in mind that the second number won't be included in the range, Like this:
if (len(name1)) - (len(name2)) in range(-3, 3):
Problem 2:
You are doing a mistake in the string concatenation, Here:
text="Here is how much you love each other: ", (randint(40, 100)), '%')
Solution:
There are two possible solutions for this problem:
You can use the plus "+" symbol instead of commas in it, Like this:
text="Here is how much you love each other: " + str(randint(40, 100)) + '%'
But as you can see, then you will also have to convert the random integer(randint(40, 100)) to a string, Like this: str(randint(40, 100))
The easiest solution to this problem is to use a formatted string, Like this:
text=f"Here is how much you love each other: {(randint(40, 100))}%"
Problem 3:
The main reason for getting the error is that you have defined your labels(l1 and l2) inside a function(get_love()), And you are trying to pack() these labels outside the function.
Solution:
The solution is to remove the pack() from outside the function for both labels(l1 and l2), and pack() them inside the function right after defining them. Like This:
def get_love():
name1 = entry1.get()
name2 = entry2.get()
if (len(name1)) - (len(name2)) == 2 or 1 or 0 or -1 or -2 or -3:
l1 = tk.Label(root, text=f"Here is how much you love each other: {(randint(40, 100))}%")
l1.pack()
else:
l2 = tk.Label(root, text=f"Here is how much you love each other: {(randint(0, 49))}%")
l2.pack()
Complete Fixed Code:
Here is the complete fixed code for you:
import tkinter as tk
from random import *
def get_love():
name1 = entry1.get()
name2 = entry2.get()
if (len(name1)) - (len(name2)) in range(-3, 3):
l1 = tk.Label(root, text=f"Here is how much you love each other: {(randint(40, 100))}%")
l1.pack()
else:
l2 = tk.Label(root, text=f"Here is how much you love each other: {(randint(0, 49))}%")
l2.pack()
root = tk.Tk()
root.title("Love Calculator")
root.minsize(600, 600)
root.configure(background='pink')
w = tk.Label(root, bg="pink", font="Times 32 bold", text="Welcome to Love Calculator")
w1 = tk.Label(root, bg="pink", font="Arial 20", text=" ")
w2 = tk.Label(root, bg="pink", fg="white", font="Arial 19", text="Write your name here")
entry1 = tk.Entry(root)
w10 = tk.Label(root, bg="pink", font="Arial 20", text=" ")
w3 = tk.Label(root, bg="pink", fg="white", font="Arial 19", text="Write your lover's name here")
entry2 = tk.Entry(root)
b = tk.Button(root, text="Click to see how much you love each other", font='Times 20 bold', command=get_love)
w.pack()
w1.pack()
w2.pack()
entry1.pack()
entry2.pack()
w3.pack()
w10.pack()
b.pack()
root.mainloop()

I don't believe a lambda is needed here, simply use the if/else to generate the number then format it into the label text.
Python has a nice feature for testing if a number is between two values: if -3 <= x <= 2
Also, avoid pitfalls like using numbers as variables, and importing things multiple times (import tkinter as tk, from tkinter import *)
For labels that are never going to change you don't need to store them to a variable, just pack/grid/place them as-is.
If you just need a space on the window add padding to an existing widget, or use a grid layout.
These are all just suggestions to hopefully help.
I did a bunch of code cleanup here:
from random import randint
import tkinter as tk
def get_love():
name1 = entry1.get()
name2 = entry2.get()
if -3 <= (len(name1) - len(name2)) <= 2:
number = randint(40, 100)
else:
number = randint(0, 49)
display.config(text="Here is how much you love eachother: {}%".format(number))
root = tk.Tk()
root.title("Love Calculator")
root.minsize(600, 600)
root.configure(background = 'pink')
tk.Label(root, bg="pink",font="Times 32 bold",
text="Welcome to Love Calculator").pack(pady = (0, 20))
tk.Label(root, bg="pink", fg="white", font="Arial 19",
text="Write your name here").pack()
entry1 = tk.Entry(root)
entry1.pack()
entry2 = tk.Entry(root)
entry2.pack()
tk.Label(root, bg="pink", fg="white",font="Arial 19",
text="Write your lover's name here").pack(pady = (0, 20))
tk.Button(root, text="Click to see how much you love each other",
font='Times 20 bold', command=get_love).pack(pady = (0, 20))
display = tk.Label(root, bg="pink")
display.pack()
root.mainloop()

Related

How do I get the values assigned to the Correct and Total numbers to update when the user inputs their answer?

I have a Python file that when run, opens a window for simple addition practice. It asks the user for their input, and if the total is correct will output "Right!" and "Oops!" for incorrect. Below all of this is a counter that keeps track of the correct number out of the total. However, at the moment, those numbers both remain zero when user enters their input. What kind of changes would need to be made under the ClicktheButton1 function in order to get this program properly functioning? Thanks.
The output would end up looking like "2 out 4 correct" in the window, updating after each new problem is solved.
from tkinter import *
import random as rn
window = Tk()
window.geometry('350x350')
window.title("C200")
x = rn.randint(0,100)
y = rn.randint(0,100)
correct, incorrect = 0,0
myLabel = Label(window, text="{0}+{1}=".format(x,y), font=("Arial Bold", 15))
myLabel.grid(column=0, row=0)
myLable2 = Label(window, text = "",font=("Arial Bold", 15))
myLable2.grid(column=0, row=5)
mylabel3 = Label(window,text = "0 out of 0 correct",font=("Arial Bold", 15))
mylabel3.grid(column=0, row=10)
mytxt = Entry(window, width=12)
mytxt.grid(column=1,row=0)
def ClicktheButton1():
global x
global y
global correct
global incorrect
myguess = int(mytxt.get())
if x + y == myguess:
myLable2.configure(text = "Right!")
correct += 1
else:
myLable2.configure(text = "Oops!")
incorrect += 1
x = rn.randint(0,100)
y = rn.randint(0,100)
mytxt.focus()
mytxt.delete(0,END)
myLabel.configure(text = "{0}+{1}=".format(x,y))
btn1 = Button(window, text="check", command = ClicktheButton1)
btn1.grid(column=0, row=7)
def ClicktheButton2():
window.destroy()
btn1 = Button(window, text="Quit", command = ClicktheButton2)
btn1.grid(column=400, row=400)
window.mainloop()
You have to change text in mylabel3 in the same why as you change text in myLabel - and even in the same place. I don't know why you have problem with this.
myLabel.configure(text = "{0}+{1}=".format(x,y))
mylabel3.configure(text="{0} of {1} correct".format(correct, correct+incorrect))

I cant generate a random number and print it

I can't generate the number because I get the error NameError: name 'z' is not defined.
import tkinter as tk
from random import randint
def randomize():
z.set ( randint(x.get(),y.get()))
root = tk.Tk()
x = tk.IntVar()
y = tk.IntVar()
text= tk.Label(root, text = "press the button for random number")
enterX = tk.Entry(root)
enterY = tk.Entry(root)
button = tk.Button(root, text = "Press here", command=randomize)
result = tk.Label(root,text="Number is:")
number = tk.Label(root, textvariable=z)
text.pack()
enterX.pack()
enterY.pack()
button.pack()
result.pack()
number.pack()
root.mainloop()
I need help to resolve the error
You have 2 problems here.
One. You are missing z = tk.Intvar() in the global namespace.
Two. You need to assign each entry field one of the IntVar()'s.
Keep in mind that you are not validating the entry fields so if someone types anything other than a whole number you will run into an error.
Take a look at this code.
import tkinter as tk
from random import randint
def randomize():
z.set(randint(x.get(),y.get()))
print(z.get()) # added print statement to verify results.
root = tk.Tk()
x = tk.IntVar()
y = tk.IntVar()
z = tk.IntVar() # added IntVar()
text= tk.Label(root, text = "press the button for random number")
enterX = tk.Entry(root, textvariable=x) # added textvariable
enterY = tk.Entry(root, textvariable=y) # added textvariable
button = tk.Button(root, text = "Press here", command=randomize)
result = tk.Label(root,text="Number is:")
number = tk.Label(root, textvariable=z)
text.pack()
enterX.pack()
enterY.pack()
button.pack()
result.pack()
number.pack()
root.mainloop()

Tkinter questionnaire based on get() method

I am trying to make my first GUI script based on the answers of 2 questions. I'll show an example of the non GUI script
while True:
ammount = input("What is your debt")
if ammount.isdigit() == True:
break
else:
print("Please try typing in a number")
while True:
month = input("In which month did the debt originate?")
if month not in ["January", "February"]:
print("Try again")
else:
break
The point of this script is that it is scalable with all the questions one may add, I want to understand it in the same way in Tkinter. I'll show what I've tried:
from tkinter import *
def click():
while True:
entered_text = text_entry.get()
if entered_text .isdigit() == False:
error = Label(window, text="Try again", bg = "black", fg="red", font="none 11").grid(row = 3, column = 2, sticky= W).pack()
else:
break
return True
window = Tk()
window.title("Tax calculator")
window.configure(background="black")
monto = Label(window, text="¿What is your debt?", bg="black", fg="white", font="none 12 bold")
monto.grid(row = 1, column = 0, sticky= W)
text_entry = Entry(window, width = 20, bg="white")
text_entry.grid(row = 2, column=2, sticky=W)
output = Button(window, text = "Enter", width = 6, command = click)
output.grid(row = 3, column = 0, sticky = W)
The thing is, I can't add a Label() method in the if/else of the click() method, because I would like to ask a new question once the condition is met. I can't also can't get True from click once the condition is met, because the input comes from Button() method. Thanks in advance
You don't actually need any loops here, a simple if statement would be enough to do the trick. Also, there is no need to recreate the label every time, you can just configure() its text. And, note that indexing starts from 0 - so, in your grid, actual first row (and column) needs to be numbered 0, not 1. Besides that, I suggest you get rid of import *, since you don't know what names that imports. It can replace names you imported earlier, and it makes it very difficult to see where names in your program are supposed to come from. You might want to read what PEP8 says about spaces around keyword arguments, as well:
import tkinter as tk
def click():
entered_text = text_entry.get()
if not entered_text.isdigit():
status_label.configure(text='Please try again')
text_entry.delete(0, tk.END)
else:
status_label.configure(text='Your tax is ' + entered_text)
text_entry.delete(0, tk.END)
root = tk.Tk()
root.title('Tax calculator')
root.configure(background='black')
monto = tk.Label(root, text='¿What is your debt?', bg='black', fg='white', font='none 12 bold')
monto.grid(row=0, column=0, padx=10, pady=(10,0))
text_entry = tk.Entry(root, width=20, bg='white')
text_entry.grid(row=1, column=0, pady=(10,0))
status_label = tk.Label(root, text='', bg='black', fg='red', font='none 11')
status_label.grid(row=2, column=0)
button = tk.Button(root, text='Enter', width=17, command=click)
button.grid(row=3, column=0, pady=(0,7))
root.mainloop()
I forgot to mention, if your application gets bigger, you might be better off using a class.

Python Tkinter StringVar only displaying Py_Var(number)

I am using Tkinter in python 3.4 to make a text based game, and I cannot figure out how to get a string from an Entry widget, it just returns Py_Var#, # being a number. I have looked at answers to similar questions, but none of them quite line up with what I need and have. Here's the relevant pieces of code:
from tkinter import *
win = Tk()
win.geometry("787x600")
playername = StringVar()
def SubmitName():
playername.get
#messagebox.showinfo("Success", playername)
print(playername)
frame3 = Frame(win)
frame3.pack()
label1 = Label(frame3, text="You awaken in a room, with no memories of yourself or your past. ")
label2 = Label(frame3, text="First, how about you give yourself a name:")
label1.config(font=("Courier", 11))
label2.config(font=("Courier", 11))
entry1 = Entry(frame3, textvariable=playername)
entry1.config(font=("Courier", 11))
label1.grid(row=0, column=0, columnspan=3)
label2.grid(row=1, column=0)
entry1.grid(row=1, column=1)
bnamesub= Button(frame3, text="Submit", command=lambda: SubmitName())
bnamesub.grid()
win.mainloop()
Also, first time using stackoverflow and its reading weird but w/e.
You have two mistakes in SubmitName().
First, you need to get the text like this:
txt = playername.get()
Then you need to print that txt:
print(txt)
By mistake you printed the StringVar variable itself.
from tkinter import *
import pickle
win = Tk()
win.geometry("787x600")
def SubmitName():
playername = entry1.get()
messagebox.showinfo("Success", playername)
print(playername)
frame3 = Frame(win)
frame3.grid()
label1 = Label(frame3, text="You awaken in a room, with no memories of yourself or your past. ")
label2 = Label(frame3, text="First, how about you give yourself a name:")
label1.config(font=("Courier", 11))
label2.config(font=("Courier", 11))
#name entered is a StringVar, returns as Py_Var7, but I need it to return the name typed into entry1.
entry1 = Entry(frame3)
entry1.config(font=("Courier", 11))
label1.grid(row=0, column=0, columnspan=3)
label2.grid(row=1, column=0)
entry1.grid(row=1, column=1)
bnamesub= Button(frame3, text="Submit", command=lambda: SubmitName())
bnamesub.grid()
What I changed:
-deleted playername = StringVar(). We don't really need it;
-changed inside the function: changed playername.get to playername = entry1.get();
-added frame3.grid() (without geometry managment, widgets cannot be shown on the screen.);
-also, a little edit: in Python, comments are created with # sign. So I changed * to #.
I was happy to find a solution here, but all these answers "as it is" are not working with my setting, python3.8, pycharm 2018.2
So if anyone could answer this, it seems that entry1.get() cannot be used as a string. I first wanted to append it in a list, and I did a more simple version to point out the trouble :
from tkinter import *
import pickle
win = Tk()
win.geometry("300x300")
#playername = StringVar()
def SubmitName():
labell = Label(win, text="Little tryup").grid()
playername = entry1.get()
# result about line 11: 'NoneType' object has no attribute 'get'
labelle = Label(win, text=playername).grid()
# print(txt)
label1 = Label(win, text="Enter a name:").grid()
entry1 = Entry(win).grid()
boutonne = Button(win, text="label-it!", command=lambda: SubmitName())
boutonne.grid()
win.mainloop()

Python tkinter binding a function to a button

from tkinter import *
root = Tk()
root.title("Tip & Bill Calculator")
totaltxt = Label(root, text="Total", font=("Helvitca", 16))
tiptxt = Label(root, text="Tip (%)", font=("Helvitca", 16))
peopletxt = Label(root, text="people", font=("Helvitca", 16))
totaltxt.grid(row=0, sticky=E)
tiptxt.grid(row=1, sticky=E)
peopletxt.grid(row=2, sticky=E)
totalentry = Entry(root)
tipentry = Entry(root)
peopleentry = Entry(root)
totalentry.grid(row=0, column=2)
tipentry.grid(row=1, column=2)
peopleentry.grid(row=2, column=2)
ans = Label(root, text = "ANS")
ans.grid(row=4)
def answer(event):
data1 = totalentry.get()
data2 = tipentry.get()
data3 = peopleentry.get()
if tipentry.get() == 0:
ans.configure(str((data1/data3)), text="per person")
return
elif data1 == 0:
ans.configure(text="Specify the total")
return
elif data3 == 0 or data3 ==1:
ans.configure(str(data1*(data2/100+1)))
return
elif data1 == 0 and data2 == 0 and data3 ==0:
ans.configure(text = "Specify the values")
return
else:
ans.configure(str((data1*(data2/100+1)/data3)), text="per person")
return
bf = Frame(root)
bf.grid(row=3, columnspan=3)
calc = Button(bf, text ="Calculate", fg = "black", command = answer)
calc.bind("<Button-1>", answer)
calc.grid(row=3, column=2)
root.mainloop()
I'm trying to make a tip and bill calculator with a simple design just to learn and experiment. However, I encountered a horrible problem that kept haunting for days, I usually struggle with functions in python and I'm trying to bind a function to a calculate button, which I managed to make it appear. However, I can't manage to get it to work. After some messing around I ended with this error, when I click the calculate button.
This is the error after I click the calculate button:
TypeError: answer() missing 1 required positional argument: 'event'
Commands bound to a button do not get an argument, as the nature of the event is already known. Delete 'event'.
You also bind the answer function to an event. The result is that answer is called both without and with an event argument. Get rid of the bind call.
Follow hint given by Bryan. Stop passing a digit string to .configure as a positional parameter. tk will try to interpret is as dictionary. Instead, add the number string to the rest of the label string.
Like rows, columns start from 0.
The frame is not needed.
The following revision works.
from tkinter import *
root = Tk()
root.title("Tip & Bill Calculator")
totaltxt = Label(root, text="Total", font=("Helvitca", 16))
tiptxt = Label(root, text="Tip (%)", font=("Helvitca", 16))
peopletxt = Label(root, text="people", font=("Helvitca", 16))
totaltxt.grid(row=0, column=0, sticky=E)
tiptxt.grid(row=1, column=0, sticky=E)
peopletxt.grid(row=2, column=0, sticky=E)
totalentry = Entry(root)
tipentry = Entry(root)
peopleentry = Entry(root)
totalentry.grid(row=0, column=1)
tipentry.grid(row=1, column=1)
peopleentry.grid(row=2, column=1)
ans = Label(root, text = "ANS")
ans.grid(row=4, column=0, columnspan=2, sticky=W)
def answer():
total = totalentry.get()
tip = tipentry.get()
people = peopleentry.get()
if not (total and tip):
ans['text'] = 'Enter total and tip as non-0 numbers'
else:
total = float(total)
tip = float(tip) / 100
people = int(people) if people else 1
ans['text'] = str(round(total * tip / people, 2)) + " per person"
calc = Button(root, text ="Calculate", fg = "black", command = answer)
calc.grid(row=3, column=1)
root.mainloop()

Categories