1

From my main script, I want to run a thread with tkinter to visualize all the parameters of my simulation. Something relatable to this.

Since, as it is well described in the linked question, "Tkinter isn't thread safe, and the general consensus is that Tkinter doesn't work in a non-main thread", and I do not want to run everything else on threads, is there another way to display a table (not in terminal) to track the parameters that I'm interested with?

I tried to adapt my code with the solution provided here

But as suspected it never prints the last "Finished" until I close the window

import tkinter as tk
from tkinter import ttk, Button
import threading
from Brain import AGV, IDLE
import time

class my_visual():
    def __init__(self, data):
        self.data = data

    def visualize_params(self):
        ### Create the object Window
        self.window = tk.Tk()
        self.window.geometry('900x400')
        self.window.title('Table of AGVs')
        #window.withdraw() # hide the window
        table = ttk.Treeview(self.window, columns = ('one', 'two', 'three', 'four'), show = 'headings')
        table.heading('one',  text = 'Name')
        table.heading('two',  text = 'Battery Status')
        table.heading('three',text = 'Vehicle is empty')
        table.heading('four', text = 'State')
        table.pack(fill = 'both', expand = True)
        for i in range(len(data)):
            table.insert(parent = '', index= 'end', values = self.data[i])
        btn1 = Button(self.window, text = 'Refresh', command = self.refresh())
        btn1.pack()
        self.window.mainloop()

    def refresh(self):
        self.window.quit()
        self.window.destroy()
        self.visualize_params()

car_list = []
data = []
for i in range(0,15):
    car_list.append('car_%d' %i) 
    car_list[i] = AGV(car_list[i], 100, True, IDLE(), True)
    data.append([car_list[i].GetID(), car_list[i].GetBatteryStatus(), car_list[i].GetVehicleLoadless(), car_list[i].GetState()])
  

test = my_visual(data)
threading.Thread(target = test.visualize_params()).start()
time.sleep(1)
print("Finished")

And the AGV class is the following:

class AGV:
    _state = None
    agv_list = []
    
    def __init__(self, ID, Battery_Status, Vehicle_Empty, Current_State: State, just_switched)-> None:
        self.ID = ID
        self.Battery_Status = Battery_Status
        self.Vehicle_Empty = Vehicle_Empty
        self.just_switched = just_switched
        self.SetState(Current_State)
        AGV.agv_list.append(self)
    
    def __repr__(self):
        return f"""\n Name: {self.ID}, Battery Status: {self.Battery_Status}, \
Vehicle Empty: {self.Vehicle_Empty}, Current State: {type(self._state).__name__}, Just Switched: {self.just_switched}"""
    
    def GetID(self)->str:
        return self.ID

    def GetBatteryStatus(self):
        return self.Battery_Status
    def SetBatteryStatus(self, battery_charge):
        self.Battery_Status = battery_charge

    def GetVehicleLoadless(self):
        return self.Vehicle_Empty
    def SetVehicleLoadless(self, agv_empty):
        self.Vehicle_Empty = agv_empty    

    def GetState(self) -> str:
        return f"{type(self._state).__name__}"
    def SetState(self, Current_State: State):
        self._state = Current_State
        self._state.agv = self

Is there a way to run tkinter on a thread or exists another way to display a table with the parameters without using tkinter nor printing in the terminal?

4
  • When you do target = test.visualize_params(), you are not running visualize_params in a thread. You're calling it immediately, and then passing None to the target Commented Oct 24, 2023 at 15:38
  • It really doesn't look like you need threads here. And if you do, it looks like you could easily run the other code in a separate thread. It's not clear why you think you have to run tkinter in a thread. Commented Oct 24, 2023 at 15:40
  • @BryanOakley Could you explain to me why I'm not running 'visualize_param' in a thread? And how do I do it properly?
    – Tommaso M
    Commented Oct 26, 2023 at 0:30
  • Because test.visualize_params() calls the function. This is how you call a function in python. So, it's called, and the result is passed to the target parameter. This is a fairly common mistake people make with threading. The target requires a callable (roughly translated to mean the name of a function). Commented Oct 26, 2023 at 1:53

0

Browse other questions tagged or ask your own question.