Python Tkinter simple value process - python

I just new for the GUI and need little help.
a=int(input())
if a==0:
print("hi")
else:
print("hello")
I want to change input process to click button, like a switch.
left button -> a=0
right button -> a=1
window=tkinter.Tk()
window.title("")
window.geometry("640x640+100+100")
window.resizable(True, True)
a=tkinter.Button(window, text="left")
a.pack()
b=tkinter.Button(window, text="right")
b.pack()
window.mainloop()
I can see left, right button but I don't know how to put values.
Is there any example I can use?
Thanks

Does this example help You:
from tkinter import Tk, Button
def switch(btn1, btn2):
btn1.config(state='disabled')
btn2.config(state='normal')
print(btn1['text'])
window = Tk()
window.title("")
on = Button(window, text="On", command=lambda: switch(on, off))
on.pack(side='left', expand=True, fill='x')
off = Button(window, text="Off", command=lambda: switch(off, on))
off.pack(side='left', expand=True, fill='x')
off.config(state='disabled')
window.mainloop()
If You have questions ask but here is pretty good site to look up tkinter widgets and what they do, their attributes.
Also I suggest You follow PEP 8

You need to add a function to each one that will be executed when the buttons are clicked like this:
import tkinter as tk
def left_clicked():
print("Left button clicked")
right_button.config(state="normal") # Reset the button as normal
left_button.config(state="disabled") # Disable the button
def right_clicked():
print("Right button clicked")
right_button.config(state="disabled")
left_button.config(state="normal")
window = tk.Tk()
window.title("")
window.geometry("640x640+100+100")
# window.resizable(True, True) # Unneeded as it is already the default
left_button = tk.Button(window, text="left", command=left_clicked)
left_button.pack(side="left")
right_button = tk.Button(window, text="right", command=right_clicked,
state="disabled")
right_button.pack(side="right")
window.mainloop()

Related

How do I destroy specific button in the loop when clicked?

I am trying to create a 10*10 board of buttons, which when clicked, the clicked button is destroyed and only that one. However, I don't know how to specify which button has been clicked.
from tkinter import *
root = Tk()
root.title("Board")
def buttonClick():
button.destroy()
for i in range(10):
for j in range(10):
button = Button(root, text="", padx=20, pady=10, command=buttonClick)
button.grid(row=i+1, column=j+1)
root.mainloop()
You have to create function which gets widget/button as argument and uses it with destroy()
def buttonClick(widget):
widget.destroy()
And first you have to create Button without command=
button = tk.Button(root, text="", padx=20, pady=10)
and later you can use this button as argument in command=.
button["command"] = lambda widget=button:buttonClick(widget)
It needs to use lambda to assign function with argument.
Because you create many buttons in loop so it also needs to use widget=button in lambda to create unique variable with value from button for every command. If you don't use it then all commands will use reference to the same (last) button - and click on every button will destroy only last button.
Full working code
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def buttonClick(widget):
widget.destroy()
# --- main ---
root = tk.Tk()
root.title("Board")
for i in range(10):
for j in range(10):
button = tk.Button(root, text="x", padx=20, pady=10)
button["command"] = lambda widget=button:buttonClick(widget)
button.grid(row=i+1, column=j+1)
root.mainloop()
PEP 8 -- Style Guide for Python Code
This can be easily accomplished with a custom class if you're alright with that:
from tkinter import Button, Tk
root = Tk()
root.title("Board")
class Self_Destruct_Button(Button):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.configure(command=self.button_click)
def button_click(self):
self.destroy()
for i in range(10):
for j in range(10):
button = Self_Destruct_Button(root, text="", padx=20, pady=10)
button.grid(row=i + 1, column=j + 1)
root.mainloop()
So the custom class just assigns the command to a button_click method, which destroys the button.
As a side note, I also removed the wildcard import as that's not best practice.
Let me know if this works for you

Returning values from entry's when pressing a button using Tkinter

I am writing a program that requires two values (from 2 entries) to be called when a button is pressed. I simplified to code to try to isolate the problem. For some reason the program is not behaving how I want it to. When the button is pressed, the output is "A=" and then if i click the button a second time I get ""A=entry1 B=entry2 A=". I have been trying to figure out the problem for hours now, please help.
import tkinter as tk
def button_function():
A = entry1.get()
print('A=', A)
B= entry2.get()
print('B=', B)
root = tk.Tk()
canvas = tk.Canvas(root)
canvas.pack()
entry1 = tk.Entry(root)
entry1.place(relwidth=0.5, relheight=0.5)
entry2 = tk.Entry(root)
entry2.place(rely=0.5, relwidth=0.5, relheight=0.5)
button = tk.Button(root, text = "confirm", command= button_function)
button.place(relx=0.5, relwidth=0.5, relheight=1)
root.mainloop()
You just need to change command=button_function() to command=button_function, then it will work perfectly!

How To Repeatedly Delete Differently Named Items

Recently I was working on a program where when one clicked a button, it would delete all of the tkinter buttons they made through a .yml file. Here is an example of what I mean:
(All TKinter Root Init Here)
button1 = Button(root, text="hi")
button2 = Button(root, text="hi again")
button3 = Button(root, text="hi again again")
button4 = Button(root, text="OK this is getting tiring")
button5 = Button(root, text="go away")
button6 = Button(root, text="...")
def del_all():
for i in range(999999999):
button(i).place_forget() #I was hoping to make button(i) give the output button1, then button2, and so on.
root.mainloop()
Try nametowidget in tkinter,example like:
import tkinter as tk
r = tk.Tk()
for i in range(5):
tk.Button(r,text=i).pack()
r.nametowidget(".!button").pack_forget()
r.mainloop()
This will remove the first button.If you want to remove the second button, you need to use r.nametowidget(".!button2").pack_forget()
So for you code,you may need to use:
def del_all():
root.nametowidget(".!button").place_forget()
for i in range(2, 999999999):
root.nametowidget(".!button"+str(i)).place_forget()
About the parameter in the nametowidget, there is a clear description.
You could also use winfo_children and use .widgetName to check whether it is a button,like:
import tkinter as tk
r = tk.Tk()
tk.Label(r, text="test").pack()
for i in range(5):
tk.Button(r,text=i).pack()
for i in r.winfo_children():
if i.widgetName == 'button':
i.pack_forget()
r.mainloop()
The solution would depend on how the buttons are named/stored.
For example, if the buttons were a list. Something like:
buttons = ['button1', 'button2', 'button3', 'button4']
Then you an delete by calling:
buttons.remove()
And that would 'clear' the list.

How can I delete a Label?

When I click a button, it should write text under it and the text should disappear after few seconds.
I don't know how to code that. What I have tried so far:
from tkinter import *
import time
window = Tk()
window.title("Button")
window.geometry("500x300")
def buttonclick():
tex = Label(text="You clicked the button")
tex.pack()
time.sleep(5)
tex.destroy()
but = Button(text="Click me!", command=buttonclick)
but.pack()
window.mainloop()
You can use .after() method to destroy the label after fixed period of time.
The following example will delete the label after 3 seconds:
from tkinter import *
import time
window = Tk()
window.title("Button")
window.geometry("500x300")
def buttonclick():
tex = Label(text="You clicked the button")
tex.pack()
tex.after(3000, tex.destroy)
but = Button(text="Click me!", command=buttonclick)
but.pack()
window.mainloop()
Output:
Your code looks correct for the most part. The reason why it doesn't appear to be working is that there is nothing telling the window to update after adding the text. A simple fix would be to add window.update() when you create the label.
The Code should look like:
from tkinter import *
import time
window = Tk()
window.title("Button")
window.geometry("500x300")
def buttonclick():
tex = Label(text="You clicked the button")
tex.pack()
window.update()
time.sleep(5)
tex.destroy()
window.update()
but = Button(text="Click me!", command=buttonclick)
but.pack()
window.mainloop()

How to implement lift method?

I am trying to move my function NEW_FRAME in front of the Frame for the root window so that old frame and the other widget in it will be behind for the function NEW_FRAME to only display its widget. So I searched and discovered that tkinter has lift method to achieve that but I can't implement it correctly, have tried positioning it at different places inside the function.
this link :explanation of the lift method with an example
from tkinter import *
root = Tk()
root.geometry("1300x600")
welcome = Frame(root, bg="yellow")
welcome.pack( fill=BOTH, expand=True)
label = Label(welcome, text="welcome bro to page one")
label.grid(row=45, column=50)
b = Label(welcome, text="you can select menu bar to switch page")
b.grid(row=100, column=500)
def NEWS_Frame():
new = Frame(root, bg="red")
new.pack(fill=BOTH, expand=True)
l1 = Label(new, text="Have been waiting for")
l1.grid(row=49, column=80)
l2 = Label(new, text="hello dude how be things")
l2.grid(row=0, column=0)
new.lift() # have position it to lift the new frame to the top of Frame
# menu bar start here
MAIN_MENU = Menu(root)
root.config(menu=MAIN_MENU)
File_menu = Menu(MAIN_MENU)
MAIN_MENU.add_cascade(label="NEW PAGE", menu=File_menu, underline=0)
File_menu.add_command(label="NEWS", command=NEWS_Frame)
root.mainloop()
First of all, your Minimal, Complete, and Verifiable example should only include the least amount of code as possible to reproduce the specific issue. The code below reproduces exactly the behavior you're having an issue with, but nothing more:
import tkinter as tk
def swap():
button2.pack()
button2.lift()
if __name__ == '__main__':
root = tk.Tk()
button1 = tk.Button(root, text="Swap with button 2", command=swap)
button2 = tk.Button(root, text="Swap with button 1")
button1.pack()
root.mainloop()
A workaround using pack:
You can't put widgets over another widget using pack. pack is literally for stacking in the 2-d, as in it is for stacking horizontally or vertically but not for piling widgets in the depth dimension. However, a bad workaround would be to simply hide the widget while displaying the other, which doesn't require lift at all.
In the below code each time swap is called it hides one button while displaying the other:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except:
import Tkinter as tk
def swap():
global is_button1_lifted
if is_button1_lifted:
button1.pack_forget()
button2.pack()
else:
button2.pack_forget()
button1.pack()
is_button1_lifted = not is_button1_lifted
if __name__ == '__main__':
root = tk.Tk()
is_button1_lifted = True
button1 = tk.Button(root, text="Swap with button 2", command=swap)
button2 = tk.Button(root, text="Swap with button 1", command=swap)
swap()
root.mainloop()
Answer using grid:
This is the way of using lift in the OP's case. The way this works is that both widgets displayed in the same node of a grid. The widget lift method is used on simply comes over the other(s).
In the below example both buttons are displayed, while one(button2 in this case) simply blocks the other by being in front of the other. When the lift is called it simply makes its object come to the front:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except:
import Tkinter as tk
def swap():
global is_button1_lifted
if is_button1_lifted:
button2.lift()
else:
button1.lift()
is_button1_lifted = not is_button1_lifted
if __name__ == '__main__':
root = tk.Tk()
is_button1_lifted = False
button1 = tk.Button(root, text="Swap with button 2", command=swap)
button2 = tk.Button(root, text="Swap with button 1", command=swap)
button1.grid(row=0, column=0)
button2.grid(row=0, column=0)
root.mainloop()
Answer using place:
This works almost the same way as the answer with grid, place simply has a more direct layout control:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except:
import Tkinter as tk
def swap():
global is_button1_lifted
if is_button1_lifted:
button2.lift()
else:
button1.lift()
is_button1_lifted = not is_button1_lifted
if __name__ == '__main__':
root = tk.Tk()
is_button1_lifted = False
button1 = tk.Button(root, text="Swap with button 2", command=swap)
button2 = tk.Button(root, text="Swap with button 1", command=swap)
button1.place(x=23, y=87)
button2.place(x=23, y=87)
root.mainloop()
lift moves widgets in the Z axis, pack arranges widgets in the X and Y axis. lift is incapable of changing the ordering of widget arranged with pack

Categories