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

时间:2016-06-22 17:06:53

标签: python python-3.x user-interface tkinter wait

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

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

我该如何实现?

为了澄清,我希望它像input()一样工作,因为它会暂停所有内容并等待函数调用得到解决,除了我不希望它与文本绑定,而是GUI按钮。我计划使用Tkinter制作按钮。

我最初的想法是做一个像这样的循环:

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

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

1 个答案:

答案 0 :(得分:1)

如果你打算使用GUI按钮(特别是tkinter),你不需要做任何事情 - GUI往往会运行自己的无限循环来处理绘图和处理事件。在你为tkinter提供.mainloop()的那一刻,除了回调和tkinter事件之外,你的代码中的任何一点之后都不会被执行;即:

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

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

为了做你想做的事情,我建议在长期运行的代码的开头放一个Button.disable()(所以按钮看起来不可点击),然后在Button.enable()处结束,这样你就可以点击它。或者创建/显示按钮以在函数结束时执行下一步(在运行中创建该按钮可以让您将此函数的结果直接传递到通过lambdas的下一个函数的回调中)

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的mainloop再次安排自己,而不会阻止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