As far as I can see, this is a constant problem when using tkinter
since it is not multi-threaded
. I have read a lot about this issue but I don't know how I can solve it in my case.
My application consists of a plotly dash
running in a local server with a button that calls a function that does a series of processes with the excel. At first I got main thread is not in main loop
when pressing the button. Nevertheless, setting a daemon
I managed to avoid it. However, if I press the button again the program stops working and the error mentioned above appears.
This is a summarized script of my plotly dash:
def interact_callbacks(self):
@callback(
Output('add-automatically-button', 'children'),
Input('add-automatically-button', 'n_clicks')
)
def update_output(n_clicks):
if n_clicks is not None:
t = threading.Thread(target=startInteraction)
t.setDaemon(True)
t.start()
return 'Clicked!'
else:
return 'Add automatically'
This is the function startInteraction() that is in a different .py
def startInteraction():
gui = GUI()
gui.get_excel_path()
path=gui.path
confirmation = gui.confirmationPopUp(path)
sys.stderr.write("***OK: selected**\n")
if(confirmation):
sys.stderr.write("***OK***\n")
defectLoader(path)
else:
sys.stderr.write("***CANCEL***\n")
gui.errImport()
exit()
This is my gui class (I have more pop-ups in this class)
class GUI():
def __init__(self):
self.path = None
def get_excel_path(self):
size = {
"size": (40, 1)
}
layout = [
[sg.Text('Select Database (Excel):')],
[sg.Input(**size), sg.FileBrowse(file_types=(("Excel File", "*.xlsx"),))],
[sg.OK(), sg.Cancel()]
]
window = sg.Window('File Browser', layout)
event, values = window.read()
window.close()
try:
file_path = values[0]
if event == 'Cancel' or not file_path:
sys.stderr.write("***CANCEL***\n")
raise Exception('No file selected')
self.path= file_path
except Exception as e:
sg.popup(f'Error: {e}')
exit()
How can I write a thread queue in this code? Is there other option?
This is a typical problem when trying to combine the plotly dash
library with tkinter
or pysimplegui
. I had a similar problem a few years ago and solved it by doing the following:
p = Process(target=yourFunctionName)
p.start()
Do not forget to do the following import:
from multiprocessing import Process
In your case:
def interact_callbacks(self):
@callback(
Output('add-automatically-button', 'children'),
Input('add-automatically-button', 'n_clicks')
)
def update_output(n_clicks):
if n_clicks is not None:
p = Process(target=startInteraction)
p.start()
return 'Clicked!'
else:
return 'Add automatically'
I hope this solves your problems and you can finish your app.