Consider the following code snippet:
from tkinter import *
import tkinter.filedialog as fd
def mycallback(event):
fname = fd.askopenfilename()
print(fname)
root = Tk()
b1 = Button(root, text='Hello!')
b1.bind('<Button-1>', mycallback)
b1.pack()
root.mainloop()
After pressing the button b1 an open-dialog appears as supposed. If I press OK or CANCEL after choosing a file, the program crashes with exit code 139.
What's the problem here?
I'm using Python 3.4 on OS X 10.6.8.
Calling a function when clicking a button can be done using the button's callback argument.
So instead of binding <Button-1> to the button you should use
b1 = Button(root, text='Hello!', command=mycallback)
You should then also remove the event argument from the mycallback function, since command doesn't pass any arguments.
How this solves your problem, I really dont know. But according to your comment it does.
For more information on the Button (and any other) widget, see effbot.org
Related
from tkinter import *
root = Tk()
mybutton = Button(root, text="Click Me!)
mybutton.pack
root.mainloop
I am using this code but still I am not able to see the button in the window
This code wouldn't execute neither pack method nor the mainloop because you are missing the parentheses when invoking functions. When you invoke functions without parentheses, you are only referencing to them instead of calling, so it means that the code inside the function will never be executed.
from tkinter import *
root = Tk()
mybutton = Button(root, text="Click me!")
mybutton.pack()
root.mainloop()
Modifying your code as shown above should solve your issue.
I have a script which has two tkinter.Tk() objects, two windows. One is hidden from the start (using .withdraw()), and each has a button which hides itself and shows the other (using .deiconify()). I use .mainloop() on the one shown in the beginning. Everything works, but when I close either window, the code after the mainloop() doesn't run, and the script doesn't end.
I suppose this is because one window is still open. If that is the case, how do I close it? Is it possible to have a check somewhere which closes a window if the other is closed?
If not, how do I fix this?
The essence of my code:
from tkinter import *
window1 = Tk()
window2 = Tk()
window2.withdraw()
def function1():
window1.withdraw()
window2.deiconify()
def function2():
window2.withdraw()
window1.deiconify()
button1 = Button(master=window1, text='1', command=function1)
button2 = Button(master=window2, text='2', command=function2)
button1.pack()
button2.pack()
window1.mainloop()
Compiling answers from comments:
Use Toplevel instead of multiple Tk()s. That's the recommended practice, because it decreases such problems and is a much better choice in a lot of situations.
Using a protocol handler, associate the closing of one window with the closing of both. One way to do this is the following code:
from _tkinter import TclError
def close_both():
for x in (window1,window2):
try:
x.destroy()
except TclError:
pass
for x in (window1,window2):
x.protocol("WM_DELETE_WINDOW", close_both)
In tkinter, when a button has the focus, you can press the space bar to execute the command associated with that button. I'm trying to make pressing the Enter key do the same thing. I'm certain I've done this in the past, but I can't find the code, and what I'm doing now isn't working. I'm using python 3.6.1 on a Mac.
Here is what I've tried
self.startButton.bind('<Return>', self.startButton.invoke)
Pressing the Enter key has no effect, but pressing the space bar activates the command bound to self.startButton. I've tried binding to <KeyPress-KP_Enter> with the same result.
I also tried just binding to the command I want to execute:
self.startButton.bind('<Return>', self.start)
but the result was the same.
EDIT
Here is a little script that exhibits the behavior I'm talking about.
import tkinter as tk
root = tk.Tk()
def start():
print('started')
startButton.configure(state=tk.DISABLED)
clearButton.configure(state=tk.NORMAL)
def clear():
print('cleared')
clearButton.configure(state=tk.DISABLED)
startButton.configure(state=tk.NORMAL)
frame = tk.Frame(root)
startButton = tk.Button(frame, text = 'Start', command = start, state=tk.NORMAL)
clearButton = tk.Button(frame, text = 'Clear', command = clear, state = tk.DISABLED)
startButton.bind('<Return>', start)
startButton.pack()
clearButton.pack()
startButton.focus_set()
frame.pack()
root.mainloop()
In this case, it works when I press space bar and fails when I press Enter. I get an error message when I press Enter, saying that there an argument was passed, but none is required. When I change the definition of to take dummy argument, pressing Enter works, but pressing space bar fails, because of a missing argument.
I'm having trouble understanding how wizzwizz4's answer gets both to work. Also, I wasn't seeing the error message when I pressed Enter in my actual script, but that's way too long to post.
** EDIT AGAIN **
I was just overlooking the default value of None in Mike-SMT's script. That makes things plain.
Your use of self.startButton.bind('<Return>', self.start) should work fine as long as compensate for the event that the bind will send to the function/method.
Here is a simple example that will work with the enter key as long as the button has focus.
import tkinter as tk
root = tk.Tk()
def do_something(event=None):
print("did something!")
btn = tk.Button(root, text="Do something", command=do_something)
btn.pack()
btn.bind("<Return>", do_something)
#root.bind("<Return>", do_something) will work without the button having focus.
root.mainloop()
This only works when the button has keyboard focus. Also, an argument representing the event object is passed to the callable provided. The former doesn't seem to be the problem, so try:
self.startButton.bind('<Return>', lambda e: self.startButton.invoke())
I work with Python 3.5 and TKinter.
I defined a label and file dialog that updates this label.
A button is responsible to launch this dialog.
self.sel_folder_val = the label that will be updated.
The code:
self.sel_folder_val['text']=filedialog.askdirectory()
After pressing the button in order to launch this dialog, the button stays pressed. Any dialog that a button is responsible to open cause the button to stay low (pressed) after closing this dialog.
I have tried this also with no help...:
self.select_folder_btn.config(relief=RAISED)
Code example:
self.select_folder_btn = Button(self.top)
self.select_folder_btn.place(relx=0.07, rely=0.57, height=34, width=187)
self.select_folder_btn.configure(activebackground="#d9d9d9")
self.select_folder_btn.configure(activeforeground="#000000")
self.select_folder_btn.configure(background="#d9d9d9")
self.select_folder_btn.configure(disabledforeground="#a3a3a3")
self.select_folder_btn.configure(font=self.font3)
self.select_folder_btn.configure(foreground="#000000")
self.select_folder_btn.configure(highlightbackground="#d9d9d9")
self.select_folder_btn.configure(highlightcolor="black")
self.select_folder_btn.configure(pady="0")
self.select_folder_btn.configure(text='''Select destination folder''')
self.select_folder_btn.bind('<Button-1>',self.update_folder_value)
def update_folder_value(self,event):
self.sel_folder_val['text']=filedialog.askdirectory()
return
After executing update_folder_value() function, self.select_folder_btn stays down.
I used the command:
self.select_folder_btn.configure(command=self.update_folder_value)
Instead of bind:
self.select_folder_btn.bind('<Button-1>',self.update_folder_value)
It solved my problem.
Thanks
First for future reference this is a minimal working example:
from Tkinter import *
import tkFileDialog as filedialog
class app:
def __init__(self):
self.top = Tk()
self.select_folder_btn = Button(self.top)
self.select_folder_btn.place(relx=0.07, rely=0.57, height=34, width=187)
self.select_folder_btn.configure(activebackground="#d9d9d9")
self.select_folder_btn.configure(activeforeground="#000000")
self.select_folder_btn.configure(background="#d9d9d9")
self.select_folder_btn.configure(disabledforeground="#a3a3a3")
#self.select_folder_btn.configure(font=self.font3)
self.select_folder_btn.configure(foreground="#000000")
self.select_folder_btn.configure(highlightbackground="#d9d9d9")
self.select_folder_btn.configure(highlightcolor="black")
self.select_folder_btn.configure(pady="0")
self.select_folder_btn.configure(text='''Select destination folder''')
self.select_folder_btn.configure(command=self.update_folder_value)
self.sel_folder_val = {}
self.top.mainloop()
def update_folder_value(self):
self.sel_folder_val['text']=filedialog.askdirectory()
self.top.update_idletasks()
app()
and even that's not minimal. Second your problem is hard to find since this isn't minimal- you're doing something really weird - binding the button to a click. You're overriding the built-in binding, and apparently it still affects the state of the button on press, but not going back. What you wanted is:
self.select_folder_btn.configure(command=self.update_folder_value)
instead of your:
self.select_folder_btn.bind('<Button-1>',self.update_folder_value)
You could also define that in the Button command. What you did is bypassed the button mechanism, so apparently only half of it is executed, and the relief is not raised. Note you have to remove the event parameter your method accepts.
I am using tkMessageBox.showinfo (info at tutorialspoint) to popup warnings in my program.
The problem happens only when the warning is called with a second TopLevel window (apart from the main one) on screen: in this case the warning remains hidden behind the second TL window.
I tried to call it thus:
tkMessageBox.showinfo(title='Warning',message=s).lift()
but it doesnt work. Any ideas?
I think the message box is only ever guaranteed to be above its parent. If you create a second toplevel and you want a messagebox to be on top of that second window, make that second window the parent of the messagebox.
tl2 = tk.Toplevel(...)
...
tkMessageBox.showinfo("Say Hello", "Hello World", parent=tl2)
I do not see the issue that you describe. The code I wrote below is just about the minimum needed to create a window which creates a second window. The second window creates an info box using the showinfo method. I wonder whether you have something besides this. (Note that I made the windows somewhat large in order to attempt cover up the info window.)
from Tkinter import Tk, Button, Toplevel
import tkMessageBox
top = Tk()
def make_window():
t = Toplevel(top)
t.title("I'm Window 2. Look at me too!")
B2 = Button(t, text = "Click me", command = hello)
B2.pack()
t.geometry('500x500+50+50')
def hello():
tkMessageBox.showinfo("Say Hello", "Hello World")
B1 = Button(top, text = "New Window", command = make_window)
B1.pack()
top.title("I'm Window 1. Look at me!")
top.geometry('500x500+100+100')
top.mainloop()
This was tested on Windows 7 (64-bit) using Python 2.7 (32-bit). It produces something like this: