Python - how to wait for user trigger in the middle of a function?

你说的曾经没有我的故事 提交于 2021-02-05 11:12:27

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!