Skip to content
Advertisement

Start and Stop threads with while loop

I’m building a tkinter GUI to retrieve incoming data from a device (through request) and appending them into a csv file, while having a preview of these data.

I use thread but struggle to understand it properly, especially how to pause and restart it.

When I click on the start button, my threads are working properly. Once I try to click the stop streaming button, my stop_threads variable change to 0, however, the while loop in my thread do not see this change. Do you know why?

Thanks a lot!

import tkinter as tk
import threading
from tkinter import ttk


def init_csv():
    pass
    # create my csv file here

def clear_data():
    tv1.delete(*tv1.get_children())
    init_csv()


def stream_data():
    global stop_threads
    IP_Machine = IP_entry.get()

    while True:
        if stop_threads == 1:
            print('Stream')
            # retrieve incoming data from my device (through request)
            # appending them into a csv file

        if stop_threads == 0:
            print('Pause')
            # I want to pause this thread here


def start_stream():
    t1_stream.start()
    stream_label['text'] = 'Streaming...'
    button_start.destroy()

    # Create stop streaming button
    button_stop = tk.Button(main_frame, text="Stop Streaming", bg=Blue, fg=Bg_color, font='BOLD 12',
                            command=stop_stream)
    button_stop.place(relx=0.2, rely=0.14, relwidth=0.15, relheight=0.07)


def stop_stream():
    stop_threads = 0
    stream_label['text'] = ''

    # Create ReStart streaming button
    button_restart = tk.Button(main_frame, text="Start Streaming", bg=Blue, fg=Bg_color, font='BOLD 12',
                               command=restart)
    button_restart.place(relx=0, rely=0.14, relwidth=0.15, relheight=0.07)


def restart():
    stop_threads = 1
    stream_label['text'] = 'Streaming...'


def curve():
    # show live plot data with matplot Funcanimation
    pass


def refresch_treeview():
    tv1.delete(*tv1.get_children())
    # define content of the treeview and refrech
    tv1.after(500, refresch_treeview)


csv_path = 'C:/Users/b/Desktop/testfile.csv'
init_csv()
global stop_threads
stop_threads = 1

# Multitasking definition
t1_stream = threading.Thread(target=stream_data)
t2_refresch = threading.Thread(target=refresch_treeview)

# My Tkinter interface bellow
root = tk.Tk()

# Variables
Bg_color = '#F2F2F2'
Blue = '#045FB4'
c_width = 1400
c_height = 700

# Template
canvas = tk.Canvas(root, height=c_height, width=c_width, bg=Bg_color)
canvas.pack()
left_frame = tk.Frame(root, bg=Blue)
left_frame.place(anchor='center', relx=0.05, rely=0.5, relwidth=0.002, relheight=0.9)
right_frame = tk.Frame(root, bg=Blue)
right_frame.place(anchor='center', relx=0.95, rely=0.5, relwidth=0.002, relheight=0.9)
top_frame = tk.Frame(root, bg=Blue)
top_frame.place(anchor='center', relx=0.5, rely=0.05, relwidth=0.9, relheight=0.004)
bottom_frame = tk.Frame(root, bg=Blue)
bottom_frame.place(anchor='center', relx=0.5, rely=0.95, relwidth=0.9, relheight=0.004)
main_frame = tk.Frame(root, bg=Bg_color)
main_frame.place(anchor='center', relx=0.5, rely=0.5, relwidth=0.8, relheight=0.8)
# Title
title = tk.Label(root, text='Data analysis', height=2, width=20, font='bold 18')
title.place(anchor='center', relx=0.50, rely=0.05)

# ENTRIES Definition
# Machine IP
IP_frame = tk.Frame(main_frame, bg=Bg_color)
IP_frame.place(relx=0, rely=0.05, relwidth=0.35, relheight=0.05)
IP_label = tk.Label(IP_frame, text='2000Xc IP address : ', font='12')
IP_label.pack(side='left', fill='y')
IP_entry = tk.Entry(IP_frame, width=22, font='12')
IP_entry.pack(side='right', fill='y')

# Streaming runing label
stream_label = tk.Label(main_frame, font='10', text='')
stream_label.place(anchor='w', relx=0, rely=0.45, relwidth=0.1, relheight=0.06)

# BUTTONS Definition
# Start streaming button
button_start = tk.Button(main_frame, text="Start Streaming", bg=Blue, fg=Bg_color, font='BOLD 12', command=start_stream)
button_start.place(relx=0, rely=0.14, relwidth=0.15, relheight=0.07)

# Clear data
button_clear = tk.Button(main_frame, text="Clear data", bg=Blue, fg=Bg_color, font='BOLD 10', command=clear_data)
button_clear.place(relx=0.92, rely=0.9, relwidth=0.08, relheight=0.06)
# Show graph button
button_graph = tk.Button(main_frame, text="Show curves", bg=Blue, fg=Bg_color, font='BOLD 10', command=curve)
button_graph.place(relx=0.6, rely=0.35, relwidth=0.1, relheight=0.05)

# csv preview
preview_frame = tk.Frame(main_frame, bg=Bg_color)
preview_frame.place(relx=0, rely=0.5, relwidth=1, relheight=0.4)
tv1 = ttk.Treeview(preview_frame)
tv1.place(relheight=0.95, relwidth=1)  # set the height and width of the widget to 100% of its container (frame1).
# scroll preview
treescrolly = tk.Scrollbar(preview_frame, orient="vertical",
                           command=tv1.yview)  # command means update the yaxis view of the widget
treescrollx = tk.Scrollbar(preview_frame, orient="horizontal",
                           command=tv1.xview)  # command means update the xaxis view of the widget
tv1.configure(xscrollcommand=treescrollx.set,
              yscrollcommand=treescrolly.set)  # assign the scrollbars to the Treeview Widget
treescrollx.pack(side="bottom", fill="x")  # make the scrollbar fill the x axis of the Treeview widget
treescrolly.pack(side="right", fill="y")  # make the scrollbar fill the y axis of the Treeview widget

t2_refresch.start()

root.mainloop()

Advertisement

Answer

You have to change only one thing. You need to define stop_threads as global inside the functions. Python then knows that you are referring to the global variable instead of creating a new variable inside the local function scope.

import tkinter as tk
import threading
from tkinter import ttk


def init_csv():
    pass
    # create my csv file here

def clear_data():
    tv1.delete(*tv1.get_children())
    init_csv()


def stream_data():
    global stop_threads
    IP_Machine = IP_entry.get()

    while True:
        if stop_threads == 1:
            print('Stream')
            # retrieve incoming data from my device (through request)
            # appending them into a csv file

        if stop_threads == 0:
            print('Pause')
            # I want to pause this thread here


def start_stream():
    t1_stream.start()
    stream_label['text'] = 'Streaming...'
    button_start.destroy()

    # Create stop streaming button
    button_stop = tk.Button(main_frame, text="Stop Streaming", bg=Blue, fg=Bg_color, font='BOLD 12',
                            command=stop_stream)
    button_stop.place(relx=0.2, rely=0.14, relwidth=0.15, relheight=0.07)


def stop_stream():
    global stop_threads
    stop_threads = 0
    stream_label['text'] = ''

    # Create ReStart streaming button
    button_restart = tk.Button(main_frame, text="Start Streaming", bg=Blue, fg=Bg_color, font='BOLD 12',
                               command=restart)
    button_restart.place(relx=0, rely=0.14, relwidth=0.15, relheight=0.07)


def restart():
    global stop_threads
    stop_threads = 1
    stream_label['text'] = 'Streaming...'


def curve():
    # show live plot data with matplot Funcanimation
    pass


def refresch_treeview():
    tv1.delete(*tv1.get_children())
    # define content of the treeview and refrech
    tv1.after(500, refresch_treeview)


csv_path = 'C:/Users/b/Desktop/testfile.csv'
init_csv()

stop_threads = 1

# Multitasking definition
t1_stream = threading.Thread(target=stream_data)
t2_refresch = threading.Thread(target=refresch_treeview)

# My Tkinter interface bellow
root = tk.Tk()

# Variables
Bg_color = '#F2F2F2'
Blue = '#045FB4'
c_width = 1400
c_height = 700

# Template
canvas = tk.Canvas(root, height=c_height, width=c_width, bg=Bg_color)
canvas.pack()
left_frame = tk.Frame(root, bg=Blue)
left_frame.place(anchor='center', relx=0.05, rely=0.5, relwidth=0.002, relheight=0.9)
right_frame = tk.Frame(root, bg=Blue)
right_frame.place(anchor='center', relx=0.95, rely=0.5, relwidth=0.002, relheight=0.9)
top_frame = tk.Frame(root, bg=Blue)
top_frame.place(anchor='center', relx=0.5, rely=0.05, relwidth=0.9, relheight=0.004)
bottom_frame = tk.Frame(root, bg=Blue)
bottom_frame.place(anchor='center', relx=0.5, rely=0.95, relwidth=0.9, relheight=0.004)
main_frame = tk.Frame(root, bg=Bg_color)
main_frame.place(anchor='center', relx=0.5, rely=0.5, relwidth=0.8, relheight=0.8)
# Title
title = tk.Label(root, text='Data analysis', height=2, width=20, font='bold 18')
title.place(anchor='center', relx=0.50, rely=0.05)

# ENTRIES Definition
# Machine IP
IP_frame = tk.Frame(main_frame, bg=Bg_color)
IP_frame.place(relx=0, rely=0.05, relwidth=0.35, relheight=0.05)
IP_label = tk.Label(IP_frame, text='2000Xc IP address : ', font='12')
IP_label.pack(side='left', fill='y')
IP_entry = tk.Entry(IP_frame, width=22, font='12')
IP_entry.pack(side='right', fill='y')

# Streaming runing label
stream_label = tk.Label(main_frame, font='10', text='')
stream_label.place(anchor='w', relx=0, rely=0.45, relwidth=0.1, relheight=0.06)

# BUTTONS Definition
# Start streaming button
button_start = tk.Button(main_frame, text="Start Streaming", bg=Blue, fg=Bg_color, font='BOLD 12', command=start_stream)
button_start.place(relx=0, rely=0.14, relwidth=0.15, relheight=0.07)

# Clear data
button_clear = tk.Button(main_frame, text="Clear data", bg=Blue, fg=Bg_color, font='BOLD 10', command=clear_data)
button_clear.place(relx=0.92, rely=0.9, relwidth=0.08, relheight=0.06)
# Show graph button
button_graph = tk.Button(main_frame, text="Show curves", bg=Blue, fg=Bg_color, font='BOLD 10', command=curve)
button_graph.place(relx=0.6, rely=0.35, relwidth=0.1, relheight=0.05)

# csv preview
preview_frame = tk.Frame(main_frame, bg=Bg_color)
preview_frame.place(relx=0, rely=0.5, relwidth=1, relheight=0.4)
tv1 = ttk.Treeview(preview_frame)
tv1.place(relheight=0.95, relwidth=1)  # set the height and width of the widget to 100% of its container (frame1).
# scroll preview
treescrolly = tk.Scrollbar(preview_frame, orient="vertical",
                           command=tv1.yview)  # command means update the yaxis view of the widget
treescrollx = tk.Scrollbar(preview_frame, orient="horizontal",
                           command=tv1.xview)  # command means update the xaxis view of the widget
tv1.configure(xscrollcommand=treescrollx.set,
              yscrollcommand=treescrolly.set)  # assign the scrollbars to the Treeview Widget
treescrollx.pack(side="bottom", fill="x")  # make the scrollbar fill the x axis of the Treeview widget
treescrolly.pack(side="right", fill="y")  # make the scrollbar fill the y axis of the Treeview widget

t2_refresch.start()

root.mainloop()
Advertisement