2017-08-02 105 views
0

我想通过使用matplolib中的一些按钮来控制某些函数的执行。 我想暂停的功能,这是在我的情况下,打破了循环的执行,对于我用我的脚本如下:Python - 打破外部函数的循环

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:我发现以下问题具有相同的标题,How to break a loop from an outside function,但是,答案是根据循环中的值打破,而不是一个值从外面。

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() 
+3

听起来像你的问题真的在于你正在一个线程中执行所有的事情。您通常需要一个单独的线程来处理鼠标点击(和其他UI操作)。在这种情况下,你的解决方案应该工作(ish)。 – acdr

回答

0

像这样的东西可能工作更OOP的做法....从GUI事件处理程序

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) 
+0

我试图在我的代码的更新版本中做类似的事情,仍然无法正常工作。 – philippos

1

回调应该完成快,否则他们撑起负责处理事件的线程。这意味着您不能在回调函数中执行如下操作: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() 
+0

我试图在我的代码的更新版本中做类似的事情,仍然无法正常工作。 – philippos