I want to hide a tkinter button but not when the user clicks it. I just want to hide it, at random times. How will I do that in Python? Below is the code I tried:
self.startGame = Button(self.canvas, text="Start", background='white', command = self.startGame, font=("Helvetica"))
self.startGame.place(x=770, y=400)
Hiding it:
self.startGame.bind('<Button-1>', self.hide_me)
def hide_me(self, event):
print('hide me')
event.widget.pack_forget()
It doesn't even get inside the hide_me function.
As pointed out in the comments you should use place_forget() for widgets that were set on the screen using place().
Same goes for pack() and grid(). You would use pack_forget() and grid_forget() respectively.
Here is a modified example of your code.
import tkinter as tk
class Example(tk.Tk):
def __init__(self):
super().__init__()
canvas = tk.Canvas(self)
canvas.pack()
self.startGame = tk.Button(canvas, text="Start", background='white', font=("Helvetica"))
self.startGame.place(x=150, y=100)
self.startGame.bind('<Button-1>', self.hide_me)
def hide_me(self, event):
print('hide me')
event.widget.place_forget()
if __name__ == "__main__":
Example().mainloop()
That said you do not need a bind here. Simply use a lambda statement in your command like this:
import tkinter as tk
class Example(tk.Tk):
def __init__(self):
super().__init__()
canvas = tk.Canvas(self)
canvas.pack()
self.startGame = tk.Button(canvas, text="Start", background='white', font=("Helvetica"),
command=lambda: self.hide_me(self.startGame))
self.startGame.place(x=150, y=100)
def hide_me(self, event):
print('hide me')
event.place_forget()
if __name__ == "__main__":
Example().mainloop()
Related
Total noob can't make tkinter button bind to keyboard.
I've tried to bind they both in main() and in the init().
I've tried bunches of permutations of syntax. Nothing works.
I've tried around until the button(s) get focus and hitting then. NOTHING HAPPENS.
Anyone have the secret insider information on how to do it?
from tkinter import *
from tkinter.ttk import Frame, Button, Style
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
self.btn_convert.bind("<Return>", self.convert)
# -----------------------------------------------
def convert(self):
print("enter pressed")
# -----------------------------------------------
def quit(self):
self.root.destroy()
exit()
# -----------------------------------------------
def initUI(self):
self.master.title("Weight Converter")
self.pack(fill=BOTH, expand=True)
self.frame_btn = Frame(self)
self.frame_btn.pack(fill=BOTH, expand=True, padx=20, pady=5)
self.btn_convert=Button(self.frame_btn, text="Convert", command=self.convert)
self.btn_convert.pack(side=LEFT, padx=5, pady=5)
self.btn_close1=Button(self.frame_btn, text="Close", command=quit)
self.btn_close1.pack(side=LEFT, padx=5, pady=5)
def main():
root = Tk()
root.geometry("300x250+300+200")
app = Example()
root.bind("<Return>", lambda event: root.convert())
root.mainloop()
if __name__ == '__main__':
main()
Replace:
root.bind("<Return>", lambda event: root.convert())
with:
root.bind("<Return>", lambda event: app.convert())
or:
#in case you have multiple instances of Tk
app.bind("<Return>", lambda event: app.convert())
app.focus_set()
As convert is a method for Example instance(app) as opposed to Tk instance(root). Also, make sure that the object.bind is used on(root in above two lines and app onthe last line) has the focus by either manually focusing or calling object.focus_set().
Below is an example that prints "Enter" or "Escape" based on the keypress:
import tkinter as tk
class App(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.button = tk.Button(self, text="Event")
self.button.bind('<Return>', lambda evt : self.event_handler(True))
self.button.focus_set() # ensure initial focus is on the button
self.button.pack()
def event_handler(self, is_enter):
if is_enter:
my_string = "Enter"
else:
my_string = "Escape"
print(my_string)
if __name__ == '__main__':
root = tk.Tk()
app = App(root)
app.button.bind('<Escape>', lambda evt : app.event_handler(False))
app.pack()
root.mainloop()
Demo Example for all keys
Below demo should be displaying the pressed key for all keys:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def on_key_press(event):
global label
label['text'] = event.keysym
if __name__ == '__main__':
root = tk.Tk()
label = tk.Label(root)
root.bind('<KeyPress>', on_key_press)
label.pack()
root.mainloop()
To add a general "press Enter to run convert" binding, you should apply it to root. To add further focus-based bindings, you should apply them on a per-button basis, like so:
from tkinter import *
from tkinter.ttk import Frame, Button, Style
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
# -----------------------------------------------
def convert(self):
print("enter pressed")
# -----------------------------------------------
def quit(self):
print("quit pressed")
self.destroy()
exit()
# -----------------------------------------------
def initUI(self):
self.master.title("Weight Converter")
self.pack(fill=BOTH, expand=True)
self.frame_btn = Frame(self)
self.frame_btn.pack(fill=BOTH, expand=True, padx=20, pady=5)
self.btn_convert=Button(self.frame_btn, text="Convert", command=self.convert)
self.btn_convert.pack(side=LEFT, padx=5, pady=5)
self.btn_close1=Button(self.frame_btn, text="Close", command=quit)
self.btn_close1.pack(side=LEFT, padx=5, pady=5)
# When tab focus is on the "Close" button, change Return behaviour.
self.btn_close1.bind("<Return>", lambda event: self.quit())
def main():
root = Tk()
root.geometry("300x250+300+200")
app = Example()
root.bind("<Return>", lambda event: app.convert())
root.mainloop()
if __name__ == '__main__':
main()
I have tried all the other posts on this topic but none of them have worked for me...
Here is my code:
from tkinter import *
window=Tk()
window.geometry('600x400')
window.title('hello world')
def wrong():
root=Tk()
text=Text(root)
text.insert(INSERT,"WRONG!, you stupid idiot!!!!")
text.pack()
def right():
root=Tk()
text=Text(root)
text.insert(INSERT,"CORRECT, good job!")
text.pack()
def reset():
hide_widgets()
class UIProgram():
def setupUI(self):
buttonlist=[]
button= Button(window,text='Sanjam',command=wrong).pack()
button2=Button(window,text='Sunny the Bunny',command=wrong).pack()
button3= Button(window, text='Sunjum',command=right).pack()
button4= Button(window, text='bob',command=wrong).pack()
button5= Button(window, text='next',command=reset)
button5.pack()
self.label=Label(window)
self.label.pack()
window.mainloop()
program= UIProgram()
program.setupUI()
I am aware of pack_forget() and tried it, but it keeps giving me an error. Also, is it possible to make a command(like the 'reset' one I have) and use that in the command for a clear screen button. Please help, I am new to Tkinter and don't know much about these things..
Thanks
Example code
I'm tired to describe the same mistakes hundreds of times - some comments in code.
import tkinter as tk
# --- classes ---
class UIProgram():
def __init__(self, master):
self.master = master # use to add elements directly to main window
self.buttons = [] # keep buttons to change text
# frame to group buttons and easily remove all buttons (except `Next`)
self.frame = tk.Frame(self. master)
self.frame.pack()
# group button in frame
button = tk.Button(self.frame, text='Sanjam', command=self.wrong)
button.pack()
self.buttons.append(button)
button = tk.Button(self.frame, text='Sunny the Bunny', command=self.wrong)
button.pack()
self.buttons.append(button)
button = tk.Button(self.frame, text='Sunjum', command=self.right)
button.pack()
self.buttons.append(button)
button = tk.Button(self.frame, text='bob', command=self.wrong)
button.pack()
self.buttons.append(button)
# button outside frame
button_next = tk.Button(self.master, text='Next >>', command=self.reset)
button_next.pack()
self.label = tk.Label(self.frame)
self.label.pack()
def wrong(self):
# create second window with message and closing button
win = tk.Toplevel()
tk.Label(win, text="WRONG!, you stupid idiot!!!!").pack()
tk.Button(win, text='close', command=win.destroy).pack()
def right(self):
# create second window with message and closing button
win = tk.Toplevel()
tk.Label(win, text="CORRECT, good job!").pack()
tk.Button(win, text='close', command=win.destroy).pack()
def reset(self):
# remove frame with all buttons
self.frame.pack_forget()
tk.Label(self.master, text="frame removed").pack()
# or only remove text in labels
#for button in self.buttons:
# button['text'] = '-- place for new text --'
# --- main ---
root = tk.Tk()
root.geometry('600x400')
root.title('hello world')
program = UIProgram(root)
root.mainloop()
BTW: if you do var = Widget(...).pack() then you assign None to var because pack()/grid()/place() return None. You have to do it in two lines
var = Widget(...)
var.pack()
or in one line if you don't need var
Widget(...).pack()
This is my Copy&Paste program:
from tkinter import *
import Pmw
class CopyTextWindow(Frame):
def __init__(self):
Frame.__init__(self)
Pmw.initialise()
self.pack(expand=YES, fill=BOTH)
self.master.title("ScrolledText Demo")
self.frame1=Frame(self, bg="White")
self.frame1.pack(expand=YES, fill=BOTH)
self.text1=Pmw.ScrolledText(self, text_width=25, text_height=12, text_wrap=WORD,
hscrollmode="static", vscrollmode="static")
self.text1.pack(side=LEFT, expand=YES, fill=BOTH, padx=5, pady=5)
options = ["Copy", "Paste"]
self.selectedOption = StringVar()
self.menu = Menu(self.frame1, tearoff=0)
for option in options:
self.menu.add_radiobutton( label=option, variable=self.selectedOption,
command=self.ExecuteOption)
self.text1.bind("<Button-3>", self.popUpMenu)
def popUpMenu(self, event):
self.menu.post(event.x_root, event.y_root)
def ExecuteOption(self):
if self.selectedOption.get()=="Copy":
self.CopiedText=self.text1.get(SEL_FIRST, SEL_LAST)
else:
self.text1.settext( self.text1.get()+self.CopiedText)
def main():
CopyTextWindow().mainloop()
if __name__=="__main__":
main()
In this program, I want to make a GUI, that in it you can copy and paste text that you have selected. when you press the right mouse button, a little menu with the Copy and Paste options.
The program opens up, but when I press the right mouse button, no menu appears. Python also doesn't complain with an error.
I need to understand my mistake in this code.
For a reason I ignore, the event doesn't seem to be triggered when the bind is on the Text or on the Frame, but it works when it's on the main window:
from tkinter import *
import Pmw
class CopyTextWindow(Frame):
def __init__(self, master=None):
# I've added a master option to pass to the frame
Frame.__init__(self, master)
Pmw.initialise()
self.pack(expand=YES, fill=BOTH)
self.master.title("ScrolledText Demo")
self.frame1=Frame(self, bg="White")
self.frame1.pack(expand=YES, fill=BOTH)
self.text1=Pmw.ScrolledText(self, text_width=25, text_height=12, text_wrap=WORD,
hscrollmode="static", vscrollmode="static")
self.text1.pack(side=LEFT, expand=YES, fill=BOTH, padx=5, pady=5)
options = ["Copy", "Paste"]
self.selectedOption = StringVar()
self.menu = Menu(self.frame1, tearoff=0)
for option in options:
self.menu.add_radiobutton( label=option, variable=self.selectedOption,
command=self.ExecuteOption)
def popUpMenu(self, event):
print("ok")
self.menu.post(event.x_root, event.y_root)
def ExecuteOption(self):
if self.selectedOption.get()=="Copy":
self.CopiedText=self.text1.get(SEL_FIRST, SEL_LAST)
else:
self.text1.settext( self.text1.get()+self.CopiedText)
def main():
# main window
root = Tk()
ctw = CopyTextWindow(root)
# bind on the main window
root.bind("<Button-3>", ctw.popUpMenu)
root.mainloop()
if __name__=="__main__":
main()
How can I get a blocking modal input dialog box in standard Python?
I need the user to input a value before the code can proceed.
Here is some not-working test code, but the idea is that I should be able to call MyDialog from anywhere in the script, so this is just a simplified example.
import tkinter
class MyDialog:
def __init__(self, prompt):
self.top = tkinter.Toplevel()
tkinter.Label(self.top, text=prompt).pack()
self.e = tkinter.Entry(self.top)
self.e.pack(padx=5)
tkinter.Button(self.top, text="OK", command=self.ok).pack(pady=5)
def ok(self):
self.top.destroy()
return self.e.get()
root = tkinter.Tk()
userName = MyDialog('Enter your name')
tkinter.Label(root, text="Hello {}".format(userName)).pack()
root.mainloop()
The dialog should not only disable the master window, but block whatever code called it. And it should be able to pass the value back to the calling code.
The solution requires two critical pieces. First, use grab_set to block all events in the other window (or, more correctly, send all events to the dialog window). Second, use wait_window to prevent the method from returning until the dialog has been destroyed.
That being said, you shouldn't be using it like in your example. You need to have the mainloop running before you create the window. It might work OK on some platforms, but in general you shouldn't expect your GUI to behave properly until mainloop is running.
Here's a simple example:
import Tkinter as tk
class MyDialog(object):
def __init__(self, parent, prompt):
self.toplevel = tk.Toplevel(parent)
self.var = tk.StringVar()
label = tk.Label(self.toplevel, text=prompt)
entry = tk.Entry(self.toplevel, width=40, textvariable=self.var)
button = tk.Button(self.toplevel, text="OK", command=self.toplevel.destroy)
label.pack(side="top", fill="x")
entry.pack(side="top", fill="x")
button.pack(side="bottom", anchor="e", padx=4, pady=4)
def show(self):
self.toplevel.grab_set()
self.toplevel.wait_window()
value = self.var.get()
return value
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.button = tk.Button(self, text="Click me!", command=self.on_click)
self.label = tk.Label(self, text="", width=40)
self.label.pack(side="top", fill="x")
self.button.pack(padx=20, pady=20)
def on_click(self):
result = MyDialog(self, "Enter your name:").show()
self.label.configure(text="your result: '%s'" % result)
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
I'm trying to make my first GUI program. The problem is, that I can't figure out how to make a main menu, which would switch to one of the programs after clicking a button.
#Dev by Mkee
from Tkinter import *
import tkMessageBox
#Main Stuff
app = Tk()
app.title("Mkee's Tools")
app.geometry('300x200')
#modules
class Programs:
def Shuffle():
app2 = Tk()
app2.title("Shuffle")
app2.geometry('300x200')
app2.mainloop()
#end of modules
labelText = StringVar()
labelText.set('')
label1 = Label(app, textvariable=labelText, height=4)
label1.pack()
button1 = Button(app, text='Shuffle', width=30, command=Programs.Shuffle)
button1.pack(side='right', padx=5,pady=1)
app.mainloop()
I know that I'm doing it wrong. I just have no idea how to do it, So i gave it a try of how could it be. Please help me.
You could call pack_forget() to hide widgets, and (later)
pack to show them again:
Tkinter is singled-threaded, and mainloop runs the main event loop. Therefore you shouldn't call mainloop twice.
#Dev by Mkee
import Tkinter as tk
import sys
class Shuffle(object):
def __init__(self,master=None):
self.master=master
self.text=tk.Text(master)
def hide(self):
self.text.pack_forget()
def show(self):
self.text.pack(side=tk.LEFT, padx=5, pady=5)
class Buttons(object):
def __init__(self,master=None):
self.master=master
self.red = tk.Button(self.master, text="Red", bg="red", fg="white")
self.green = tk.Button(self.master, text="Green", bg="green", fg="black")
self.blue = tk.Button(self.master, text="Blue", bg="blue", fg="white")
def hide(self):
self.red.pack_forget()
self.green.pack_forget()
self.blue.pack_forget()
def show(self):
self.red.pack(side=tk.LEFT,expand=tk.YES,fill=tk.BOTH)
self.green.pack(side=tk.LEFT,expand=tk.YES,fill=tk.BOTH)
self.blue.pack(side=tk.LEFT,expand=tk.YES,fill=tk.BOTH)
class MainApp(object):
def __init__(self,master=None):
self.master=master
app=self.app=tk.Tk()
app.title("Mkee's Tools")
app.geometry('300x200')
self.shuffle=Shuffle(master)
self.buttons=Buttons(master)
self.current=None
menubar=tk.Menu(app)
program_menu=tk.Menu(menubar)
program_menu.add_command(label='Shuffle',
command=lambda: self.show(self.shuffle))
program_menu.add_command(label='Buttons',
command=lambda: self.show(self.buttons))
program_menu.add_command(label='Quit',command=sys.exit)
menubar.add_cascade(label='Programs', menu=program_menu)
app.config(menu=menubar)
def show(self,obj):
if self.current != obj:
try: self.current.hide()
except AttributeError: pass
self.current=obj
obj.show()
def main():
m=MainApp()
m.app.mainloop()
if __name__=='__main__':
main()