Home > Mobile >  Using threading to pass a widget value to a calculation loop and back again to the GUI
Using threading to pass a widget value to a calculation loop and back again to the GUI

Time:12-29

I'm experimenting with tkinter, and trying to make a program that can have the user enter a value into an entry widget, have that input value be processed by a calculation, then be able to pass that back to the GUI to be output. When I run this code, the GUI starts but the output widget does nothing. I've set a colour for the background widget to make sure it is generating in the first place, and it does show up.

#TKinter Threading Test

#Importing all relevant tkinter modules
from tkinter import *
from tkinter import ttk
import tkinter as tk
from tkinter.ttk import *

#Importing threading
from threading import Thread

#Creating window
thrdng_root = tk.Tk()
thrdng_root.geometry("900x900")

#Creating grid columns
thrdng_root.columnconfigure(0, weight = 3)
thrdng_root.columnconfigure(1, weight = 7)
thrdng_root.columnconfigure(2, weight = 3)

#Creating grid rows
thrdng_root.rowconfigure(0, weight = 5)
thrdng_root.rowconfigure(1, weight = 1)
thrdng_root.rowconfigure(2, weight = 5)
thrdng_root.rowconfigure(3, weight = 5)

#Creating a variable for the input widget
input_var = StringVar()

#Creating entry widget for the user to input a value
input_widget = ttk.Entry(thrdng_root, textvariable = input_var)
input_widget.grid(column = 1, row = 0)

#Creating a variable for the output widget
output_var = StringVar()

#Crating the output widget
output_widget = ttk.Label(thrdng_root, textvariable = output_var, background = "#FFFFFF")
output_widget.grid(column = 1, row = 2)

#Defining the function after the global variables have been set so that they are recognised
def calculation_process():
    #Making the loop go on indefinitely
    loop_continue = "Yes"
    while loop_continue == "Yes":
        temp = str(input_var)
        split_temp = temp.split("R")
        calc_var = float(split_temp[1])
        output_var = str(calc_var   1)

#Setting the function as a thread
calc_thread = Thread(target = calculation_process)

#Starting the thread so that the two indefinite loops can go on without blocking each other
calc_thread.start()

#Starting the indefinite GUI loop
thrdng_root.mainloop()

Is what I'm trying to do even possible, and if it is, what am I missing?

CodePudding user response:

This is one approach, using queue.Queues. There is no need to use StringVars as for most of the widgets it is easier to use their own methods. Also all of tkinter should run in one process and one thread, meaning you shouldn't put any of its "things" in another thread or call any of its methods from other threads (like you tried to do). Most of the explanation is in code comments:

import tkinter as tk
import threading
import queue


def send_value():
    # get the value that user entered
    value = entry.get()
    # don't allow entering any new values
    entry.config(state='disabled')
    submit.config(state='disabled')
    # put the value to do calculations with in the queue
    queue_in.put(value)


def update_out():
    # if there is a value in the output queue
    if not queue_out.empty():
        # get that value
        value = queue_out.get()
        # show the value on the label
        output.config(text=value)
        # set entry and button back to normal
        entry.config(state='normal')
        submit.config(state='normal')
    # schedule repeated call to this function
    root.after(100, update_out)


def calc():
    while True:
        if queue_in.empty():
            continue
        # if a value has been put in the input queue
        value = queue_in.get()
        # do calculations
        new = value   ' calculation :)'
        # put the new value in the output queue
        queue_out.put(new)


root = tk.Tk()

# create input and output queues
queue_in = queue.Queue()
queue_out = queue.Queue()
# start the calculation thread
threading.Thread(target=calc).start()

entry = tk.Entry(root)
entry.pack()

output = tk.Label(root)
output.pack()
# start the update "loop"
update_out()

submit = tk.Button(root, text='Calculate', command=send_value)
submit.pack()

root.mainloop()

Useful:

Also:
I strongly advise against using wildcard (*) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2 and so on or import the whole module: import module then You can also use an alias: import module as md or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.

  • Related