TKinter windows do not appear when using multiprocessing on Linux

By : Weeble
Source: Stackoverflow.com
Question!

I want to spawn another process to display an error message asynchronously while the rest of the application continues.

I'm using the multiprocessing module in Python 2.6 to create the process and I'm trying to display the window with TKinter.

This code worked okay on Windows, but running it on Linux the TKinter window does not appear if I call 'showerror("MyApp Error", "Something bad happened.")'. It does appear if I run it in the same process by calling showerrorprocess directly. Given this, it seems TKinter is working properly. I can print to the console and do other things from processes spawned by multiprocessing, so it seems to be working too.

They just don't seem to work together. Do I need to do something special to allow spawned subprocesses to create windows?

from multiprocessing import Process
from Tkinter import Tk, Text, END, BOTH, DISABLED
import sys
import traceback

def showerrorprocess(title,text):
    """Pop up a window with the given title and text. The
       text will be selectable (so you can copy it to the
       clipboard) but not editable. Returns when the
       window is closed."""
    root = Tk()
    root.title(title)
    text_box = Text(root,width=80,height=15)
    text_box.pack(fill=BOTH)
    text_box.insert(END,text)
    text_box.config(state=DISABLED)
    def quit():
        root.destroy()
        root.quit()
    root.protocol("WM_DELETE_WINDOW", quit)
    root.mainloop()

def showerror(title,text):
    """Pop up a window with the given title and text. The
       text will be selectable (so you can copy it to the
       clipboard) but not editable. Runs asynchronously in
       a new child process."""
    process = Process(target=showerrorprocess,args=(title,text))
    process.start()

Edit

The issue seems to be that TKinter was imported by the parent process, and "inherited" into the child process, but somehow its state is inextricably linked to the parent process and it cannot work in the child. So long as you make sure not to import TKinter before you spawn the child process, it will work because then it is the child process that is importing it for the first time.

By : Weeble


Answers

This discussion could be helpful.

Here's some sample problems I found:

  1. While the multiprocessing module follows threading closely, it's definitely not an exact match. One example: since parameters to a process must be pickleable, I had to go through a lot of code changes to avoid passing Tkinter objects since these aren't pickleable. This doesn't occur with the threading module.

  2. process.terminate() doesn't really work after the first attempt. The second or third attempt simply hangs the interpreter, probably because data structures are corrupted (mentioned in the API, but this is little consolation).

By : Malx


Maybe calling the shell command xhost + before calling your program from that same shell will work?

I am guessing your problem lies with the X-server.



Without comment on the algorithm, or on use of appropriate library functions...

I would have expected to see more use of pattern matching and recursion; for example parse_character (no longer folded) might be replaced with something like:

parse_in_format ([], FmtStr, ParmStrs, ParmName) -> {FmtStr, ParmStrs};
parse_in_format ([${ | Vr], FmtStr, ParmStrs, ParmName) -> parse_in_name (Vr, FmtStr, ParmStrs, ParmName);
parse_in_format ([$} | Vr], FmtStr, ParmStrs, ParmName) -> throw() % etc.
parse_in_format ([V | Vr], FmtStr, ParmStrs, ParmName) -> parse_in_format (Vr, [V | FmtStr], ParmStrs, ParmName).

parse_in_name ([], FmtStr, ParmStrs, ParmName) -> throw() % etc.
parse_in_name ([$} | Vr], FmtStr, ParmStrs, ParmName) -> parse_in_format (Vr, FmtStr, [list_to_atom(lists:reverse(ParmName))|ParmStrs], "");
parse_in_name ([${ | Vr], FmtStr, ParmStrs, ParmName) -> throw() % etc.
parse_in_name ([V | Vr], FmtStr, ParmStrs, ParmName) -> parse_in_name (Vr, FmtStr, ParmStrs, [V | ParmName]).

Kicked off with a

parse_in_format (FormatStr,  [], [], "");


This video can help you solving your question :)
By: admin