1

In python 2.7 if i click a button when a loop is running IDLE stops working till python comes out of the loop. I've attached my entire code as I don't have any idea why would this be happening.

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

Here both buttons work fine in first go but second time neither the value of x gets updated when I click on stop nor the button works till python comes out of the loop. Can anybody tell why this is happening.

0

2 Answers 2

1

Yes, the program executes the for() before doing anything else. To bypass that you will have to use some container that can be shared by both the thread and the main program in real time to stop the for() in midstream (in Multiprocessing it is a manager dictionary or list, don't know what it is in Threading), or use Tkinter's after method doing something similar to the code below which uses class instance objects/attributes (variables in this code) that can be seen and used through out the class. 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()
Sign up to request clarification or add additional context in comments.

3 Comments

:/ is it possible without the use of classes?
:D i know and i certainly will @BillalBEGUERADJ but i've not used them in my project where this code is required ^_^' thats why i was asking if it can be done without classes
I got the answer :) without classes... but what @joe did was the right thing to do ... i'll attach an answer anyway..
1

Only needed to use variable.get() and set() along with root.update() at the end of the loop.

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

But I would say classes are a better way to do this :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.