Page 1 of 1

How to stop a running script in tkinter

Posted: Wed Feb 15, 2017 11:50 am
by joseplaselva
I'm making a GUI aplication with tkinter for a timelapse , when a start button initialize a counting process I would like to have the possibility of stop the process with another button and resset the aplication to the initial state. I don't know how to do because when the first button starts the script , all the buttons are blocked till scripts finalize.
Thanks in advance for your help

Re: How to stop a running script in tkinter

Posted: Wed Feb 15, 2017 1:08 pm
by scotty101
Sharing your code might help us to help you.

I'm willing to bet that you have used time.sleep to provide a delay between taking photographs. When using Tkinter, you shouldn't use (long) delays and you should make use of the .after method instead to trigger an event after a specified period of time.

There are a few examples and tutorials out there explaining how to use after. This one for example.

Re: How to stop a running script in tkinter

Posted: Wed Feb 15, 2017 3:28 pm
by joseplaselva
Thanks for your fast reply.
Well my code is not very prof, I'm very beginner. In resume My START button do many things:
start a delay
show the seconds of this delay in a labbel
show the status in another labbel
strart to shoot - wait an interval - shoot until the amount specified - showing the increase of shoots

and I just want to cancel this "procedure" to set the GUI in stand by again

Re: How to stop a running script in tkinter

Posted: Wed Feb 15, 2017 3:30 pm
by joseplaselva
Sorry I forgot the code:

import sys
from Tkinter import *
import RPi.GPIO as GPIO
import time
import tkMessageBox as tkmsg
from time import sleep

root = Tk()
root.title("test configuration")
root.geometry("480x320")
#estableix que no es pot redimensionar
root.resizable(0,0)

# variables text labels

var = StringVar()
vid = StringVar()
sec = IntVar()
bgcolor = StringVar()

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

GPIO.setup(25, GPIO.OUT)
GPIO.setup(24, GPIO.OUT)

delayshooting = 10
delayfilming = 3
interval = 2
nrshoots = 6
bgcolor = "green"
shoot = 1
delaysec = delayshooting
index = 0
selft = 5
var.set("D12-I6-T12")
sec.set(0)
vid.set("NO VIDEO")

root.update_idletasks()


# BOTO START-----------------------------------------------


def startshoot () :
global delayshooting
global delayfilming
global interval
global nrshoots
global index
global shoot
global delaysec
global tittel
global bgcolor
global selft

if selft == 5:
if index == 1:
vid.set("WAIT TO FILMING")
root.update_idletasks()
secf = delayfilming

for i in range(delayfilming):
sec.set(secf)
root.update_idletasks()
secf = secf-1
sleep(1)
elif index == 2:
vid.set("RECORDING")
bgcolor="red"
etfilm.configure(background=bgcolor)
root.update_idletasks()


for i in range (delaysec):
if index >0:
vid.set("RECORDING")
var.set("DELAY SHOOTING")
sec.set(delaysec)
root.update_idletasks()
delaysec = delaysec-1

else:
var.set("DELAY SHOOTING")
sec.set(delaysec)
root.update_idletasks()
delaysec = delaysec-1

sleep(1)

for i in range(nrshoots):
print "beep"
GPIO.output(25, GPIO.HIGH)
sleep(1)
GPIO.output(24, GPIO.HIGH)
sleep(0.3)
var.set("SHOOTING")
sec.set(shoot)
root.update_idletasks()
print " SHOOTING: " ,shoot
GPIO.output(24, GPIO.LOW)
sleep(0.3)
GPIO.output(25, GPIO.LOW)
if shoot==nrshoots:
print "end of roll"
print "beep, beep"
var.set("END ROLL")
root.update_idletasks()
sec.set(0)
sleep(delayfilming)
vid.set("NO VIDEO")
var.set("D12-I6-T12")
root.update_idletasks()
print "stop filming"
else:
sleep(interval)
shoot = shoot+1

delayshooting = 3
delayfilming = 3
interval = 3
nrshoots = 3
index = 0
shoot = 1
delaysec = delayshooting
GPIO.cleanup
print"END PROCESS"
else:
print"STARTINTG SELTIMER"
print selft
sect = selft
for i in range (selft):
var.set("SELFTIMMER ON")
sec.set(sect)
root.update_idletasks()
sect = sect-1
sleep(1)
var.set("D12-I6-T12")
sec.set(0)
selft = 5
root.update_idletasks()


# BOTO STOP/RESET--------------------------------------------

def stopproces ():
root.destroy()

# BOTO ACTIVATE VIDEO----------------------------------

def video():
global index
if index == 0:
vid.set("VIDEO ON-OFF")
elif index ==1:
vid.set("VIDEO ONLY OFF")
else:
vid.set("NO VIDEO")
root.update_idletasks()

if index ==2:
index = 0
else:
index = index + 1


# BOTO STOP VIDEO --------------------------------------

def videostop():
global index
index=0
vid.set("NO VIDEO")
root.update_idletasks()

# BOTO SELFTIMER ---------------------------------------

def selftimer():
global selft
selft = selft + 5
sec.set(selft)
var.set("SELFTIMER ON")
root.update_idletasks()


# BOTO SELFTIMER STOP---------------------------------------

def selftimerStop():
global selft
sec.set(0)
var.set("D12-I6-T12")
root.update_idletasks()
selft = 5

# LABELS--------------------------------------------------------------------------------------------

etfilm = Label(root,width=12, font=('arial narrow', 14, 'normal'),fg="white", bg=bgcolor, textvariable=vid)
etfilm.grid(row=0, column=0,columnspan=1, padx=3, pady=2, sticky=NSEW)


etstatus = Label(root,width=12, font=('arial narrow', 14, 'normal'),bg="yellow", textvariable=var)
etstatus.grid(row=0, column=1,columnspan=1, padx=3, pady=2, sticky=NSEW)



etnum = Label(root, relief=SUNKEN, font=('arial', 18, 'normal'), textvariable=sec)
etnum.grid(row=0, column=2, ipadx=13, padx=0, sticky=NSEW)

# BUTTONS-------------------------------------------------------------------------------------------------

botshoot = Button(root, width=18, font=('arial narrow', 30, 'normal'), text="START ", activebackground="#00dfdf")
botshoot.grid(row=4, rowspan=2, column=0,columnspan=3,ipady=15,pady=1, sticky=NSEW)
botshoot.configure(command=startshoot)

botkam = Button(root,width=10, font=('arial', 24, 'normal'), text="VIDEO SETTINGS", activebackground="#00dfdf")
botkam.grid(row=6, rowspan=3, column=0,columnspan=2, pady=1, sticky=NSEW)
botkam.configure(command=video)

botkamStop = Button(root,width=3, font=('arial', 24, 'normal'), text="STOP", activebackground="#00dfdf")
botkamStop.grid(row=6, rowspan=3, column=2, pady=1, sticky=NSEW)
botkamStop.configure(command=videostop)

botSelf = Button(root,width=10, font=('arial', 24, 'normal'), text="ACTIVATE SELFTIMER", activebackground="#00dfdf")
botSelf.grid(row=9, rowspan=3, column=0,columnspan=2, pady=1, sticky=NSEW)
botSelf.configure(command=selftimer)

botSelf1 = Button(root,width=3, font=('arial', 24, 'normal'), text="STOP", activebackground="#00dfdf")
botSelf1.grid(row=9, rowspan=3, column=2, pady=1, sticky=NSEW)
botSelf1.configure(command=selftimerStop)

botConf = Button(root,heigh=2, font=('arial', 18, 'normal'), text="CONFIGURE", activebackground="red")
botConf.grid(row=12, rowspan=3, column=0,columnspan=1, pady=1, sticky=NSEW)

botStop = Button(root,heigh=2, font=('arial', 18, 'normal'), text="STOP/RESET", activebackground="red")
botStop.grid(row=12, rowspan=3, column=1,columnspan=2, pady=1, sticky=NSEW)
botStop.configure(command=stopproces)


root.mainloop()

Re: How to stop a running script in tkinter

Posted: Thu Feb 16, 2017 1:38 pm
by Davies
hi joseplaselva
please add your code using the code button

Code: Select all

if you use code:
    your indentations will be displayed correctly

Re: How to stop a running script in tkinter

Posted: Thu Feb 16, 2017 2:58 pm
by ghp
Hello,
in my programs, I use threads and queues to 'decouple' background processes.
The GUI writes commands to a commandQueue. This is very fast and the GUI keeps responsive.
A commandThread reads the commandQueue and performs actions as needed. In the example, it sets the direction for a counter which is running separately. The 'runIt-variable is needed to terminate the threads on exit.
Hope this helps,
Gerhard

Code: Select all

#!/usr/bin/python
# -*- coding: utf-8 -*-

from Tkinter import Tk, RIGHT, BOTH
from ttk import Frame, Button, Style, Label

import Queue
import time
import threading
#
# counter is only used to have some possibility to 
# draw current position on GUI
#
class Counter:
    def __init__ (self):
        self.counter = 0
    def increment(self, val):
        self.counter += val
        print(self.counter)   
         
counter = Counter()

class GUI(Frame):
    def __init__(self, parent, commandQueue):
        self.commandQueue = commandQueue
        Frame.__init__(self, parent)   
         
        self.parent = parent
        
        self.initUI()
        parent.protocol("WM_DELETE_WINDOW", self.exitAction)
        parent.after(300, self.refresh)
    
    def refresh(self):
        self.text.config(text= "current: {c:d}". format(c=counter.counter))
        self.text.pack

        self.parent.after(300, self.refresh)
             
    def exitAction(self):
        print("exitAction")
        self.commandQueue.put("exit")
        self.parent.destroy()
        
    def rightAction(self):
        print("rightAction")
        self.commandQueue.put("right")
        
    def stopAction(self):
        print("stopAction")
        self.commandQueue.put("stop")
        
    def leftAction(self):
        print("leftAction")
        self.commandQueue.put("left")
        
    def initUI(self):
      
        self.parent.title("Background")
        self.style = Style()
        self.style.theme_use("default")
        
        # frame = Frame(self, relief=RAISED, borderwidth=1)
        # frame.pack(fill=BOTH, expand=1)
        
        self.pack(fill=BOTH, expand=1)
        
        self.text= Label(self,text='start', font=(None, 20))
        self.text.pack()
        
        rightButton = Button(self, text="right", command = self.rightAction)
        rightButton.pack(side=RIGHT, padx=5, pady=5)
        stopButton = Button(self, text="stop", command = self.stopAction)
        stopButton.pack(side=RIGHT, padx=5, pady=5)
        leftButton = Button(self, text="left", command=self.leftAction)
        leftButton.pack(side=RIGHT)

class DoSomethingInBackground:
    def __init__(self, commandQueue):
        self.commandQueue = commandQueue
        
        self.runIt = True
        self.direction = 0
        
        # commandThread reads commands from a queue and executes them
        self.commandThread = threading.Thread(target=self.run_command)
        self.commandThread.start()
        
        # this is the basic execution engine
        self.executeThread = threading.Thread(target=self.run_something)
        self.executeThread.start()
        
        
        
    def run_something(self):
        while self.runIt:
            time.sleep(0.7)
            global counter
            counter.increment( self.direction )
         
    def run_command(self):
        while self.runIt:
            try:
                s = self.commandQueue.get(True, 0.1)
            except Queue.Empty:
                continue
            if s == 'right':
                self.direction = 1
            if s == 'left':
                self.direction = -1
            if s == 'stop':
                self.direction = 0
               
            if s == 'exit':
                self.runIt = False        
                
def main():
  
    commandQueue = Queue.Queue()
    doSomethingInBackground = DoSomethingInBackground(commandQueue)
    
    root = Tk()
    root.geometry("300x200+300+300")
    app = GUI(root, commandQueue)
    root.mainloop()  


if __name__ == '__main__':
    main() 

Re: How to stop a running script in tkinter

Posted: Sat Feb 18, 2017 2:15 pm
by joseplaselva
Many thanks Gerhard. Big help , I apreciate very much

Re: How to stop a running script in tkinter

Posted: Sun Feb 19, 2017 1:45 pm
by RogerW
Threads are very powerful but do need car. Tkinter widgets have a function "after" which alows a function to be called after a given delay. It is not precise but can ofter be adequate. This might offer a simpler solution.

Code: Select all

import tkinter as tk

class Mainframe(tk.Frame):
    # Mainframe contains the widgets
    # More advanced programs may have multiple frames
    # or possibly a grid of subframes
    
    def __init__(self,master,*args,**kwargs):
        # *args packs positional arguments into tuple args
        #  **kwargs packs keyword arguments into dict kwargs
        
        # initialise base class
        tk.Frame.__init__(self,master,*args,**kwargs)
        # in this case the * an ** operators unpack the parameters
        
        # put your widgets here
        self.counter_message = tk.IntVar()
        tk.Label(self,textvariable = self.counter_message).grid(row = 0,column = 0)
        tk.Button(self,text ="Start",command = self.do_start).grid(row = 1,column = 0)
        tk.Button(self,text ="Stop",command = self.do_stop).grid(row = 2,column = 0)
        
        self.count = 0
        self.delay = 100
        self.max_count = 100
        self.stop_count = False

        
    def bump_count(self):
        # see if we should aboort
        if self.stop_count:
            return
        
        self.count += 1
        # Now keep going or do end of timer processing
        if self.count < self.max_count:
            self.counter_message.set(self.count)
            self.after(self.delay,self.bump_count)
        else:
            # counter has reached the end without interruption
            # so put code here
            pass
    
    def do_start(self):
        # called when start button pressed
        self.stop_count = False
        self.count = 0
        self.counter_message.set(self.count)
        self.after(self.delay,self.bump_count)
        
    def do_stop(self):
        # called when stop button pressed
        self.stop_count = True
    
class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
               
        # set the title bar text
        self.title('Counter Demo')
        # Make sure app window is big enough to show title 
        self.geometry('300x100')
      
        # create and pack a Mainframe window
        Mainframe(self).pack()
        
        # now start
        self.mainloop()
                    
# create an App object
# it will run itself
App()

Re: How to stop a running script in tkinter

Posted: Sun Feb 19, 2017 2:22 pm
by joseplaselva
Thanks for your help Roger , I'm going in this direction. At the end I got it , I start with just a resume of my old aplication and I plane to go step by step, testing all the elements I need for my GUI aplication.

Code: Select all

from Tkinter import *
import time
from time import sleep
shootdelay = 5
shootinterval = 7
shootnumber = 12
class Example:
    
    
       
    def __init__(self, master):
        

        self.etfilm = Label(root,width=12, font=('arial narrow', 14, 'normal'),fg="white", bg="green")
        self.etfilm.grid(row=0, column=0,columnspan=1, padx=3, pady=2, sticky=NSEW)
    

        self.etstatus = Label(root,width=17, font=('arial narrow', 14, 'normal'),bg="yellow")
        self.etstatus.grid(row=0, column=1,columnspan=2, padx=3, pady=2, sticky=NSEW)
        self.etstatus.configure(text="SET TO:D12-I6-T12") 

        self.textBox = Text(root,height= 1,width=1, relief=SUNKEN, font=('arial', 18, 'normal'),)
        self.textBox.grid(row=0, column=3, ipadx=13, padx=0, sticky=NSEW)


        self.botshoot = Button(root, width=18, font=('arial narrow', 30, 'normal'), text="START ", activebackground="#00dfdf")
        self.botshoot.grid(row=4, rowspan=2, column=0,columnspan=4,ipady=15,pady=1, sticky=NSEW)
        self.botshoot.configure(command=self.start)

        self.botkam = Button(root,width=10, font=('arial', 20, 'normal'), text="VIDEO SETTINGS", activebackground="#00dfdf")
        self.botkam.grid(row=6, rowspan=3, column=0,columnspan=3, pady=1, sticky=NSEW)
        

        self.botkamStop = Button(root,width=3, font=('arial', 20, 'normal'), text="STOP", activebackground="#00dfdf")
        self.botkamStop.grid(row=6, rowspan=3, column=3, pady=1, sticky=NSEW)
        

        self.botSelf = Button(root,width=10, font=('arial', 20, 'normal'), text="ACTIVATE SELFTIMER", activebackground="#00dfdf")
        self.botSelf.grid(row=9, rowspan=3, column=0,columnspan=3, pady=1, sticky=NSEW)
        self.botSelf.configure(command=self.selftiming)

        self.botSelf1 = Button(root,width=3, font=('arial', 20, 'normal'), text="STOP", activebackground="#00dfdf")
        self.botSelf1.grid(row=9, rowspan=3, column=3, pady=1, sticky=NSEW)
        

        self.botConf = Button(root,heigh=2, font=('arial', 18, 'normal'), text="CONFIGURE", activebackground="red")
        self.botConf.grid(row=12, rowspan=3, column=0,columnspan=1, pady=1, sticky=NSEW)

        self.botStop = Button(root,heigh=2, font=('arial', 18, 'normal'), text="STOP/RESET", activebackground="red")
        self.botStop.grid(row=12, rowspan=3, column=1,columnspan=3, pady=1, sticky=NSEW)
        self.botStop.configure(state=DISABLED,command=self.stop)

       

    def start(self):
        self.count = 0
        self.cancel_id = None
        self.botConf.configure(state=DISABLED)
        self.botshoot.configure(state=DISABLED)
        self.botStop.configure(state=NORMAL)
        self.shooting()

    def shooting(self):
        global shootdelay
        
        self.textBox.delete("1.0", END)
        if self.count < shootdelay:
            self.count += 1
            self.textBox.insert(END, str(self.count)+'\n\n')
            self.cancel_id = self.textBox.after(1000, self.shooting)
            self.etstatus.configure(bg="yellow") 
            self.etstatus.configure(text="shoot delay")           
            root.update_idletasks()
            print(self.count)
        else:
            self.botConf.configure(state=NORMAL)
            self.botshoot.configure(state=NORMAL)
            self.botStop.configure(state=DISABLED)
            
    def stop(self):
        if self.cancel_id is not None:
            self.textBox.after_cancel(self.cancel_id)
            self.cancel_id = None
            self.textBox.insert(END, 0)
            self.textBox.delete("1.0", END)
            self.botConf.configure(state=NORMAL)
            self.botshoot.configure(state=NORMAL)
            self.etstatus.configure(bg="red") 
            self.etstatus.configure(text="STOP PROCESS")           
            root.update_idletasks()
            sleep(2)
            self.etstatus.configure(bg="yellow") 
            self.etstatus.configure(text="SET TO:D12-I6-T12")           
            root.update_idletasks()

    def selftiming(self):
            self.etstatus.configure(text="SELFTIMER ON")           
            root.update_idletasks()

root=Tk()
Example(root)
root.mainloop()