I wonder if there is there a way to test/check if tkinter mainloop
is running somehow? Issuing multiple tk.Tk().mainloop()
commands will break the GUI, but I haven't found a way to check if mainloop
has been started for the tk._default_root
?
-
1Since it's your code that is starting the mainloop, have you tried setting a flag to know when you've started it? Though, you should be calling it exactly once so it's not clear why you need to know if it's running or not. – Bryan Oakley Mar 31 '21 at 19:10
-
@Bryan Oakley I'm trying to write a library/framework which should be able to be used both with the event loop running or start it itself it not, so it would be convenient if a run check would be possible (as I can check that tk._default_root exists but not if it has been started or not) – JacobP Apr 01 '21 at 06:33
3 Answers
Annoyingly, while Tk().willdispatch()
exists (though it appears undocumented) to lie and say the mainloop
is running when it isn't (I've used it to allow an asyncio
task to interlace asyncio
events with tkinter
events), there is no Python-level API to query the underlying flag (C level struct member dispatching
) it sets.
The only place the flag is tested is in functions that automatically marshal calls from non-main threads to the mainloop
thread, and it's not practical to use this as a mechanism of detection (it requires spawning threads solely to perform the test, involves a timeout, and throws an exception when it fails, making it ugly even if you could make it work).
In short, it's going to be on you. A solution you might use would be to make a subclass that intercepts the call to mainloop
and records that it has been called:
class CheckableTk(Tk):
def __init__(self, *args, **kwargs):
self.running = False
super().__init__(*args, **kwargs)
def mainloop(self, *args, **kwargs):
self.running = True
try:
return super().mainloop(*args, **kwargs)
finally:
self.running = False
def willdispatch(self, *args, **kwargs):
self.running = True # Lie just like willdispatch lies
return super().willdispatch(*args, **kwargs)
It's not a great solution, and I'd discourage it in general. The real answer is, have one, and only one, single place that runs the mainloop
, instead of splitting up the possible launch points all over your program.

- 143,180
- 12
- 188
- 271
Posting a threading based solution from matplotlib
source code:
lib/matplotlib/backends/_backend_tk.py
def is_tk_mainloop_running():
import threading
dispatching = sentinel = object()
def target():
nonlocal dispatching
try:
tk._default_root.call('while', '0', '{}')
except RuntimeError as e:
if str(e) == "main thread is not in main loop":
print('not dispatching')
dispatching = False
else:
raise
except BaseException as e:
print(e)
raise
else:
dispatching = True
print('dispatching')
t = threading.Thread(target=target, daemon=True)
t.start()
tk._default_root.update()
t.join()
if dispatching is sentinel:
raise RuntimeError('thread failed to determine dispatching value')
return dispatching
If you know the process name, in Windows, you can use psutil to check if a process is running.
Import psutill:
import psutil
build a function to check if a process is running:
def is_running(name: str) -> bool:
name = name if name.endswith('.exe') else name + '.exe'
return name in [process.name() for process in psutil.process_iter()]
or a function to kill a process:
def kill(name: str) -> bool:
name = name if name.endswith('.exe') else name + '.exe'
for process in psutil.process_iter():
if process.name() == name:
process.kill()
return True
return False
and then you can simply use them like this
if __name__ == "__main__":
app_name = 'chrome'
if is_running(name=app_name):
if kill(name=app_name):
print(f'{app_name} killed!')
else:
print(f'{app_name} is not running!')

- 282
- 2
- 9
-
Literally none of this answers the OP's question. The `tkinter` `mainloop` may or may not be running at any time during the lifetime of the process. – ShadowRanger Apr 01 '21 at 00:45