2013-08-28 2 views
3

Я новичок в Tkinter, поэтому прошу прощения, если это легко, но я ищу пару часов и не могу понять это. Я хочу сделать это после того, как mainlop простаивает, я всегда хочу вызвать функцию checkForGroupUpdates(). Когда я запускаю код ниже, он запускается только один раз. Я не могу понять, чтобы он запускался каждый раз, когда mainloop простаивает. Я ценю помощь.Tkinter только вызывает after_idle один раз

from Tkinter import * 
import random 

class Network(Frame): 
    """ Implements a stop watch frame widget. """                
    def __init__(self, parent=None, **kw):  
     Frame.__init__(self, parent, kw) 
     self.makeWidgets()  

    def makeWidgets(self):      
     """ Make the time label. """ 
     self._canvas = Canvas(self, width=600, height=400) 
     self._canvas.pack() 

    def checkForGroupUpdates(self): 
     print "checking" 
     h=0 
     this=10 
     while this>.0001: 
      this=random.random() 
      print h 
      h=h+1 
     print "checked" 


def main(): 
    root = Tk() 
    nw = Network(root) 
    nw.pack(side=TOP) 

    root.after_idle(nw.checkForGroupUpdates) 
    root.mainloop() 


if __name__ == '__main__': 
    main() 
+0

Что вы подразумеваете под «каждый раз, когда mainloop бездействует»? Обычно он простаивает, за исключением случаев, когда вы нажимаете кнопки. –

+0

Да, в идеале я бы хотел, чтобы вышеуказанная программа по существу непрерывно запускала checkForGroupUpdates(), поскольку mainloop обычно должен быть простаивающим большую часть времени. Я бы хотел, чтобы checkForGroupUpdates() запускался каждый раз, когда mainloop простаивает. – user1763510

+0

Итак, вы хотите, чтобы он выполнялся тысячи раз в секунду, когда программа ничего не делает? Нужно ли часто запускаться так часто или может выполняться всего несколько раз в секунду? Если он запускается непрерывно, пока приложение не работает, редко бывает более полезным, чем просто называть его несколько раз в секунду. –

ответ

7

Вместо вызова функции все время, когда приложение находится в режиме ожидания, вы должны назвать его просто один раз каждую долю секунды. Например, если вы хотите проверить, в 10 раз каждую секунду вы могли бы сделать что-то вроде этого:

def checkForGroupUpdates(self): 
    <do whatever you want> 
    self.after(100, self.checkForGroupUpdates) 

После вызова этой функции один раз, он будет организовать для себя назвать еще раз в 100мс. Это будет продолжаться до выхода программы. Если программа переходит в нерабочее состояние (то есть: при нажатии кнопки), эта функция будет приостановлена, так как tkinter является однопоточным. После повторного запуска программы проверка будет продолжена.

4

@ user1763510, обратите внимание, что в ответе Брайана Оукли у него есть checkForGroupUpdates еще раз позвонить self.after. Это связано с тем, что self.after выполняет только звонок, поэтому для повторных вызовов требуется, чтобы он вызывал себя внутри функции, вызываемой первым вызовом. Таким образом, он продолжает неоднократно называть себя.

То же самое касается функции after_idle(). Вы должны иметь checkForGroupUpdates еще раз позвонить after_idle() внизу.

Вот документация для after, after_idle и т. Д. В описании after есть даже небольшой пример, что делает его понятным.

Документация: http://effbot.org/tkinterbook/widget.htm

Пример из указанной выше ссылке, под after описание:

#Method 1 
class App: 
    def __init__(self, master): 
     self.master = master 
     self.poll() # start polling 

    def poll(self): 
     ... do something ... 
     self.master.after(100, self.poll) 

Чтобы использовать after_idle вместо этого, он будет выглядеть следующим образом:

#Method 2 
class App: 
    def __init__(self, master): 
     self.master = master 
     self.poll() # start polling 

    def poll(self): 
     ... do something ... 
     self.master.update_idletasks() 
     self.master.after_idle(self.poll) 

Обратите внимание на добавление линия self.master.update_idletasks(). Это рисует графический интерфейс и обрабатывает нажатия кнопок и все. В противном случае after_idle() будет всасывать все ресурсы и не допускать самообновления графического интерфейса пользователя в mainloop().

Альтернативой использованию

 self.master.update_idletasks() 
     self.master.after_idle(self.poll) 

является использование:

 #Method 3 
     self.master.update_idletasks() 
     self.master.after(0, self.poll) 

Использование self.master.after(0, self.poll) мой предпочтительный метод, так как это позволяет мне легко изменить 0 на что-то другое, если я решу я не Не нужно постоянно запускать self.poll. Увеличивая время задержки до по меньшей мере 1 мс, вам больше не нужно звонить self.master.update_idletasks().Таким образом, это тоже работает:

 #Method 4 
     self.master.after(1, self.poll) 

заметить также, что для всех приведенных выше примеров, вызывая self.poll() в функции __init__ является то, что пинает все это, и хранение master в self.master необходимо просто так, что внутри poll вы можете позвонить after или after_idle функция через self.master.after_idle, например.

В: Стабилен ли он/он работает?
A: Я проверил тестовый код, используя метод 3 чуть выше в течение ~ 21 часа, и он работал стабильно все время, позволяя графическому интерфейсу использоваться и все.

В: Каково сравнение скорости для каждого метода выше?
А:

  • Способ 1: (я не ускорить его испытание)
  • Метод 2: ~ 0,44 мс/итерации
  • Метод 3: ~ 0,44 мс/итерации
  • Метод 4 : ~ 1,61 мс/итерация

Вопрос: Каков мой предпочтительный метод?
A: Способ 3 или 4.

+0

Немного опасно называть 'after_idle' функцией, называемой' after_idle'. Что может случиться, так это то, что вы никогда не дадите tkinter возможность полностью разрядить очередь ожидания, а это значит, что у него никогда не будет возможности обслуживать любые другие события, которые могут быть отложены. –

+0

Разве это не значит, что 'update_idletasks()' решает? Я провел быстрый тест и, похоже, работает, как я уже говорил выше. Для '... делать что-то ...' Я печатаю «тест», и при печати в фоновом режиме графический интерфейс, который я создал, отображает. –

+0

Вы должны помнить, что эта функция вызывалась процессом tkinter, который обслуживает очередь ожидания. Итак, представьте себе функцию, которая отнимает один элемент (т. Е. Эта функция), выполняет его, а затем проверяет, есть ли что-то еще в очереди. Если есть, он обрабатывает его. Поэтому перед тем, как это сделать, вы добавите что-то новое в очередь. Он никогда не заканчивается из пунктов в очереди, потому что для каждого снятого предмета добавляется другое. Вложенный вызов 'update_idletasks' может исчерпать список, но вы сразу же добавляете новый, прежде чем текущий проход через очередь будет завершен. –

Смежные вопросы