如果这个问题的答案很明显,我很抱歉,但我不熟悉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()时应等待用户输入。诀窍是我希望它等待按下按钮而不是文本+输入。
答案 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
。