2016-04-23 2 views
1

В python 2.7, если я нажимаю кнопку, когда цикл работает, IDLE перестает работать, пока python не выходит из цикла. Я прикрепил весь свой код, поскольку я не знаю, почему это произойдет.Кнопка не работает до конца текущего цикла в python

import time 
import Tkinter as tk 
from Tkinter import StringVar 
import threading 

x="False" 

def xval(*args): 
    for i in range(0,9): 
     global x 
     if(x=="False"): 
      print "x=false %d time"%i 
      time.sleep(1) 

def stop(event): 
       resume_btn.configure(state="normal") 
       global x 
       x ="True" 
       print "execution stopped:%s"%x 

def start(event): 
       global x 
       x ="False" 
       print "execution started:%s"%x 
       xval() 

root = tk.Tk() 

th = threading.Event() 
t = threading.Thread(target=xval,args=(th,)) 
t.deamon=True 
t.start() 

x_btn = tk.Button(root, text="Stop", background="Snow", width=20) 
x_btn.grid(row=0, column=4, sticky="W", padx=20, pady=5) 
x_btn.bind('<Button-1>',stop) 

resume_btn = tk.Button(root, text="Start", background="Snow", width=20) 
resume_btn.configure(state="disabled") 
resume_btn.grid(row=0, column=6, sticky="W", padx=20, pady=5) 
resume_btn.bind('<Button-1>',start) 

root.mainloop() 

Здесь обе кнопки работают отлично в первом ходу, но второй раз ни значения х обновляется, когда я нажимаю на остановке, ни кнопка работает до питон выходит из цикла. Может кто-нибудь сказать, почему это происходит.

ответ

1

Да, программа выполняет функцию for() перед тем, как делать что-либо еще. Чтобы обойти это, вам придется использовать какой-то контейнер, который может использоваться как потоком, так и основной программой в режиме реального времени, чтобы остановить for() в середине потока (в Multiprocessing это словарь или список менеджеров, не знаю, что это находится в Threading) или использовать метод Tkinter after, который делает что-то похожее на код ниже, который использует объекты экземпляра класса/атрибуты (переменные в этом коде), которые можно увидеть и использовать через класс. http://www.tutorialspoint.com/python/python_classes_objects.htm

import Tkinter as tk 

class StartStop(): 
    def __init__(self, root): 
     self.x="False" 
     self.ctr=0 

     x_btn = tk.Button(root, text="Stop", background="Snow", width=20) 
     x_btn.grid(row=0, column=4, sticky="W", padx=20, pady=5) 
     x_btn.bind('<Button-1>', self.stop) 

     self.resume_btn = tk.Button(root, text="Start", background="Snow", width=20) 
     self.resume_btn.configure(state="disabled") 
     self.resume_btn.grid(row=0, column=6, sticky="W", padx=20, pady=5) 
     self.resume_btn.bind('<Button-1>', self.start) 


    def xval(self): 
     if self.x=="False": 
      print "x=false %d=counter value"%self.ctr 
      self.ctr += 1 
      if self.ctr < 9: 
       ## after gives the program time to update 
       ## time.sleep() stops everyting 
       root.after(1000, self.xval) 

    def stop(self, event): 
      self.resume_btn.configure(state="normal") 
      self.x ="True" 
      print "execution stopped:%s"%self.x 

    def start(self, event): 
      self.x ="False" 
      print "execution started:%s"%self.x 
      self.ctr=0 
      self.xval() 

root = tk.Tk() 
S=StartStop(root) 
root.mainloop() 
+0

:/возможно без использования классов? – YSR

+0

Занятия хорошими манерами. Вы должны учиться хорошим манерам. @ YSR –

+0

: D я знаю, и я, конечно, буду @BillalBEGUERADJ, но я не использовал их в своем проекте, где этот код требуется^_^'Вот почему я спрашивал, можно ли это сделать без классов – YSR

1

только нужно использовать variable.get() и набор() вместе с root.update() в конце цикла.

import time 
import Tkinter as tk 
from Tkinter import StringVar 
import threading 
global root 
root = tk.Tk() 
x = tk.StringVar() 
x.set('false') 

def xval(*args): 
    try: 
     for i in range(0,9): 
      global x 
      print x.get() 
      if x.get()== 'false' : 
       print "x=false %d time"%i 
       time.sleep(1) 
      else: 
       print "waiting" 
      root.update() 
    except: 
     pass 

def stop(event): 
       resume_btn.configure(state="normal") 
       global x 
       x.set('true') 
       print "execution stopped:%s"%x 


def start(event): 
       global x 
       x.set('false') 
       print "execution started:%s"%x 
       xval() 


root.title("GUI-Data Retrieval") 
th = threading.Event() 
t = threading.Thread(target=xval,args=(th,)) 
t.deamon=True 
t.start() 
x_btn = tk.Button(root, text="Stop", background="Snow", width=20) 
x_btn.grid(row=0, column=4, sticky="W", padx=20, pady=5) 
x_btn.bind('<Button-1>',stop) 
resume_btn = tk.Button(root, text="Start", background="Snow", width=20) 
resume_btn.configure(state="disabled") 
resume_btn.grid(row=0, column=6, sticky="W", padx=20, pady=5) 
resume_btn.bind('<Button-1>',start) 
root.mainloop() 

Но я бы сказал, классы лучший способ сделать это :)