I'm testing out tkinter and trying to have a calculation done on values from a GUI created in a procedure. It works fine if the GUI creation is not in a procedure, but cannot identify the widgets if the widgets are made in a procedure, even if the GUI procedure is defined before the other functions/procedures and called after. Is this impossible or am I doing something wrong?
#TKinter Threading Test
#Importing all relevant tkinter modules
import tkinter as tk
from tkinter import ttk
#Importing threading
from threading import Thread
#Importing queues
import queue
def take_value():
#Place the input_widget value into the queue
temp = input_widget.get()
print(temp)
#Temporarily pause the entry of new variables
input_widget.config(state = "disabled")
output_widget.config(state = "disabled")
queue_input.put(temp)
def place_value():
#Check if there is a value in the output queue at all
if queue_output.empty():
#print("Output queue is empty")
temp = "Nothing"
else:
temp = queue_output.get()
#Place the value onto the label
output_widget.config(text = temp)
#Re-activate the widgets
input_widget.config(state = "normal")
output_widget.config(state = "normal")
thrdng_root.after(100, place_value)
def calculation_process():
#Check if there is a value in the input queue at all
while True:
if queue_input.empty():
#print("Input queue is empty")
temp = "Nothing"
else:
temp = queue_input.get()
new_value = str(float(temp) 1)
print(new_value)
queue_output.put(new_value)
def create_GUI():
#Creating window
thrdng_root = tk.Tk()
thrdng_root.geometry("900x900")
#Creating a queue for values going into the calculation
queue_input = queue.Queue()
#Creating a queue for values coming out
queue_output = queue.Queue()
#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)
thrdng_root.rowconfigure(4, weight = 5)
#Creating entry widget for the user to input a value
input_widget = ttk.Entry(thrdng_root)
input_widget.grid(column = 1, row = 0)
#Creating the output widget
output_widget = ttk.Label(thrdng_root, background = "#FFFFFF")
output_widget.grid(column = 1, row = 2)
place_value()
#Creating the button that submits the data to the loop
submit_widget = ttk.Button(thrdng_root, text = "Calculate", command = take_value)
submit_widget.grid(column = 1, row = 3)
#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()
create_GUI()
CodePudding user response:
This is no different for tkinter widgets as it is for any other python object. You need to save a reference to the widget, and provide a way to access that reference. This is typically done by one of these methods:
- save the reference as a global if you aren't using classes
- save the reference as an instance variable if you are using classes
- pass the reference to the function that needs it.
Since you are not using classes, that eliminates #2. The simplest solution is to use global variables. For every widget that you want to be able to access in a function other than where it was created, you should declare it as global.
For example, if input_widget
is one of those widgets you need to use in more than one place, declare it as global in the function where it is defined.
def create_GUI():
global input_widget
...
input_widget = ttk.Entry(thrdng_root)'
...