Thonny how to fix this stacked label - python

When I press OK to print out the answer multiple times, the answers just stack on each other but are not replaced by each other, how do I fix this bug?
from tkinter import *
from tkinter import messagebox
def main():
global window
window = Tk()
window.title("Calculator")
window.geometry("540x540")
label1 = Label(window, text="Calculator", font=("Windsor", 30), fg="light blue")
label1.pack()
global entry1
entry1 = Entry(window, width=20, font=("Arial 20"))
entry1.pack()
entry1.focus()
label2 = Label(window, text="+", font=("Windsor", 30), fg="light blue")
label2.pack()
global entry2
entry2 = Entry(window, width=20, font=("Arial 20"))
entry2.pack()
entry2.focus()
global label3
label3 = Label(window, text="=", font=("Windsor", 30), fg="light blue")
label3.pack()
button2 = Button(window, text="OK", fg="blue",
font="Arial 16 bold", command =button2_click)
button2.pack()
window.mainloop()
def button2_click():
Label.after(0, label.master.destroy)
try:
a = int(entry1.get())
b = int(entry2.get())
Label(window, text=f"{a+b}", font=("Windsor", 30), fg="light blue").pack()
except:
messagebox.showwarning("Error", "Invalid Entry or Entry Missing!")
if __name__=='__main__':
main()

It is better to create the result label once inside main() and update its text inside button2_click():
from tkinter import *
from tkinter import messagebox
def main():
global entry1, entry2, result
window = Tk()
window.title("Calculator")
window.geometry("540x540")
label1 = Label(window, text="Calculator", font=("Windsor", 30), fg="light blue")
label1.pack()
entry1 = Entry(window, width=20, font=("Arial 20"))
entry1.pack()
entry1.focus()
label2 = Label(window, text="+", font=("Windsor", 30), fg="light blue")
label2.pack()
entry2 = Entry(window, width=20, font=("Arial 20"))
entry2.pack()
label3 = Label(window, text="=", font=("Windsor", 30), fg="light blue")
label3.pack()
# create result label
result = Label(window, font=("Windsor", 30), fg="light blue")
result.pack()
button2 = Button(window, text="OK", fg="blue", font="Arial 16 bold", command=button2_click)
button2.pack()
window.mainloop()
def button2_click():
# below line will raise exception
#Label.after(0, label.master.destroy)
try:
a = int(entry1.get())
b = int(entry2.get())
# update result label
result.config(text=f"{a+b}")
except:
messagebox.showwarning("Error", "Invalid Entry or Entry Missing!")
if __name__=='__main__':
main()

Edit: I moved the button2_click () to the top. I comment out in line 17.
from tkinter import *
from tkinter import messagebox
window = Tk()
window = Tk()
def main():
global window
window.title("Calculator")
window.geometry("540x540")
label1 = Label(window, text="Calculator", font=("Windsor", 30), fg="light blue")
label1.pack()
def button2_click():
Label.after(0, label.master.destroy)
try:
a = int(entry1.get())
b = int(entry2.get())
Label(window, text=f"{a+b}", font=("Windsor", 30), fg="light blue").pack()
except:
messagebox.showwarning("Error", "Invalid Entry or Entry Missing!")
global entry1
entry1 = Entry(window, width=20, font=("Arial 20"))
entry1.pack(ipadx =10, ipady= 10)
entry1.focus()
label2 = Label(window, text="+", font=("Windsor", 30), fg="light blue")
label2.pack()
global entry2
entry2 = Entry(window, width=20, font=("Arial 20"))
entry2.pack()
entry2.focus()
global label3
label3 = Label(window, text="=", font=("Windsor", 30), fg="light blue")
label3.pack(ipadx =20, ipady= 20)
button2 = Button(window, text="OK", fg="blue",
font="Arial 16 bold", command =button2_click)
button2.pack()
window.mainloop()
def button2_click():
Label.after(0, label.master.destroy)
try:
a = int(entry1.get())
b = int(entry2.get())
Label(window, text=f"{a+b}", font=("Windsor", 30), fg="light blue").pack()
except:
messagebox.showwarning("Error", "Invalid Entry or Entry Missing!")
if __name__=='__main__':
main()

Related

How to remove 2 buttons by pressing one?

I want to remove the buttons "play" and "help" by pressing just on button "play". How can I do that? I need that the button "play" destroy himself and in addition destroy the button "help"
This is my code:
from tkinter import *
import tkinter.messagebox
from random import *
window = Tk()
window.title("Simon")
window.geometry("300x200")
label = Label(window, text="Simon Game!", font=("Ariel", 80),
bg="CadetBlue3")
label.pack()
window.configure(bg="CadetBlue3")
def destroy(button):
def inner():
button.destroy()
return inner
def click_help_button():
tkinter.messagebox.showinfo("Instructions", "The device
creates a series of tones and lights and requires a user to
repeat the sequence. If the user succeeds, the series becomes
progressively longer and more complex. Once the user fails, the
game is over")
help_btn = Button(window, width=12, height=2, text="Help",
bg="grey",font=("Ariel", 18), command=click_help_button)
help_btn.pack(side='bottom')
help_btn.place(x=800, y=150)
start_btn = Button(window, width=12, height=2, text="Play",
bg="grey", font=("Ariel", 18), command=destroy(help_btn))
start_btn.pack(pady=10)
start_btn.place(x=525, y=150)
start_btn.config(command=destroy(start_btn))
red_btn = Button(window, width=35, height=15, bg='red')
red_btn.place(x=495, y=270)
green_btn = Button(window, width=35, height=15, bg='green')
green_btn.place(x=750, y=270)
blue_btn = Button(window, width=35, height=15, bg='blue')
blue_btn.place(x=495, y=495)
yellow_btn = Button(window, width=35, height=15, bg='yellow')
yellow_btn.place(x=750, y=495)
window.mainloop()
Thanks to those who help!
I would make a click_play_button function
def click_play_button():
start_btn.destroy()
help_btn.destroy()
And call on it when pressing the play button
start_btn = Button(window, width=12, height=2, text="Play",
bg="grey", font=("Ariel", 18), command=click_play_button)
start_btn.pack(pady=10)
start_btn.place(x=525, y=150)
Below also worked...
def destroy(button):
button.destroy()
def click_help_button():
tkinter.messagebox.showinfo("Instructions", "The device")
help_btn = Button(window, width=12, height=2, text="Help",
bg="grey", font=("Ariel", 18), command=click_help_button)
help_btn.pack(side='bottom')
help_btn.place(x=800, y=150)
start_btn = Button(window, width=12, height=2, text="Play",
bg="grey", font=("Ariel", 18), command=lambda: [destroy(help_btn), destroy(start_btn)])
start_btn.pack(pady=10)
start_btn.place(x=525, y=150)
red_btn = Button(window, width=35, height=15, bg='red')
red_btn.place(x=495, y=270)
green_btn = Button(window, width=35, height=15, bg='green')
green_btn.place(x=750, y=270)
blue_btn = Button(window, width=35, height=15, bg='blue')
blue_btn.place(x=495, y=495)
yellow_btn = Button(window, width=35, height=15, bg='yellow')
yellow_btn.place(x=750, y=495)
window.mainloop()

How can i make this text entry/frame as a whole disappear?

So I want to make this frame that I made disappear after the press of a button. Heres the code:
import tkinter as tk
root = tk.Tk()
root.geometry("150x50+680+350")
def FormSubmission():
global button_start
root.attributes("-fullscreen", True)
frame = tk.Frame(root)
tk.Label(frame, text="First Name:").grid(row=0)
entry1 = tk.Entry(frame)
entry1.grid(row=0, column=1)
tk.Label(frame, text="Last Name:").grid(row=1)
e2 = tk.Entry(frame)
e2.grid(row=1, column=1)
tk.Label(frame, text="Email:").grid(row=2)
e3 = tk.Entry(frame)
e3.grid(row=2, column=1)
tk.Label(frame, text="Date of Birth:").grid(row=3)
e4 = tk.Entry(frame)
e4.grid(row=3, column=1)
frame.pack(anchor='center', expand=True)
button_next = tk.Button(root, text = "Next", height = 2, width = 7, command = MainPage).pack()
button_start.place_forget()
def MainPage():
global FormSubmission
root.attributes("-fullscreen", True)
l1 = tk.Label(root, text = "Welcome Back," , font = ("Arial", 44)).pack()
button_start.place_forget() # You can also use `button_start.destroy()`
button_start = tk.Button(root, text="Start", height=3, width=20, command = FormSubmission)
button_start.place(x = 0, y = 10)
button_exit = tk.Button(root, text="Exit", command=root.destroy)
button_exit.place(x=1506, y=0)
root.mainloop()
So as you see I want to make the frame/function (FormSubmission) for the entry field disappear after pressing the next button after in the function (MainPage).
You can use pack_forget
Every geometry manager(pack, grid, place) has its own ..._forget
I've re-edit your snippet just for the use case you wished for.
Anyway I think you should re-design your app.
import tkinter as tk
root = tk.Tk()
root.geometry("150x50+680+350")
def FormSubmission():
global button_start
root.attributes("-fullscreen", True)
frame = tk.Frame(root)
tk.Label(frame, text="First Name:").grid(row=0)
entry1 = tk.Entry(frame)
entry1.grid(row=0, column=1)
tk.Label(frame, text="Last Name:").grid(row=1)
e2 = tk.Entry(frame)
e2.grid(row=1, column=1)
tk.Label(frame, text="Email:").grid(row=2)
e3 = tk.Entry(frame)
e3.grid(row=2, column=1)
tk.Label(frame, text="Date of Birth:").grid(row=3)
e4 = tk.Entry(frame)
e4.grid(row=3, column=1)
frame.pack(anchor='center', expand=True)
button_next = tk.Button(root, text = "Next", height = 2, width = 7, command = lambda: MainPage(frame)).pack()
button_start.place_forget()
def MainPage(frame):
global FormSubmission
frame.pack_forget()
root.attributes("-fullscreen", True)
l1 = tk.Label(root, text = "Welcome Back," , font = ("Arial", 44)).pack()
button_start.place_forget() # You can also use `button_start.destroy()`
button_start = tk.Button(root, text="Start", height=3, width=20, command = FormSubmission)
button_start.place(x = 0, y = 10)
button_exit = tk.Button(root, text="Exit", command=root.destroy)
button_exit.place(x=1506, y=0)
root.mainloop()

Attribute Error: '_tkinter.tkapp' object has no attribute 'root'

I don’t understand why this error appears, I have two source codes in one, everything works fine, in the second this error comes out. Looked at similar questions
but it did not give a result
try:
from Tkinter import * # for Python2
except ImportError:
from tkinter import * # for Python3
class Application(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.initialize_user_interface()
def initialize_user_interface(self):
self.master.root.title("Работа с планом")
self.master.root.geometry('400x300+200+200')
self.lbl_name = Label(root, text='Название проекта:', font=("Arial Bold", 14))
self.lbl_name.grid(column=0, row=1)
self.txt_name = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_name.grid(column=1, row=1)
self.lbl_lic = Label(root, text='Жидкость для работы:')
self.lbl_lic.grid(column=0, row=2)
self.txt_lic = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_lic.grid(column=1, row=2)
self.lbl_tank = Label(root, text='Имя танкера для работы:')
self.lbl_tank.grid(column=0, row=3)
self.txt_tank = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_tank.grid(column=1, row=3)
self.lbl_desk = Label(root, text='Описание действий сотрудника:')
self.lbl_desk.grid(column=0, row=4)
self.txt_desk = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_desk.grid(column=1, row=4)
self.lbl_agr = Label(root, text='Согласование работ с нормоконтролером:')
self.lbl_agr.grid(column=0, row=5)
self.txt_agr = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_agr.grid(column=1, row=5)
self.txt_name.focus()
self.but_b = Button(root, text="Назад", font=("Arial Bold", 14))
self.but_b.grid(column=0, row=6)
self.but_go = Button(root, text="Вперед", font=("Arial Bold", 14), command=self.safe)
self.but_go.grid(column=0, row=7)
self.but_safe = Button(root, text="Сохранить", font=("Arial Bold", 14))
self.but_safe.grid(column=1, row=6)
self.but_del = Button(root, text="Удалить", font=("Arial Bold", 14))
self.but_del.grid(column=1, row=7)
if __name__ == '__main__':
root = tk.Tk()
run = Application(root)
Application(root)
root.mainloop()
Firstly, when you are changing the Root Title and geometry, you do not need to call the root simply leaving it as self.master.geometry('400x300+200+200') will work fine.
Secondly, when using from tkinter import * you do not need to use tk.Frame you can just use Frame as Python will recognise this as a class name.
Thirdly one of your button commands self.safe will cause an error because this method is not defined nor is it a built in Tk command.
Improved code...
from tkinter import *
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.master = master
self.initialize_user_interface()
def initialize_user_interface(self):
self.master.title("Работа с планом")
self.master.geometry('400x300+200+200')
self.lbl_name = Label(root, text='Название проекта:', font=("Arial Bold", 14))
self.lbl_name.grid(column=0, row=1)
self.txt_name = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_name.grid(column=1, row=1)
self.lbl_lic = Label(root, text='Жидкость для работы:')
self.lbl_lic.grid(column=0, row=2)
self.txt_lic = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_lic.grid(column=1, row=2)
self.lbl_tank = Label(root, text='Имя танкера для работы:')
self.lbl_tank.grid(column=0, row=3)
self.txt_tank = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_tank.grid(column=1, row=3)
self.lbl_desk = Label(root, text='Описание действий сотрудника:')
self.lbl_desk.grid(column=0, row=4)
self.txt_desk = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_desk.grid(column=1, row=4)
self.lbl_agr = Label(root, text='Согласование работ с нормоконтролером:')
self.lbl_agr.grid(column=0, row=5)
self.txt_agr = Entry(root, width=50, font=("Arial Bold", 14))
self.txt_agr.grid(column=1, row=5)
self.txt_name.focus()
self.but_b = Button(root, text="Назад", font=("Arial Bold", 14))
self.but_b.grid(column=0, row=6)
self.but_go = Button(root, text="Вперед", font=("Arial Bold", 14), command=None)
self.but_go.grid(column=0, row=7)
self.but_safe = Button(root, text="Сохранить", font=("Arial Bold", 14))
self.but_safe.grid(column=1, row=6)
self.but_del = Button(root, text="Удалить", font=("Arial Bold", 14))
self.but_del.grid(column=1, row=7)
if __name__ == '__main__':
root = Tk()
run = Application(root)
Application(root)
root.mainloop()

How can i go about making a button state active when entry fields are filled?

I want to have my "Create account" button only active if the password field has more than 5 characters.
I have tried to add some if checks to grab the entry field's length. (in code snippet) and my issue with that was the main loop only loops once while the window is open, so I think that wont work.
def createAccount():
window = tk.Tk()
window.geometry('320x125')
window.title("Create an account")
window.resizable(False, False)
window.configure(bg='gray')
#Buttons
window.create_close_button = Button(window, text="Close", command=window.destroy)
create_button = Button(window, text="Create", command=lambda: checkIfValid(
window.create_password_entry,
window.create_confirm_password_entry,
window.create_username_entry,
window), state='disabled')
#Labels
window.padding_label = Label(window, bg='gray')
window.create_username_label = Label(window, text="Username", bg='gray', fg='white')
window.create_password_label = Label(window, text="Password", bg='gray', fg='white')
window.create_confirm_password_label = Label(window, text="Confirm Password", bg='gray', fg='white')
#Entries
window.create_username_entry = Entry(window, bd=1, bg='gray', fg='white')
window.create_password_entry = Entry(window, show="*", bd=1, bg='gray', fg='white')
window.create_confirm_password_entry = Entry(window, show="*", bd=1, bg='gray', fg='white')
#Add all to grid
window.create_username_label.grid(row=1, column=1)
window.create_username_entry.grid(row=1, column=2)
window.create_password_label.grid(row=2, column=1)
window.create_password_entry.grid(row=2, column=2)
window.create_confirm_password_label.grid(row=3, column=1)
window.create_confirm_password_entry.grid(row=3, column=2)
window.padding_label.grid(row=4, column=1, columnspan=2)
create_button.grid(row=5, column=1)
window.create_close_button.grid(row=5, column=2)
def onKey(event):
if len(window.create_password_entry.get()) < 5:
create_button.configure(state = 'disabled')
else:
create_button.configure(state = 'normal')
window.create_password_entry.bind('<KeyRelease>', onKey)
window.mainloop()
I can't say that I expected the loop to only go through ONE time while the window was open, but I want to see how I could do this in a better way if anyone knows the answer.
Error here:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "", line 49, in createAccount
createAccountMenu.createAccount()
File "", line 58, in createAccount
window.bind('<KeyRelease>', onKey)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1251, in bind
return self._bind(('bind', self._w), sequence, func, add)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1206, in _bind
self.tk.call(what + (sequence, cmd))
_tkinter.TclError: can't invoke "bind" command: application has been destroyed
You can bind event <KeyRelease> to Entry with function which will check length. This function will be executed every time when you release key in Entry
import tkinter as tk
def on_key(event):
#print('len:', len(event.widget.get()))
#print('len:', len(entry.get()))
if len(entry.get()) > 5:
button['state'] = 'normal'
else:
button['state'] = 'disabled'
root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
entry.bind('<KeyRelease>', on_key)
button = tk.Button(root, text='OK', state='disabled')
button.pack()
root.mainloop()
EDIT: Code used for test. It works for me without problems. It close correctly.
import tkinter as tk
from tkinter import *
def createAccount(main_menu_window):
window = tk.Tk()
window.geometry('320x125')
window.title("Create an account")
window.resizable(False, False)
window.configure(bg='gray')
#Buttons
window.create_close_button = Button(window, text="Close", command=window.destroy)
create_button = Button(window, text="Create", command=lambda: checkIfValid(
window.create_password_entry,
window.create_confirm_password_entry,
window.create_username_entry,
window, main_menu_window), state='disabled')
#Labels
window.padding_label = Label(window, bg='gray')
window.create_username_label = Label(window, text="Username", bg='gray', fg='white')
window.create_password_label = Label(window, text="Password", bg='gray', fg='white')
window.create_confirm_password_label = Label(window, text="Confirm Password", bg='gray', fg='white')
#Entries
window.create_username_entry = Entry(window, bd=1, bg='gray', fg='white')
window.create_password_entry = Entry(window, show="*", bd=1, bg='gray', fg='white')
window.create_confirm_password_entry = Entry(window, show="*", bd=1, bg='gray', fg='white')
#Add all to grid
window.create_username_label.grid(row=1, column=1)
window.create_username_entry.grid(row=1, column=2)
window.create_password_label.grid(row=2, column=1)
window.create_password_entry.grid(row=2, column=2)
window.create_confirm_password_label.grid(row=3, column=1)
window.create_confirm_password_entry.grid(row=3, column=2)
window.padding_label.grid(row=4, column=1, columnspan=2)
create_button.grid(row=5, column=1)
window.create_close_button.grid(row=5, column=2)
def onKey(event):
if len(window.create_password_entry.get()) < 5:
create_button['state'] = 'disabled'
else:
create_button['state'] = 'normal'
window.create_password_entry.bind('<KeyRelease>', onKey)
window.mainloop()
def checkIfValid(create_password_entry, create_confirm_password_entry, create_username_entry, window, window_2):
print(create_password_entry.get())
print(create_confirm_password_entry.get())
print(create_username_entry.get())
window.destroy()
window_2.destroy()
window = tk.Tk()
Button(window, text='Create Account', command=lambda:createAccount(window)).pack()
Button(window, text='Close', command=window.destroy).pack()
window.mainloop()
You could use a trace_add callback set for an event on the entry field variable.
The following example activates the button when text is added to the entry, and disables it when the entry is cleared.
import tkinter as tk
def toggle_button(txt_var):
if txt_var.get():
btn.configure(state=tk.NORMAL)
else:
btn.configure(state=tk.DISABLED)
root = tk.Tk()
txt = tk.StringVar(root)
entry = tk.Entry(root, textvariable=txt)
entry.pack()
btn = tk.Button(root, text='button', command=lambda: print('this'), state=tk.DISABLED)
btn.pack()
txt.trace_add('write', lambda v_name, ndx, mode, txt_var=txt: toggle_button(txt_var))
root.mainloop()

How to update Labels in tkinter?

I'm trying to create a program in where you put a word in a box, press add, and this word goes to a list, which is also displayed on the right side. When I press the forward button the first thing on the list is deleted. Problem is I can't get the labels to update when I press the buttons / edit the list.
from tkinter import *
root = Tk()
root.title('Speakers List')
root.minsize(800, 600)
speakers = ['none']
spe = speakers[0]
def add():
if spe == 'none':
speakers.insert(0, [s])
e.delete(0, END)
spe.config(text=speakers[0])
else:
speakers[-2] = [s]
e.delete(0, END)
spe.config(text=speakers[0])
return
def forward():
if len(speakers) is 0:
return
else:
del speakers[0]
spe.config(text=speakers[0])
return
entry = StringVar()
e = Entry(root, width=30, font=("Arial", 20), textvariable=entry)
e.grid(row=0, sticky=W)
s = e.get()
button1 = Button(root, padx=10, pady=10, bd=5, text='Add', fg='black', command=add)
button1.grid(row=0, column=1)
button2 = Button(root, padx=10, pady=10, bd=5, text='Next', fg='black', command=forward)
button2.grid(row=1, column=1)
n = Label(root, font=("Arial", 35), bd=2, text=spe)
n.grid(row=1, sticky=W)
listdisplay = Label(root, font=('Arial', 20), text=speakers)
listdisplay.grid(row=0, column=10)
root.mainloop()
Is this the sort of thing you were looking for ?
from tkinter import *
root = Tk()
root.title('Speakers List')
root.minsize(800, 600)
speakers = ['50']
spe = speakers[0]
def add():
entry=e.get()
speakers.append(entry)
listdisplay.config(text=speakers)
return
def forward():
if len(speakers) is 0:
return
else:
del speakers[0]
listdisplay.config(text=speakers)
spe=speakers[0]
n.config(text=spe)
return
entry = StringVar()
e = Entry(root, width=30, font=("Arial", 20), textvariable=entry)
e.grid(row=0, sticky=W)
s = e.get()
button1 = Button(root, padx=10, pady=10, bd=5, text='Add', fg='black',command=add)
button1.grid(row=0, column=1)
button2 = Button(root, padx=10, pady=10, bd=5, text='Next', fg='black',command=forward)
button2.grid(row=1, column=1)
n = Label(root, font=("Arial", 35), bd=2, text=spe)
n.grid(row=1, sticky=W)
listdisplay = Label(root, font=('Arial', 20), text=speakers)
listdisplay.grid(row=0, column=10)
root.mainloop()
If so:
You create a list and then you use the append function to add an item to it. The rest was pretty much right.

Categories