我想使用ipywidgets按钮使我的脚本具有交互性。但我认为我缺少的GUI和线程有一些非常基础:按钮触发的功能似乎只在主脚本完成时调用!
我想实现这个GUI的方式是我的主循环执行一些计算并检查GUI在每次迭代时设置的参数。
让我们看一下这个例子,我们有一个开关按钮,然后应该改变主循环是执行一个还是另一个计算:
不工作示例
from ipywidgets import widgets
import threading, time
SWITCH = False
def onclick_switch(b):
global SWITCH
SWITCH = not SWITCH # toggle
print('Button clicked! Switch: %s'%(SWITCH))
# set up GUI
button = widgets.Button( description='Switch')
button.on_click( onclick_switch )
display(button)
while True:
if SWITCH:
res = 2*2 # do sophisticated calculations / plots etc
print('result: %s'%(res))
else:
res = 3*3 # do sophisticated calculations / plots etc
print('result: %s'%(res))
time.sleep(1)
按预期显示“切换”按钮,每秒打印第二次计算结果(“结果:9”)。但是,开关没有效果。只有在中断内核后才会评估按钮点击次数!
所以我想到如何将main函数放在一个单独的线程中,以免它干扰按钮?
近乎有效的例子
SWITCH = False
def onclick_switch(b):
global SWITCH
SWITCH = not SWITCH # toggle
print('Button clicked! Switch: %s'%(SWITCH))
# set up GUI
button = widgets.Button( description='Switch')
button.on_click( onclick_switch )
display(button)
def mainloop(): # loop is now a function
while True:
if SWITCH:
res = 2*2 # do sophisticated calculations / plots etc
print('result: %s'%(res))
else:
res = 3*3 # do sophisticated calculations / plots etc
print('result: %s'%(res))
time.sleep(1)
mainthread = threading.Thread( target = mainloop ) # let's use threading
mainthread.start()
这更接近我想要的东西:但它只执行一次(打印“结果:9”一次),并且只在第一次按下按钮后继续。
我无法理解这种行为。但我确实理解这对于GUI来说是一般性的,因为如果我使用mpl_connect(也许还有qt / tkinter?)它也是一样的。
在我发现的ipywidgets示例中,没有主循环,每当用户更改任何内容时,总是只有一次执行绘图函数。这不是我需要的,我需要一个主循环!
那么一般如何做呢?按钮如何在内部工作,以便在主循环运行时无法执行?多线程/ GUI在哪里出错?
我正在使用ipywidgets 7.1.1和jupyter 5.4.0 with python 2.7