views:

456

answers:

2

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, so 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()


I accepted Malx's answer because it set me on the right track. 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.

A: 

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.

Nicholas Leonard
I gave it a shot, but no luck.
Weeble
sorry couldn't have been more helpful to you...
Nicholas Leonard
+1  A: 

Could this discussion be of any help?

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).

Malx
Aha! You gave me an idea. My main process has no need of Tkinter, so I moved the line importing all the tkinter stuff into showerrorprocess and it worked! I guess that multiprocessing must have pickled up all of the state in the Tkinter module. I wonder how to stop it from doing that.
Weeble