Reputation: 33
I am trying to multiprocess multiple tkinter windows where threading (for long running processes with while loops) in each process will be required. Is this possible?
I have tried to work around this by doing a pure multithread implementation - The entire application starts to turn 'laggy'; hence the attempt now to do multiprocessing. Please see code for a very simplified, basic version of what I am trying to do. There are 2 scripts:
Main file (to run)
from tkinter import *
from tkinter import ttk
import threading
import multiprocessing
import multiprocessing_import_worker
def hello():
if __name__ == '__main__':
p_list = ["Hello", "success"]
p = multiprocessing.Process(target=multiprocessing_import_worker.worker, args=p_list)
p.start()
root.destroy()
root = Tk()
root.title("Window 1")
statusFrame = Frame(root)
statusFrame.pack()
statusLabelFrame = LabelFrame(statusFrame, text='TEST FRAME', font="Helvetica 8 bold")
statusLabelFrame.pack(fill="both", expand="yes", padx="7")
firstButtonFrame = Frame(root)
firstButtonFrame.pack()
statusbar = Label(statusLabelFrame, text="TEST", width=40, font="Helvetica 8 bold")
statusbar.pack()
b1=ttk.Button(firstButtonFrame, text="START SESSION", width=15, command=hello)
b1.pack(pady=(10,0))
root.mainloop()
Secondary file (to be run as a separate process)
def worker(word, word2):
import threading
import tkinter as tk
from tkinter import ttk
import os
print(word)
print(word2)
def testThread():
global word
global word2
print(word)
print(word2)
root = tk.Tk()
root.withdraw()
rootWindow = tk.Toplevel()
rootWindow.title("Window 2")
statusFrame = tk.Frame(rootWindow)
statusFrame.pack()
statusLabelFrame = tk.LabelFrame(statusFrame, text='TEST FRAME', font="Helvetica 8 bold")
statusLabelFrame.pack(fill="both", expand="yes", padx="7")
firstButtonFrame = tk.Frame(rootWindow)
firstButtonFrame.pack()
statusbar = tk.Label(statusLabelFrame, text="TEST", width=40, font="Helvetica 8 bold")
statusbar.pack()
b1=ttk.Button(firstButtonFrame, text="START SESSION", width=15, state='disabled')
b1.pack(pady=(10,0))
child_thread1 = threading.Thread(target=testThread)
child_thread1.start()
rootWindow.protocol("WM_DELETE_WINDOW", os._exit(0))
rootWindow.mainloop()
Expected results:
Actual results:
Upvotes: 3
Views: 3667
Reputation: 1806
The standard way to do this would be for all GUI manipulation to take place in a single process, while other processes will handle any computationally-heavy tasks. As long as there's no heavy computation going on in the GUI process, the application should remain responsive, and you can use cross-process communication to update the GUI with results of the heavy process as needed.
Upvotes: 2
Reputation: 385920
It's possible, but all interaction with the GUI must be in a single process. Tkinter itself cannot span processes, nor threads. Your other processes must put work on a queue that the tkinter process periodically polls and acts upon (of course, you could also communicate with any other form of IPC).
The reason for this is that each root window is associated with an embedded tcl interpreter, and this interpreter itself cannot span processes.
Upvotes: 3