2

I'm currently developing a program with a GUI to gather data from a sensor and visualise it within the GUI. The data from the sensor is stored in a list for further calculations.

What I'm currently trying to do, is starting the logging process in a new thread. This should stop the GUI from freezing.

My current code:

import tkinter as tk
import time
import threading

class GUI:
    def __init__(self, tk_object):
        self.gui = tk_object
        self.gui.title("Logger") 
        self.gui.resizable(width=True, height=True)

        self.testlabel = tk.Label(self.gui, text="Recording in process")
        self.testlabel.grid(row = 7, column = 0)
        self.testlabel.config(bg='white')

        btn1 = tk.Button(master, text="Start Recording", width=16, height=5, command=lambda: self.start_functions())
        btn1.grid(row=2,column=0)
        btn2 = tk.Button(master, text="Stop Recording", width=16, height=5, command=lambda: self.stop_functions())
        btn2.grid(row=3,column=0)

    def start_functions(self):
        """Calls the method get_sample in a new thread and changes the bg-color of the label to red""" 
        Thread_1 = threading.Thread(target=self.get_sample(), name='Thread1')        
        Thread_1.start()
        self.testlabel.config(bg='red') 

    def stop_functions(self):
        """Stops all active threads and changes bg-color of the label back to white""" 
        #stop_threads = threading.Event()
        #stop_threads.set()
        threading.Event().set()
        self.testlabel.config(bg='white')            

    def get_sample(self):
        """get data and append it to a list"""
        while not threading.Event().is_set():
            time.sleep(1)
            res_cel.append(res_cel[-1]+1)
            x_value.append(x_value[-1]+1)
        print(res_cel)
        print(x_value) 


master = tk.Tk()
master_object = GUI(master)
master.mainloop()

Currently, the get_sample method contains a placeholder. I'm trying to stop the Thread1 (where the get_sample method is running in) via the Event() handler.

while not threading.Event().is_set():

This doesn't seem to work in a proper way. Are there better ways to do this? Before this approach I tried using a class to handle the threads (This was found on stackoverflow, but I can't seem to find it anymore, sorry):

class Controller(object):

def __init__(self):
    self.thread1 = None
    self.stop_threads = Event()

def run(self):
    .. do somehting

and starting / stopping the threads via:

def starting_thread(self):
    self.stop_threads.clear()
    self.thread1 = Thread(target = self.run)
    self.thread1.start()

def stopping_thread(self):
    self.stop_threads.set()
    self.thread1 = None

Note: These functions are within the Controller Class. With this solution I wasn't able to alter the lables background color in the GUI Class, since it doesn't know what object it is referencing to.

Im fairly new to programming python so I'd be glad if someone could explain to me what I'm missing here.

Thanks xSaturn

Vasilis G.
  • 7,556
  • 4
  • 19
  • 29
xSaturn
  • 23
  • 3

1 Answers1

1

You'd better create your own Thread object with a method to stop it. A thread stop running when it goes of its run method. Look at the example bellow

import time
import tkinter as tk
from threading import Thread

class MyThread(Thread):
    thread_running = False

    def run(self):
        k = 0
        self.thread_running = True
        while self.thread_running:
            print(k)
            k +=1
            time.sleep(1)
        print("thread ended")

    def stop(self):
        self.thread_running = False


class Window(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.thread = None

        tk.Button(self, text="launch thread", command=self.launch_thread)\
            .grid(row=1, column=0)
        tk.Button(self, text="stop thread", command=self.stop_thread)\
            .grid(row=2, column=0)

    def launch_thread(self):
        if self.thread:
            print("thread already launched")
        else:
            print("thread launched")
            self.thread = MyThread()
            self.thread.start()


    def stop_thread(self):
        if self.thread:
            self.thread.stop()
            self.thread = None
        else:
            print("no thread running")

if __name__ == '__main__':
    win = Window()
    win.mainloop()

See this topic for more information Is there any way to kill a Thread?

Sylvan LE DEUNFF
  • 682
  • 1
  • 6
  • 21
  • 1
    Thanks this works very well! The approach to create a Thread Object is better than mine. Kind regards xSaturn – xSaturn Dec 17 '18 at 16:23