Ricky Spanish February 2016

Python GUI Threading

I want to have a function run continuously within a tkinter GUI. I have attached some shell code:

#!/usr/bin/env python3

import tkinter as tk
from time import sleep
import os
import sys

class Application(Frame):

    def __init__(self, master):
        super(Application, self).__init__(master)
        self.grid()
        self.create_widgets()

        def create_widgets(self):
        ......

root = Tk()  

def run_continously:
    ... -- calls sleep -- ...
    root.after(3000, run_continuously)


root.geometry('%dx%d+%d+%d' % (w, h, x, y))
app = Application(root)
root.after(3000, run_continuously)          
root.mainloop()

When running the GUI it tends to run the 'run_continuously' function once and the GUI freezes up. I suspect from poking around that this is due to the sleep function (which I call in the run_continuously function)

How would I go about implementing the 'run_continuously' function in a very simple thread to get around this issue? Would running the function in a thread even get me around the problem? The 'run_continuously' function does not need to interact at all with the Application class. I want it to run simply in the background and stop when the mainloop is finished.

Here is the end of the code:

def run_continuously(quit_flag):
    print("in it")
    if not quit_flag:
        GPIO.output(DIR_PIN, True)
        for i in range(steps):
            print("in loop")
            GPIO.output(STEP_PIN, True)
            sleep(sDelay)
            GPIO.output(STEP_PIN, False)
            sleep(sDelay)
        sleep(wait_time)
        GPIO.output(DIR_PIN, False)    
        for i in range(steps):
            GPIO.output(STEP_PIN, True)
            sleep(sDelay)
            GPIO.output(STEP_PIN, False)
            sleep(sDelay)
            print("run motor")
        root.after(1000, run_continuously(quit_flag,))


#=================================================================
# main        

Answers


David Cullen February 2016

This is a minimal, complete, and verifiable example that exits cleanly if the 'QUIT' button is pressed or Ctrl-C is pressed:

from Tkinter import *
import multiprocessing
import threading
import time
import logging


class Application(Frame):
    def create_widgets(self):
        self.quit_button = Button(self)
        self.quit_button['text'] = 'QUIT'
        self.quit_button['fg'] = 'red'
        self.quit_button['command'] = self.quit
        self.quit_button.pack({'side': 'left'})

    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.quit_button = None
        self.pack()
        self.create_widgets()
        self.poll()

    def poll(self):
        """
        This method is required to allow the mainloop to receive keyboard
        interrupts when the frame does not have the focus
        """
        self.master.after(250, self.poll)


def worker_function(quit_flag):
    counter = 0
    while not quit_flag.value:
        counter += 1
        logging.info("Work # %d" % counter)
        time.sleep(1.0)


format = '%(levelname)s: %(filename)s: %(lineno)d: %(message)s'
logging.basicConfig(level=logging.DEBUG, format=format)
root = Tk()
app = Application(master=root)
quit_flag = multiprocessing.Value('i', int(False))
worker_thread = threading.Thread(target=worker_function, args=(quit_flag,))
worker_thread.start()
logging.info("quit_flag.value = %s" % bool(quit_flag.value))
try:
    app.mainloop()
except KeyboardInterrupt:
    logging.info("Keyboard interrupt")
quit_flag.value = True
logging.info("quit_flag.value = %s" % bool(quit_flag.value))
worker_thread.join()

Post Status

Asked in February 2016
Viewed 1,371 times
Voted 5
Answered 1 times

Search




Leave an answer