问题
I want to prompt user to choose between yes and no in the middle of a function and then continue the function accordingly. How is it possible?
Here is my code:
def download_popup(file_name, url, size, threshold):
root = Tk()
label = Label(root,
text="The file {file} at {url} is {size}Bytes large which is larger than your threshold({threshold})."
"\nShall I still download it?".format(file_name, url, size, threshold))
yes = ttk.Button(root, width=5, text="yse",
command=lambda: return True)
no = ttk.Button(root, width=5, text="no",
command=lambda: return False)
label.grid(column=0, row=0, colspan=2)
yes.grid(column=0, row=1)
no.grid(column=1, row=1)
mainloop()
# somewhere else in the middle of a function I have:
if response.getheader('Content-Length') > setting.download_threshold_var.get():
# I want the function to wait in this line:
if download_popup(file, url, response.getheader('Content-Length'), setting.download_threshold_var.get()):
out_file.write(response.read())
Of course my code is nonsense I just put it to show better what it is like that I actually want.
By the way I can fix it by splitting the function to 3 functions in a way that first function calls download_popup() and download_popup calls either the second or third function according to the user choice but I want a more elegant solution.
回答1:
The simplest solution is to use one of the predefined dialogs, such as askyesno
. If you want your own dialog, the pattern is to create an instance of a Toplevel
, and then call wait_window
which will not return until the window is destroyed.
Using predefined dialogs
In python 3, the built-in dialogs are in the sub-module messagebox
. To ask a yes/no question you can use askyesno
. For example:
import tkinter as tk
from tkinter import messagebox
def download_popup(file_name, url, size, threshold):
...
answer = tk.messagebox.askyesno("Confirmation", "The file...")
if answer:
print("you answered yes")
else:
print("you answered no")
Creating your own dialog
The key is to create a toplevel, then wait for it to be destroyed. To get the value from the dialog, you can use a global or instance variable.
It's usually best to use a class rather than a global variable, but simplicity I'll give an answer that uses a global variable:
def download_popup(file_name, url, size, threshold):
global result
result = False
def do_yes():
global result
result = True
dialog.destroy()
def do_no():
global result
result = False
dialog.destroy()
dialog = tk.Toplevel()
...
dialog.wait_window(dialog)
print("you chose %s" % result)
回答2:
You can use the command
attribute of a Button
widget to call a def
.
This means you don't have to put everything on hold to get the user's answer. You can just setup two def
's (or one and pass in a different parameter at the start) and call them when the button's are pressed.
See below:
from tkinter import *
root = Tk()
def yes():
print("The user pressed yes, now do something you fool!")
def no():
print("Oh no, they pressed no. Quick, panic!")
yes = Button(root, text="Yes", command=yes)
no = Button(root, text="No", command=no)
yes.pack()
no.pack()
root.mainloop()
If you need this to be done with one function you can use something like the below:
from tkinter import *
root = Tk()
def callback(self, *args):
print(boolean.get())
boolean = BooleanVar()
boolean.trace("w", callback)
yes = Button(root, text="Yes", command=lambda: boolean.set(True))
no = Button(root, text="No", command=lambda: boolean.set(False))
yes.pack()
no.pack()
root.mainloop()
来源:https://stackoverflow.com/questions/46446246/python-how-to-wait-for-user-trigger-in-the-middle-of-a-function