[英]Python - breaking a loop from an outside function
我想通过使用matplolib
某些按钮来控制某些功能的执行。 我想暂停执行一个函数,在本例中是为了中断for循环,因为我在脚本中使用了以下命令:
def pause(mouse_event):
global pauseVal
pauseVal ^= True
def play(mouse_event):
for x in range(int(dataSlider.val),len(listOfMomentsVis)):
if pauseVal == True:
break
else:
image.set_data(listOfMomentsVis[x])
fig.canvas.draw()
dataSlider.set_val(x+1)
time.sleep(timeSleep)
print(x)
发生的情况是该函数将在下次尝试执行时而不是在执行期间不执行 。 换句话说, pause
按钮在下一次执行之前不会生效。
我的问题是:如何通过外部按钮事件在执行过程中中断for循环? 那可行还是应该采用其他方式? (可以让for循环listen
外部函数吗?!)
PS:我发现了以下标题相同的问题,即如何从外部函数中断循环 ,但是,答案是根据循环中的值而不是外部值中断。
updae
这是我的脚本更新版本。 我考虑了评论和答案,做了一堂课,但仍然没有得到想要的结果。
class animationButtons():
def __init__(self):
self.pauseVal = False
def backward(self, mouse_event):
ref = int(dataSlider.val)
if ref-1<0:
print('error')
else:
image.set_data(listOfMomentsVis[ref-1])
dataSlider.set_val(ref-1)
def forward(self, mouse_event):
ref = int(dataSlider.val)
if ref+1>len(listOfMomentsVis):
ref = int(dataSlider.val)-1
print('error')
else:
image.set_data(listOfMomentsVis[ref])
dataSlider.set_val(ref+1)
print('from forward', dataSlider.val)
def play(self, mouse_event):
for x in range(int(dataSlider.val),len(listOfMomentsVis)):
ref = int(dataSlider.val)
dataSlider.set_val(ref+1)
time.sleep(timeSleep)
print('from play',ref)
if self.pauseVal:
break
def playReverse(self, mouse_event):
for x in range(int(dataSlider.val),0,-1):
ref = int(dataSlider.val)
dataSlider.set_val(ref-1)
time.sleep(timeSleep)
print('from play',ref)
if self.pauseVal:
break
def pause(self, mouse_event):
self.pauseVal ^= True
print(self.pauseVal)
def animate(self, val):
ref = int(dataSlider.val)
image.set_data(listOfMomentsVis[ref])
print('from animate',ref)
fig.canvas.draw()
来自GUI事件处理程序的回调应快速完成,否则它们将占用负责处理事件的线程。 这意味着您不能在回调函数中time.sleep(timeSleep)
。
相反,您可以使用计时器来定期触发动画事件,然后使用播放和暂停按钮来停止和启动计时器。 下面的示例创建一个移动的正弦波,该正弦波在移动了一个完整波长后会停止。 如果尚未播放动画,则按下播放会触发动画;如果当前正在暂停动画,则继续播放。 如果正在播放动画,则暂停将暂停动画。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.2) # add space for buttons
x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))
class Example:
steps = 200
def __init__(self):
self.step_index = 0
self.timer = None
def animate(self):
print(self.step_index)
# update the data
line.set_ydata(np.sin(x + (2 * np.pi * self.step_index / self.steps)))
self.step_index += 1
plt.draw()
# stop if end of animation
if self.step_index >= self.steps:
self.timer = None
return False
def play(self, event):
if not self.timer:
# no current animation, start a new one.
self.timer = fig.canvas.new_timer(interval=10)
self.timer.add_callback(self.animate)
self.step_index = 0
self.timer.start()
def pause(self, event):
if not self.timer:
return
self.timer.stop()
ex = Example()
ax_pause = plt.axes([0.7, 0.05, 0.1, 0.075])
ax_play = plt.axes([0.81, 0.05, 0.1, 0.075])
pause_button = Button(ax_pause, 'Pause')
pause_button.on_clicked(ex.pause)
play_button = Button(ax_play, 'Play')
play_button.on_clicked(ex.play)
plt.show()
像这样的事情可能更像是一种面向对象的方法。
class ClasName():
# Add any variables you want to keep track of...
def __init__(self, dataSlider, listOfMomentsVis):
self.paseVal = False
self.dataSlider = dataSlider
self.listOfMomentsVis = listOfMomentsVis
# Your methods to manipulate the class instance variables
def pause(self, mouse_event):
self.pauseVal ^= True
def play(self, mouse_event):
for x in range(int(self.dataSlider.val),len(self.listOfMomentsVis)):
if self.pauseVal == True:
# Reset the pauseVal state
self.pauseVal ^= False
break
else:
image.set_data(listOfMomentsVis[x])
fig.canvas.draw()
dataSlider.set_val(x+1)
time.sleep(timeSleep)
print(x)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.