Python - 如何在函数中间等待用户触发?

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

我想提示用户在函数中间选择是和否,然后相应地继续该函数。怎么可能?

这是我的代码:

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())

当然我的代码是胡说八道,我只是为了更好地展示我真正想要的东西。

顺便说一下,我可以通过将函数拆分为 3 个函数来修复它,第一个函数调用 download_popup() 并且 download_popup 根据用户调用第二个或第三个函数选择,但我想要一个更优雅的解决方案。

您可以使用 Button 小部件的 command 属性来调用 def

这意味着您不必为了得到用户的答复而搁置一切。您可以只设置两个 def(或一个并在开始时传入不同的参数)并在按下按钮时调用它们。

见下文:

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()

如果您需要使用一个函数来完成此操作,您可以使用类似以下的函数:

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()

最简单的解决方案是使用预定义对话框之一,例如 askyesno。如果你想要自己的对话框,模式是创建一个 Toplevel 的实例,然后调用 wait_window,在 window 被销毁之前,它不会 return。

使用预定义的对话框

在python3中,内置对话框在子模块messagebox中。要提出 yes/no 问题,您可以使用 askyesno。例如:

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")

创建您自己的对话框

关键是创建一个顶层,然后等待它被销毁。要从对话框中获取值,您可以使用全局变量或实例变量。

通常最好使用 class 而不是全局变量,但为了简单起见,我将给出一个使用全局变量的答案:

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)