如何让脚本等待按下按钮?

How can I make a script wait for a button press?

如果这个问题的答案很明显,我深表歉意,但我不熟悉 Python 的内部工作原理。

基本场景:我有一个 Python 脚本可以做一些事情。定期地,当满足某些条件时(如设置标志变量),我希望脚本暂停并等待用户按下 GUI 按钮。

我该如何实现?

澄清一下,我希望它像 input() 那样工作,因为它暂停一切并等待函数调用被解析,除了我不希望它绑定到文本,而是一个 GUI按钮。我打算使用 Tkinter 制作按钮。

我最初的想法是制作一个类似这样的 while 循环:

x = 2
while (x > 1):
    #do nothing

然后按钮将调用一个设置 x = 0 的函数

这是执行此操作的正确方法吗?有没有更好的办法?我是否遗漏了一些明显的东西?

示例代码:

class Displayable(object):
    max_display_level = 1   # can be overridden in subclasses
    manual_step = False     # can be overridden in subclasses

    def display(self,level,*args,**kwargs):
        -Do stuff unrelated to the question-

        if (self.manual_step):
           if level <= self.max_display_level:
               input("Waiting for input: ")

这背后的想法是对象将扩展 class 可显示对象并设置它们自己的 max_display_level 和 manual_step 值。更高的 max_display_level 意味着将显示更多消息(即,如果我调用 display() 级别 = 1、2、3 和 4,如果我的 max_display_level ==2,则只有前 2 个调用将执行所有逻辑。这是一种允许用户设置执行详细程度的方法。它存在的原因我不会深入,但它应该保留。)如果特定对象具有 manual_step == true 并且水平满足,它应该在调用 display() 时等待用户输入。诀窍是我希望它等待按下按钮而不是文本+输入。

如果您打算使用 GUI 按钮(尤其是 tkinter),您不需要做任何事情 - GUI 倾向于 运行 它们自己的无限循环来处理绘图和处理事件。当你为 tkinter 使用 .mainloop() 时,除了回调和 tkinter 事件之外,代码中的任何内容都不会执行;即:

root= Tk()
root.mainloop()
print("This won't be printed until root window is closed")

最佳做法是将按下按钮时应该发生的事情作为 command/callback 绑定到该按钮。 (Button(master, ... command=callback OR command=lambda *e: callback()))

如您所愿,我建议在较长的 运行ning 代码开头放置一个 Button.disable()(这样按钮看起来不可点击),然后是Button.enable() 在最后,所以你可以点击它。或者 create/show 在函数末尾执行下一步的按钮(即时创建该按钮可以让您通过 lambda 将此函数的结果直接传递到下一个函数的回调中)

def cb_1(root_window, btn_to_disable):
    btn_to_disable.disable()
    foo = complex_algorithm()
    # Create a button for the next part
    Button(root_window, text='do cb_2 with foo',
           command=lambda e, arg=foo, r=root_window: cb_2(r, arg)).pack()

def cb_2(root, argument):
    print("This is foo, from cb_1:",argument) # prints foo

root = Tk()
btn = Button(root, text="do cb_1",
             command=lambda *e: cb_1(root, btn))
btn.pack()
root.mainloop()
print("This isn't printed until the GUI is closed!")

编辑:根据您的最新编辑,似乎 after() 将成为您的朋友 - 它允许函数通过 tkinter 的主循环再次安排自己,而不会阻止 GUI 的操作。即在 Displayable:

def display(self, level, *args, **kwargs):
    #unrelated#
    self.wait_for_next(level, *args, **kwargs)

def wait_for_next(self, level, *args, **kwargs)
    if self.manual_step:
       if (level <= self.max_display_level):
           if self.button_set_value:
               # Do something with button-set value
               print('FOO')
           else:
               # set ourselves to re-check after 1000 ms
               self.root.after(1000,
                               lambda *e:self.wait_for_next(level, *args, **kwargs))

大概,无论您的按钮在哪里,它们都会设置一些值(或只是设置一个标志)。当该值为真时,将打印 "FOO"。此时您可能会再次调用 display()。

另一种方法是简单地将 display() 作为按钮的回调,因此当按下按钮时,将调用 display